def test_generate_dont_fix_inputs_with_fixed_var(self): m = _make_simple_model() m.v4.fix() subs = [ ([m.con1], [m.v1]), ([m.con2, m.con3], [m.v2, m.v3]), ] other_vars = [ [m.v2, m.v3], [m.v1], ] for i, (block, inputs) in enumerate(generate_subsystem_blocks(subs)): self.assertIs(block.model(), block) var_set = ComponentSet(subs[i][1]) con_set = ComponentSet(subs[i][0]) input_set = ComponentSet(other_vars[i]) self.assertEqual(len(var_set), len(block.vars)) self.assertEqual(len(con_set), len(block.cons)) self.assertEqual(len(input_set), len(inputs)) self.assertTrue(all(var in var_set for var in block.vars[:])) self.assertTrue(all(con in con_set for con in block.cons[:])) self.assertTrue(all(var in input_set for var in inputs)) self.assertFalse(m.v1.fixed) self.assertFalse(m.v2.fixed) self.assertFalse(m.v3.fixed) self.assertTrue(m.v4.fixed) self.assertFalse(m.v1.fixed) self.assertFalse(m.v2.fixed) self.assertFalse(m.v3.fixed) self.assertTrue(m.v4.fixed)
def test_generate_subsystems_with_fixed_var(self): m = _make_simple_model() m.v4.fix() subs = [ ([m.con1], [m.v1]), ([m.con2, m.con3], [m.v2, m.v3]), ] other_vars = [ [m.v2, m.v3], [m.v1], ] for i, (block, inputs) in enumerate(generate_subsystem_blocks(subs)): inputs = list(block.input_vars.values()) with TemporarySubsystemManager(to_fix=inputs): self.assertIs(block.model(), block) var_set = ComponentSet(subs[i][1]) con_set = ComponentSet(subs[i][0]) input_set = ComponentSet(other_vars[i]) self.assertEqual(len(var_set), len(block.vars)) self.assertEqual(len(con_set), len(block.cons)) self.assertEqual(len(input_set), len(inputs)) self.assertTrue(all(var in var_set for var in block.vars[:])) self.assertTrue(all(con in con_set for con in block.cons[:])) self.assertTrue(all(var in input_set for var in inputs)) self.assertTrue(all(var.fixed for var in inputs)) self.assertFalse(any(var.fixed for var in block.vars[:])) # Test that we have properly unfixed variables, except variables # that were already fixed. self.assertFalse(m.v1.fixed) self.assertFalse(m.v2.fixed) self.assertFalse(m.v3.fixed) self.assertTrue(m.v4.fixed)
def test_generate_subsystems_include_fixed_var(self): m = _make_simple_model() m.v4.fix() subsystems = [ ([m.con1], [m.v1]), ([m.con2, m.con3], [m.v2, m.v3]), ] other_vars = [ [m.v2, m.v3, m.v4], [m.v1, m.v4], ] for i, (block, inputs) in enumerate(generate_subsystem_blocks( subsystems, include_fixed=True, )): with TemporarySubsystemManager(to_fix=inputs): self.assertIs(block.model(), block) var_set = ComponentSet(subsystems[i][1]) con_set = ComponentSet(subsystems[i][0]) input_set = ComponentSet(other_vars[i]) self.assertEqual(len(var_set), len(block.vars)) self.assertEqual(len(con_set), len(block.cons)) self.assertEqual(len(input_set), len(block.input_vars)) self.assertTrue(all(var in var_set for var in block.vars[:])) self.assertTrue(all(con in con_set for con in block.cons[:])) self.assertTrue(all(var in input_set for var in inputs)) self.assertTrue(all(var.fixed for var in inputs)) self.assertFalse(any(var.fixed for var in block.vars[:])) self.assertFalse(m.v1.fixed) self.assertFalse(m.v2.fixed) self.assertFalse(m.v3.fixed) self.assertTrue(m.v4.fixed)
def test_generate_subsystems_without_fixed_var(self): m = _make_simple_model() subs = [ ([m.con1], [m.v1, m.v4]), ([m.con2, m.con3], [m.v2, m.v3]), ] other_vars = [ [m.v2, m.v3], [m.v1, m.v4], ] for i, (block, inputs) in enumerate(generate_subsystem_blocks(subs)): with TemporarySubsystemManager(to_fix=inputs): self.assertIs(block.model(), block) var_set = ComponentSet(subs[i][1]) con_set = ComponentSet(subs[i][0]) input_set = ComponentSet(other_vars[i]) self.assertEqual(len(var_set), len(block.vars)) self.assertEqual(len(con_set), len(block.cons)) self.assertEqual(len(input_set), len(block.input_vars)) self.assertTrue(all(var in var_set for var in block.vars[:])) self.assertTrue(all(con in con_set for con in block.cons[:])) self.assertTrue(all(var in input_set for var in inputs)) self.assertTrue(all(var.fixed for var in inputs)) self.assertFalse(any(var.fixed for var in block.vars[:])) # Test that we have properly unfixed variables self.assertFalse(any(var.fixed for var in m.component_data_objects(pyo.Var)))
def test_generate_subsystems_with_exception(self): m = _make_simple_model() subs = [ ([m.con1], [m.v1, m.v4]), ([m.con2, m.con3], [m.v2, m.v3]), ] other_vars = [ [m.v2, m.v3], [m.v1, m.v4], ] with self.assertRaises(RuntimeError): for i, (block, inputs) in enumerate(generate_subsystem_blocks(subs)): with TemporarySubsystemManager(to_fix=inputs): self.assertTrue(all(var.fixed for var in inputs)) self.assertFalse(any(var.fixed for var in block.vars[:])) if i == 1: raise RuntimeError() # Test that we have properly unfixed variables self.assertFalse(any(var.fixed for var in m.component_data_objects(pyo.Var)))
def generate_strongly_connected_components( constraints, variables=None, include_fixed=False, ): """ Performs a block triangularization of the incidence matrix of the provided constraints and variables, and yields a block that contains the constraints and variables of each diagonal block (strongly connected component). Arguments --------- constraints: List of Pyomo constraint data objects Constraints used to generate strongly connected components. variables: List of Pyomo variable data objects Variables that may participate in strongly connected components. If not provided, all variables in the constraints will be used. include_fixed: Bool Indicates whether fixed variables will be included when identifying variables in constraints. Yields ------ Blocks containing the variables and constraints of every strongly connected component, in a topological order, as well as the "input variables" for that block """ if variables is None: var_set = ComponentSet() variables = [] for con in constraints: for var in identify_variables( con.expr, include_fixed=include_fixed, ): if var not in var_set: variables.append(var) var_set.add(var) assert len(variables) == len(constraints) igraph = IncidenceGraphInterface() var_block_map, con_block_map = igraph.block_triangularize( variables=variables, constraints=constraints, ) blocks = set(var_block_map.values()) n_blocks = len(blocks) var_blocks = [[] for b in range(n_blocks)] con_blocks = [[] for b in range(n_blocks)] for var, b in var_block_map.items(): var_blocks[b].append(var) for con, b in con_block_map.items(): con_blocks[b].append(con) subsets = list(zip(con_blocks, var_blocks)) for block, inputs in generate_subsystem_blocks( subsets, include_fixed=include_fixed, ): # TODO: How does len scale for reference-to-list? assert len(block.vars) == len(block.cons) yield (block, inputs)
def generate_time_blocks(m, time): subsystems = get_subsystems_along_time(m, time) for block, inputs in generate_subsystem_blocks(subsystems): yield block, inputs
def generate_time_element_blocks( m, time, skip_partition=False, flatten_vars=None, flatten_cons=None, time_subsystems=None, ): with TIMER.context("flatten"): if flatten_vars is None: scalar_vars, dae_vars = flatten_dae_components(m, time, Var) else: scalar_vars, dae_vars = flatten_vars if flatten_cons is None: scalar_cons, dae_cons = flatten_dae_components(m, time, Constraint) else: scalar_cons, dae_cons = flatten_cons with TIMER.context("get time subsystems"): # We repeat the above flattening in this function... if time_subsystems is None: subsystems = get_subsystems_along_time( m, time, flatten_vars=(scalar_vars, dae_vars), flatten_cons=(scalar_cons, dae_cons), ) else: subsystems = time_subsystems if not skip_partition: # If we know our time-subsystems are all independent, as is # the case in a discretization that only involves adjacent # time points, then we can skip this expensive partition step. with TIMER.context("partition"): partition = partition_independent_subsystems(subsystems) else: partition = [[i] for i in range(len(subsystems))] time_partition = [[time.at(i + 1) for i in subset] for subset in partition] combined_subsystems = [( [con for i in subset for con in subsystems[i][0]], [var for i in subset for var in subsystems[i][1]], ) for subset in partition] TIMER.start("subsystem blocks") for i, (block, inputs) in enumerate( generate_subsystem_blocks(combined_subsystems)): TIMER.stop("subsystem blocks") t_points = time_partition[i] assert len(block.vars) == len(block.cons) if i != 0: # Initialize with results of previous solve # TODO: Should initialize happen in a separate function? for var in dae_vars: # The time required to look up the vardata objects # in these references is actually showing up in a # profile. TODO: Potentially refactor to use # dicts: time -> vardata here... (Note that this # caches valid time points, as opposed to references) vlatest = var[latest] for t in t_points: var_t = var[t] if not var_t.fixed: var_t.set_value(vlatest.value) yield block, inputs # I don't think t_points can be empty. TODO: is this correct? latest = t_points[-1] if i != len(combined_subsystems) - 1: # Small hack so we can profile generate_subsystem_blocks # in this loop TIMER.start("subsystem blocks")