def test_numerical_instability_almost_canceling(self): # It's possible that we get almost-but-not-quite zero on the variable # being eliminated when we are doing this with floating point # arithmetic. This can get ugly later becuase it might get muliplied by # a large number later and start to "reappear" m = ConcreteModel() m.x = Var() m.x0 = Var() m.y = Var() m.cons1 = Constraint(expr=(1.342 + 2.371e-8)*m.x0 <= m.x + 17*m.y) m.cons2 = Constraint(expr=(17.56 + 3.2e-7)*m.x0 >= m.y) fme = TransformationFactory('contrib.fourier_motzkin_elimination') fme.apply_to(m, vars_to_eliminate=[m.x0], verbose=True, zero_tolerance=1e-9) constraints = m._pyomo_contrib_fme_transformation.projected_constraints # There's going to be numerical error here, and I can't really help # it. What I care about is that x0 really is gone. useful = constraints[1] repn = generate_standard_repn(useful.body) self.assertTrue(repn.is_linear()) self.assertEqual(len(repn.linear_coefs), 2) # this is the real test self.assertEqual(useful.lower, 0) self.assertIs(repn.linear_vars[0], m.x) self.assertAlmostEqual(repn.linear_coefs[0], 0.7451564696962295) self.assertIs(repn.linear_vars[1], m.y) self.assertAlmostEqual(repn.linear_coefs[1], 12.610712377673217) self.assertEqual(repn.constant, 0) self.assertIsNone(useful.upper)
def create_hull_model(self): m = ConcreteModel() m.p = Var([1, 2], bounds=(0, 10)) m.time1 = Disjunction(expr=[m.p[1] >= 1, m.p[1] == 0]) m.on = Disjunct() m.on.above_min = Constraint(expr=m.p[2] >= 1) m.on.ramping = Constraint(expr=m.p[2] - m.p[1] <= 3) m.on.on_before = Constraint(expr=m.p[1] >= 1) m.startup = Disjunct() m.startup.startup_limit = Constraint(expr=(1, m.p[2], 2)) m.startup.off_before = Constraint(expr=m.p[1] == 0) m.off = Disjunct() m.off.off = Constraint(expr=m.p[2] == 0) m.time2 = Disjunction(expr=[m.on, m.startup, m.off]) m.obj = Objective(expr=m.p[1] + m.p[2]) hull = TransformationFactory('gdp.hull') hull.apply_to(m) disaggregatedVars = ComponentSet([ hull.get_disaggregated_var(m.p[1], m.time1.disjuncts[0]), hull.get_disaggregated_var(m.p[1], m.time1.disjuncts[1]), hull.get_disaggregated_var(m.p[1], m.on), hull.get_disaggregated_var(m.p[2], m.on), hull.get_disaggregated_var(m.p[1], m.startup), hull.get_disaggregated_var(m.p[2], m.startup), hull.get_disaggregated_var(m.p[1], m.off), hull.get_disaggregated_var(m.p[2], m.off) ]) return m, disaggregatedVars
def test_simple_hull_example(self): m = ConcreteModel() m.x0 = Var(bounds=(0, 3)) m.x1 = Var(bounds=(0, 3)) m.x = Var(bounds=(0, 3)) m.disaggregation = Constraint(expr=m.x == m.x0 + m.x1) m.y = Var(domain=Binary) m.cons = Constraint(expr=2 * m.y <= m.x1) fme = TransformationFactory('contrib.fourier_motzkin_elimination') fme.apply_to(m, vars_to_eliminate=[m.x0, m.x1]) constraints = m._pyomo_contrib_fme_transformation.projected_constraints constraints.pprint() self.assertEqual(len(constraints), 1) cons = constraints[1] self.assertIsNone(cons.upper) self.assertEqual(value(cons.lower), 0) repn = generate_standard_repn(cons.body) self.assertEqual(repn.constant, 0) self.assertEqual(len(repn.linear_vars), 2) self.assertIs(repn.linear_vars[0], m.x) self.assertEqual(repn.linear_coefs[0], 1) self.assertIs(repn.linear_vars[1], m.y) self.assertEqual(repn.linear_coefs[1], -2) self.assertTrue(repn.is_linear())
def test_projected_constraints_named_correctly(self): m = self.make_tiny_model_where_bounds_matter() fme = TransformationFactory('contrib.fourier_motzkin_elimination') fme.apply_to(m.b, vars_to_eliminate=[m.y], projected_constraints_name='fme_constraints') self.assertIsInstance(m.b.component("fme_constraints"), Constraint) self.check_tiny_model_constraints(m.b.fme_constraints) self.assertIsNone(m.b._pyomo_contrib_fme_transformation.component( "projected_constraints"))
def make_model(): m = ConcreteModel() m.time = ContinuousSet(bounds=(0, 10)) m.space = ContinuousSet(bounds=(0, 5)) m.set1 = Set(initialize=['a', 'b', 'c']) m.set2 = Set(initialize=['d', 'e', 'f']) m.fs = Block() m.fs.v0 = Var(m.space, initialize=1) @m.fs.Block() def b1(b): b.v = Var(m.time, m.space, initialize=1) b.dv = DerivativeVar(b.v, wrt=m.time, initialize=0) b.con = Constraint(m.time, m.space, rule=lambda b, t, x: b.dv[t, x] == 7 - b.v[t, x]) # Inconsistent @b.Block(m.time) def b2(b, t): b.v = Var(initialize=2) @m.fs.Block(m.time, m.space) def b2(b, t, x): b.v = Var(m.set1, initialize=2) @b.Block(m.set1) def b3(b, c): b.v = Var(m.set2, initialize=3) @b.Constraint(m.set2) def con(b, s): return (5 * b.v[s] == m.fs.b2[m.time.first(), m.space.first()].v[c]) # inconsistent @m.fs.Constraint(m.time) def con1(fs, t): return fs.b1.v[t, m.space.last()] == 5 # Will be inconsistent @m.fs.Constraint(m.space) def con2(fs, x): return fs.b1.v[m.time.first(), x] == fs.v0[x] # will be consistent disc = TransformationFactory('dae.collocation') disc.apply_to(m, wrt=m.time, nfe=5, ncp=2, scheme='LAGRANGE-RADAU') disc.apply_to(m, wrt=m.space, nfe=5, ncp=2, scheme='LAGRANGE-RADAU') return m
def test_use_all_var_bounds(self): m = self.make_tiny_model_where_bounds_matter() fme = TransformationFactory('contrib.fourier_motzkin_elimination') fme.apply_to(m.b, vars_to_eliminate=[m.y]) constraints = m.b.\ _pyomo_contrib_fme_transformation.projected_constraints # if we hadn't included y's bounds, then we wouldn't get any constraints # and y wouldn't be eliminated. If we do include y's bounds, we get new # information that x <= 5: self.check_tiny_model_constraints(constraints)
def _presolve(self, *args, **kwds): if not isinstance(args[0], six.string_types): self._instance = args[0] xfrm = TransformationFactory('mpec.nl') xfrm.apply_to(self._instance) if len(self._instance._transformation_data['mpec.nl'].compl_cuids) == 0: # There were no complementarity conditions # so we don't hold onto the instance self._instance = None else: args = (self._instance,) else: self._instance = None # SystemCallSolver._presolve(self, *args, **kwds)
def _presolve(self, *args, **kwds): if not isinstance(args[0], six.string_types): self._instance = args[0] xfrm = TransformationFactory('mpec.nl') xfrm.apply_to(self._instance) if len(self._instance._transformation_data['mpec.nl'].compl_cuids ) == 0: # There were no complementarity conditions # so we don't hold onto the instance self._instance = None else: args = (self._instance, ) else: self._instance = None # SystemCallSolver._presolve(self, *args, **kwds)
def create_chull_model(self): m = ConcreteModel() m.p = Var([1, 2], bounds=(0, 10)) m.time1 = Disjunction(expr=[m.p[1] >= 1, m.p[1] == 0]) m.on = Disjunct() m.on.above_min = Constraint(expr=m.p[2] >= 1) m.on.ramping = Constraint(expr=m.p[2] - m.p[1] <= 3) m.on.on_before = Constraint(expr=m.p[1] >= 1) m.startup = Disjunct() m.startup.startup_limit = Constraint(expr=(1, m.p[2], 2)) m.startup.off_before = Constraint(expr=m.p[1] == 0) m.off = Disjunct() m.off.off = Constraint(expr=m.p[2] == 0) m.time2 = Disjunction(expr=[m.on, m.startup, m.off]) m.obj = Objective(expr=m.p[1] + m.p[2]) chull = TransformationFactory('gdp.chull') chull.apply_to(m) disaggregatedVars = ComponentSet([ chull.get_disaggregated_var(m.p[1], m.time1.disjuncts[0]), chull.get_disaggregated_var(m.p[1], m.time1.disjuncts[1]), chull.get_disaggregated_var(m.p[1], m.on), chull.get_disaggregated_var(m.p[2], m.on), chull.get_disaggregated_var(m.p[1], m.startup), chull.get_disaggregated_var(m.p[2], m.startup), chull.get_disaggregated_var(m.p[1], m.off), chull.get_disaggregated_var(m.p[2], m.off) ]) # from nose.tools import set_trace # set_trace() # disaggregatedVars = ComponentSet([relaxationBlocks[0].component("p[1]"), # relaxationBlocks[1].component("p[1]"), # relaxationBlocks[2].component("p[1]"), # relaxationBlocks[2].component("p[2]"), # relaxationBlocks[3].component("p[1]"), # relaxationBlocks[3].component("p[2]"), # relaxationBlocks[4].component("p[1]"), # relaxationBlocks[4].component("p[2]")]) return m, disaggregatedVars
def test_integer_arithmetic_non1_coefficients(self): m = ConcreteModel() m.x = Var(bounds=(0, 9)) m.y = Var(bounds=(-5, 5)) m.c1 = Constraint(expr=4 * m.x + m.y >= 4) m.c2 = Constraint(expr=m.y >= 2 * m.x) fme = TransformationFactory('contrib.fourier_motzkin_elimination') fme.apply_to(m, vars_to_eliminate=m.x, constraint_filtering_callback=None, do_integer_arithmetic=True, verbose=True) constraints = m._pyomo_contrib_fme_transformation.projected_constraints self.assertEqual(len(constraints), 3) cons = constraints[3] self.assertEqual(value(cons.lower), -32) self.assertIs(cons.body, m.y) self.assertIsNone(cons.upper) cons = constraints[2] self.assertEqual(value(cons.lower), 0) self.assertIsNone(cons.upper) repn = generate_standard_repn(cons.body) self.assertTrue(repn.is_linear()) self.assertEqual(len(repn.linear_coefs), 1) self.assertIs(repn.linear_vars[0], m.y) self.assertEqual(repn.linear_coefs[0], 2) cons = constraints[1] self.assertEqual(value(cons.lower), 4) self.assertIsNone(cons.upper) repn = generate_standard_repn(cons.body) self.assertTrue(repn.is_linear()) self.assertEqual(len(repn.linear_coefs), 1) self.assertIs(repn.linear_vars[0], m.y) self.assertEqual(repn.linear_coefs[0], 3)
def test_post_processing(self): m, disaggregatedVars = self.create_hull_model() fme = TransformationFactory('contrib.fourier_motzkin_elimination') fme.apply_to(m, vars_to_eliminate=disaggregatedVars) # post-process fme.post_process_fme_constraints(m, SolverFactory('glpk')) constraints = m._pyomo_contrib_fme_transformation.projected_constraints self.assertEqual(len(constraints), 11) # They should be the same as the above, but now these are *all* the # constraints self.check_hull_projected_constraints( m, constraints, [6, 5, 16, 17, 15, 9, 8, 1, 2, 3, 4]) # and check that we didn't change the model for disj in m.component_data_objects(Disjunct): self.assertIs(disj.indicator_var.domain, Binary) self.assertEqual(len([o for o in m.component_data_objects(Objective)]), 1) self.assertIsInstance(m.component("obj"), Objective) self.assertTrue(m.obj.active)
def test_use_all_var_bounds(self): m = ConcreteModel() m.b = Block() m.x = Var(bounds=(0, 15)) m.y = Var(bounds=(3, 5)) m.b.c = Constraint(expr=m.x + m.y <= 8) fme = TransformationFactory('contrib.fourier_motzkin_elimination') fme.apply_to(m.b, vars_to_eliminate=[m.y]) constraints = m.b.\ _pyomo_contrib_fme_transformation.projected_constraints # if we hadn't included y's bounds, then we wouldn't get any constraints # and y wouldn't be eliminated. If we do include y's bounds, we get new # information that x <= 5: self.assertEqual(len(constraints), 1) cons = constraints[1] self.assertEqual(value(cons.lower), -5) self.assertIsNone(cons.upper) repn = generate_standard_repn(cons.body) self.assertEqual(repn.constant, 0) self.assertEqual(len(repn.linear_vars), 1) self.assertIs(repn.linear_vars[0], m.x) self.assertEqual(repn.linear_coefs[0], -1)
def apply_discretization(self, transformation, **kwargs): """Discretizes the model. :param str transformation: The type of transformation (only dae.collocation...) :param dict kwargs: The options for the discretization :return: None """ fixed_times = kwargs.pop('fixed_times', None) if not self.model.alltime.get_discretization_info(): discretizer = TransformationFactory(transformation) if fixed_times == None: discretizer.apply_to(self.model, wrt=self.model.alltime, **kwargs) else: discretizer.apply_to(self.model, wrt=fixed_times, **kwargs) self._alltimes = sorted(self.model.alltime) self._n_alltimes = len(self._alltimes) # This needs to be looked at in more detail to see if it is still needed. #added for optional smoothing parameter with reading values from file CS: # if self._smoothparam_given: # dfps = pd.DataFrame(index=self.model.alltime, columns=self.model.smoothparameter_names) # for t in self.model.alltime: # if t not in self.model.allsmooth_times: # for points that are the same in original meas times and feed times # dfps.loc[t] = float(22.) #something that is not between 0 and 1 # else: # ps_dict_help = dict() # for p in self.model.smoothparameter_names: # ps_dict_help[t, p] = value(self.model.smooth_param_data[t, p]) # dfps.loc[t] = [ps_dict_help[t, p] for p in self.model.smoothparameter_names] # dfallps = dfps # dfallps.sort_index(inplace=True) # dfallps.index = dfallps.index.to_series().apply( # lambda x: np.round(x, 6)) # time from data rounded to 6 digits # dfallpsall = pd.DataFrame(index=self.model.alltime, columns=self.model.smoothparameter_names) # dfsmoothdata = pd.DataFrame(index=sorted(self.model.smooth_param_datatimes), columns=self.model.smoothparameter_names) # for t in self.model.smooth_param_datatimes: # dfsmoothdata.loc[t] = [value(self.model.smooth_param_data[t, p]) for p in self.model.smoothparameter_names] # for p in self.model.smoothparameter_names: # values = interpolate_trajectory(self.model.alltime, dfsmoothdata[p]) # for i, ti in enumerate(self.model.alltime): # if float(dfallps[p][ti]) > 1: # valueinterp=values[i] # dfallpsall[p][ti] = float(valueinterp) # else: # dfallpsall.loc[ti] = float(dfallps[p][ti]) self._default_initialization() # if hasattr(self.model, 'K'): # print('Scaling the parameters') # self.scale_parameters() else: print( '***WARNING: Model already discretized. Ignoring second discretization' )
def test_model_with_unrelated_nonlinear_expressions(self): m = ConcreteModel() m.x = Var([1, 2, 3], bounds=(0, 3)) m.y = Var() m.z = Var() @m.Constraint([1, 2]) def cons(m, i): return m.x[i] <= m.y**i m.cons2 = Constraint(expr=m.x[1] >= m.y) m.cons3 = Constraint(expr=m.x[2] >= m.z - 3) # This is vacuous, but I just want something that's not quadratic m.cons4 = Constraint(expr=m.x[3] <= log(m.y + 1)) fme = TransformationFactory('contrib.fourier_motzkin_elimination') fme.apply_to(m, vars_to_eliminate=m.x, constraint_filtering_callback=None) constraints = m._pyomo_contrib_fme_transformation.projected_constraints # 0 <= y <= 3 cons = constraints[6] self.assertEqual(cons.lower, 0) self.assertIs(cons.body, m.y) cons = constraints[5] self.assertEqual(cons.lower, -3) body = generate_standard_repn(cons.body) self.assertTrue(body.is_linear()) self.assertEqual(len(body.linear_vars), 1) self.assertIs(body.linear_vars[0], m.y) self.assertEqual(body.linear_coefs[0], -1) # z <= y**2 + 3 cons = constraints[4] self.assertEqual(cons.lower, -3) body = generate_standard_repn(cons.body) self.assertTrue(body.is_quadratic()) self.assertEqual(len(body.linear_vars), 1) self.assertIs(body.linear_vars[0], m.z) self.assertEqual(body.linear_coefs[0], -1) self.assertEqual(len(body.quadratic_vars), 1) self.assertEqual(body.quadratic_coefs[0], 1) self.assertIs(body.quadratic_vars[0][0], m.y) self.assertIs(body.quadratic_vars[0][1], m.y) # z <= 6 cons = constraints[2] self.assertEqual(cons.lower, -6) body = generate_standard_repn(cons.body) self.assertTrue(body.is_linear()) self.assertEqual(len(body.linear_vars), 1) self.assertEqual(body.linear_coefs[0], -1) self.assertIs(body.linear_vars[0], m.z) # 0 <= ln(y+ 1) cons = constraints[1] self.assertEqual(cons.lower, 0) body = generate_standard_repn(cons.body) self.assertTrue(body.is_nonlinear()) self.assertFalse(body.is_quadratic()) self.assertEqual(len(body.linear_vars), 0) self.assertEqual(body.nonlinear_expr.name, 'log') self.assertEqual(len(body.nonlinear_expr.args[0].args), 2) self.assertIs(body.nonlinear_expr.args[0].args[0], m.y) self.assertEqual(body.nonlinear_expr.args[0].args[1], 1) # 0 <= y**2 cons = constraints[3] self.assertEqual(cons.lower, 0) body = generate_standard_repn(cons.body) self.assertTrue(body.is_quadratic()) self.assertEqual(len(body.quadratic_vars), 1) self.assertEqual(body.quadratic_coefs[0], 1) self.assertIs(body.quadratic_vars[0][0], m.y) self.assertIs(body.quadratic_vars[0][1], m.y) # check constraints valid for a selection of points (this is nonconvex, # but anyway...) pts = [ #(sqrt(3), 6), Not numerically stable enough for this test (1, 4), (3, 6), (3, 0), (0, 0), (2, 6) ] for pt in pts: m.y.fix(pt[0]) m.z.fix(pt[1]) for i in constraints: self.assertLessEqual(value(constraints[i].lower), value(constraints[i].body)) m.y.fixed = False m.z.fixed = False # check post process these are non-convex, so I don't want to deal with # it... (and this is a good test that I *don't* deal with it.) constraints[4].deactivate() constraints[3].deactivate() constraints[1].deactivate() # NOTE also that some of the suproblems in this test are unbounded: We # need to keep those constraints. fme.post_process_fme_constraints(m, SolverFactory('glpk')) # we needed all the constraints, so we kept them all self.assertEqual(len(constraints), 6) # last check that if someone activates something on the model in # between, we just use it. (I struggle to imagine why you would do this # because why withold the information *during* FME, but if there's some # reason, we may as well use all the information we've got.) m.some_new_cons = Constraint(expr=m.y <= 2) fme.post_process_fme_constraints(m, SolverFactory('glpk')) # now we should have lost one constraint self.assertEqual(len(constraints), 5) # and it should be the y <= 3 one... self.assertIsNone(dict(constraints).get(5))
def test_get_index_set_except(self): ''' Tests: For components indexed by 0, 1, 2, 3, 4 sets: get_index_set_except one, then two (if any) of those sets check two items that should be in set_except insert item(s) back into these sets via index_getter ''' m = ConcreteModel() m.time = ContinuousSet(bounds=(0, 10)) m.space = ContinuousSet(bounds=(0, 10)) m.set1 = Set(initialize=['a', 'b', 'c']) m.set2 = Set(initialize=['d', 'e', 'f']) m.v = Var() m.v1 = Var(m.time) m.v2 = Var(m.time, m.space) m.v3 = Var(m.time, m.space, m.set1) m.v4 = Var(m.time, m.space, m.set1, m.set2) # Multi-dimensional set: m.set3 = Set(initialize=[('a', 1), ('b', 2)]) m.v5 = Var(m.set3) m.v6 = Var(m.time, m.space, m.set3) m.v7 = Var(m.set3, m.space, m.time) disc = TransformationFactory('dae.collocation') disc.apply_to(m, wrt=m.time, nfe=5, ncp=2, scheme='LAGRANGE-RADAU') disc.apply_to(m, wrt=m.space, nfe=5, ncp=2, scheme='LAGRANGE-RADAU') # Want this to give a TypeError # info = get_index_set_except(m.v, m.time) # Indexed by one set info = get_index_set_except(m.v1, m.time) set_except = info['set_except'] index_getter = info['index_getter'] self.assertTrue(set_except == [None]) # Variable is not indexed by anything except time # Test that index_getter returns only the new value given, # regardless of whether it was part of the set excluded (time): self.assertEqual(index_getter((), -1), -1) # Indexed by two sets info = get_index_set_except(m.v2, m.time) set_except = info['set_except'] index_getter = info['index_getter'] self.assertTrue(m.space[1] in set_except and m.space.last() in set_except) # Here (2,) is the partial index, corresponding to space. # Can be provided as a scalar or tuple. 4, the time index, # should be inserted before (2,) self.assertEqual(index_getter((2,), 4), (4, 2)) self.assertEqual(index_getter(2, 4), (4, 2)) # Case where every set is "omitted," now for multiple sets info = get_index_set_except(m.v2, m.space, m.time) set_except = info['set_except'] index_getter = info['index_getter'] self.assertTrue(set_except == [None]) # 5, 7 are the desired index values for space, time # index_getter should put them in the right order for m.v2, # even if they are not valid indices for m.v2 self.assertEqual(index_getter((), 5, 7), (7, 5)) # Indexed by three sets info = get_index_set_except(m.v3, m.time) # In this case set_except is a product of the two non-time sets # indexing v3 set_except = info['set_except'] index_getter = info['index_getter'] self.assertTrue((m.space[1], 'b') in set_except and (m.space.last(), 'a') in set_except) # index_getter inserts a scalar index into an index of length 2 self.assertEqual(index_getter((2, 'b'), 7), (7, 2, 'b')) info = get_index_set_except(m.v3, m.space, m.time) # Two sets omitted. Now set_except is just set1 set_except = info['set_except'] index_getter = info['index_getter'] self.assertTrue('a' in set_except) # index_getter inserts the two new indices in the right order self.assertEqual(index_getter('b', 1.2, 1.1), (1.1, 1.2, 'b')) # Indexed by four sets info = get_index_set_except(m.v4, m.set1, m.space) # set_except is a product, and there are two indices to insert set_except = info['set_except'] index_getter = info['index_getter'] self.assertTrue((m.time[1], 'd') in set_except) self.assertEqual(index_getter((4, 'f'), 'b', 8), (4, 8, 'b', 'f')) # The intended usage of this function looks something like: index_set = m.v4.index_set() for partial_index in set_except: complete_index = index_getter(partial_index, 'a', m.space[2]) self.assertTrue(complete_index in index_set) # Do something for every index of v4 at 'a' and space[2] # Indexed by a multi-dimensional set info = get_index_set_except(m.v5, m.set3) set_except = info['set_except'] index_getter = info['index_getter'] self.assertEqual(set_except, [None]) self.assertEqual(index_getter((), ('a', 1)), ('a', 1)) info = get_index_set_except(m.v6, m.set3, m.time) set_except = info['set_except'] index_getter = info['index_getter'] self.assertTrue(m.space[1] in set_except) self.assertEqual(index_getter(m.space[1], ('b', 2), m.time[1]), (m.time[1], m.space[1], 'b', 2)) info = get_index_set_except(m.v7, m.time) set_except = info['set_except'] index_getter = info['index_getter'] self.assertIn(('a', 1, m.space[1]), set_except) self.assertEqual(index_getter(('a', 1, m.space[1]), m.time[1]), ('a', 1, m.space[1], m.time[1])) m.v8 = Var(m.time, m.set3, m.time) with self.assertRaises(ValueError): info = get_index_set_except(m.v8, m.time) with self.assertRaises(ValueError): info = get_index_set_except(m.v8, m.space)
def test_indexed_by(self): m = ConcreteModel() m.time = ContinuousSet(bounds=(0, 10)) m.space = ContinuousSet(bounds=(0, 10)) m.set = Set(initialize=['a', 'b', 'c']) m.set2 = Set(initialize=[('a', 1), ('b', 2)]) m.v = Var() m.v1 = Var(m.time) m.v2 = Var(m.time, m.space) m.v3 = Var(m.set, m.space, m.time) m.v4 = Var(m.time, m.set2) m.v5 = Var(m.set2, m.time, m.space) @m.Block() def b(b): b.v = Var() b.v1 = Var(m.time) b.v2 = Var(m.time, m.space) b.v3 = Var(m.set, m.space, m.time) @m.Block(m.time) def b1(b): b.v = Var() b.v1 = Var(m.space) b.v2 = Var(m.space, m.set) @m.Block(m.time, m.space) def b2(b): b.v = Var() b.v1 = Var(m.set) @b.Block() def b(bl): bl.v = Var() bl.v1 = Var(m.set) bl.v2 = Var(m.time) @m.Block(m.set2, m.time) def b3(b): b.v = Var() b.v1 = Var(m.space) @b.Block(m.space) def b(bb): bb.v = Var(m.set) disc = TransformationFactory('dae.collocation') disc.apply_to(m, wrt=m.time, nfe=5, ncp=2, scheme='LAGRANGE-RADAU') disc.apply_to(m, wrt=m.space, nfe=5, ncp=2, scheme='LAGRANGE-RADAU') self.assertFalse(is_explicitly_indexed_by(m.v, m.time)) self.assertTrue(is_explicitly_indexed_by(m.b.v2, m.space)) self.assertTrue(is_explicitly_indexed_by(m.b.v3, m.time, m.space)) self.assertFalse(is_in_block_indexed_by(m.v1, m.time)) self.assertFalse(is_in_block_indexed_by(m.v2, m.set)) self.assertTrue(is_in_block_indexed_by(m.b1[m.time[1]].v2, m.time)) self.assertTrue(is_in_block_indexed_by( m.b2[m.time[1], m.space[1]].b.v1, m.time)) self.assertTrue(is_in_block_indexed_by( m.b2[m.time[1], m.space[1]].b.v2, m.time)) self.assertTrue(is_explicitly_indexed_by( m.b2[m.time[1], m.space[1]].b.v2, m.time)) self.assertFalse(is_in_block_indexed_by( m.b2[m.time[1], m.space[1]].b.v1, m.set)) self.assertFalse(is_in_block_indexed_by( m.b2[m.time[1], m.space[1]].b.v1, m.space, stop_at=m.b2[m.time[1], m.space[1]])) # Explicit indexing with multi-dimensional set: self.assertTrue(is_explicitly_indexed_by(m.v4, m.time, m.set2)) self.assertTrue(is_explicitly_indexed_by(m.v5, m.time, m.set2, m.space)) # Implicit indexing with multi-dimensional set: self.assertTrue(is_in_block_indexed_by( m.b3['a', 1, m.time[1]].v, m.set2)) self.assertTrue(is_in_block_indexed_by( m.b3['a', 1, m.time[1]].v, m.time)) self.assertTrue(is_in_block_indexed_by( m.b3['a', 1, m.time[1]].v1[m.space[1]], m.set2)) self.assertFalse(is_in_block_indexed_by( m.b3['a', 1, m.time[1]].v1[m.space[1]], m.space)) self.assertTrue(is_in_block_indexed_by( m.b3['b', 2, m.time[2]].b[m.space[2]].v['b'], m.set2)) self.assertTrue(is_in_block_indexed_by( m.b3['b', 2, m.time[2]].b[m.space[2]].v['b'], m.time)) self.assertTrue(is_in_block_indexed_by( m.b3['b', 2, m.time[2]].b[m.space[2]].v['b'], m.space)) self.assertFalse(is_in_block_indexed_by( m.b3['b', 2, m.time[2]].b[m.space[2]].v['b'], m.set)) self.assertFalse(is_in_block_indexed_by( m.b3['b', 2, m.time[2]].b[m.space[2]].v['b'], m.time, stop_at=m.b3['b', 2, m.time[2]])) self.assertFalse(is_in_block_indexed_by( m.b3['b', 2, m.time[2]].b[m.space[2]].v['b'], m.time, stop_at=m.b3))
def test_numerical_instability_early_elimination(self): # A more subtle numerical problem is that, in infinite precision, a # variable might be eliminated early. However, if this goes wrong, the # result can be unexpected (including getting no constraints when some # are expected.) m = ConcreteModel() m.x = Var() m.x0 = Var() m.y = Var() # we'll pretend that the 1.123e-9 is noise from previous calculations m.cons1 = Constraint( expr=0 <= (4.27 + 1.123e-9) * m.x + 13 * m.y - m.x0) m.cons2 = Constraint(expr=m.x0 >= 12 * m.y + 4.27 * m.x) fme = TransformationFactory('contrib.fourier_motzkin_elimination') # doing my own clones because I want assertIs tests first = m.clone() second = m.clone() third = m.clone() fme.apply_to(first, vars_to_eliminate=[first.x0], zero_tolerance=1e-10) constraints = first._pyomo_contrib_fme_transformation.\ projected_constraints cons = constraints[1] self.assertEqual(cons.lower, 0) repn = generate_standard_repn(cons.body) self.assertTrue(repn.is_linear()) self.assertEqual(repn.constant, 0) self.assertEqual(len(repn.linear_coefs), 2) # x is still around self.assertIs(repn.linear_vars[0], first.x) self.assertAlmostEqual(repn.linear_coefs[0], 1.123e-9) self.assertIs(repn.linear_vars[1], first.y) self.assertEqual(repn.linear_coefs[1], 1) self.assertIsNone(cons.upper) # so just to drive home the point, this results in no constraints: # (Though also note that that only happens if x0 is the first to be # projected out) fme.apply_to(second, vars_to_eliminate=[second.x0, second.x], zero_tolerance=1e-10) self.assertEqual(len(second._pyomo_contrib_fme_transformation.\ projected_constraints), 0) # but in this version, we assume that x is already gone... fme.apply_to(third, vars_to_eliminate=[third.x0], verbose=True, zero_tolerance=1e-8) constraints = third._pyomo_contrib_fme_transformation.\ projected_constraints cons = constraints[1] self.assertEqual(cons.lower, 0) self.assertIs(cons.body, third.y) self.assertIsNone(cons.upper) # and this is exactly the same as the above: fme.apply_to(m, vars_to_eliminate=[m.x0, m.x], verbose=True, zero_tolerance=1e-8) constraints = m._pyomo_contrib_fme_transformation.projected_constraints cons = constraints[1] self.assertEqual(cons.lower, 0) self.assertIs(cons.body, m.y) self.assertIsNone(cons.upper)