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_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))