def test_reciprocal(self): m = ConcreteModel() m.x = Var(bounds=(1, 2), initialize=1) m.y = Var(bounds=(2, 3), initialize=2) mc_expr = mc(m.x / m.y) self.assertEqual(mc_expr.lower(), 1 / 3) self.assertEqual(mc_expr.upper(), 1)
def test_var(self): m = ConcreteModel() m.x = Var(bounds=(-1, 1), initialize=3) mc_var = mc(m.x) self.assertEqual(mc_var.lower(), -1) self.assertEqual(mc_var.upper(), 1) m.no_ub = Var(bounds=(0, None), initialize=3) output = StringIO() with LoggingIntercept(output, 'pyomo.contrib.mcpp', logging.WARNING): mc_var = mc(m.no_ub) self.assertIn("Var no_ub missing upper bound.", output.getvalue().strip()) self.assertEqual(mc_var.lower(), 0) self.assertEqual(mc_var.upper(), 500000) m.no_lb = Var(bounds=(None, -3), initialize=-1) output = StringIO() with LoggingIntercept(output, 'pyomo.contrib.mcpp', logging.WARNING): mc_var = mc(m.no_lb) self.assertIn("Var no_lb missing lower bound.", output.getvalue().strip()) self.assertEqual(mc_var.lower(), -500000) self.assertEqual(mc_var.upper(), -3) m.no_val = Var(bounds=(0, 1)) output = StringIO() with LoggingIntercept(output, 'pyomo.contrib.mcpp', logging.WARNING): mc_var = mc(m.no_val) mc_var.subcv() self.assertIn("Var no_val missing value.", output.getvalue().strip()) self.assertEqual(mc_var.lower(), 0) self.assertEqual(mc_var.upper(), 1)
def test_linear_expression(self): m = ConcreteModel() m.x = Var(bounds=(1, 2), initialize=1) with self.assertRaises(NotImplementedError): mc_expr = mc(quicksum([m.x, m.x], linear=True)) self.assertEqual(mc_expr.lower(), 2) self.assertEqual(mc_expr.upper(), 4)
def test_clone_without_expression_components(self): m = ConcreteModel() m.x = Var(initialize=5) m.y = Var(initialize=3) m.e = Expression(expr=m.x**2 + m.x - 1) base = m.x**2 + 1 test = clone_without_expression_components(base, {}) self.assertIs(base, test) self.assertEqual(base(), test()) test = clone_without_expression_components(base, {id(m.x): m.y}) self.assertEqual(3**2+1, test()) base = m.e test = clone_without_expression_components(base, {}) self.assertIsNot(base, test) self.assertEqual(base(), test()) self.assertIsInstance(base, _ExpressionData) self.assertIsInstance(test, EXPR.SumExpression) test = clone_without_expression_components(base, {id(m.x): m.y}) self.assertEqual(3**2+3-1, test()) base = m.e + m.x test = clone_without_expression_components(base, {}) self.assertIsNot(base, test) self.assertEqual(base(), test()) self.assertIsInstance(base, EXPR.SumExpression) self.assertIsInstance(test, EXPR.SumExpression) self.assertIsInstance(base.arg(0), _ExpressionData) self.assertIsInstance(test.arg(0), EXPR.SumExpression) test = clone_without_expression_components(base, {id(m.x): m.y}) self.assertEqual(3**2+3-1 + 3, test())
def test_active_parent_block(self): m = ConcreteModel() m.d1 = Block() m.d1.sub1 = Disjunct() m.d1.sub2 = Disjunct() m.d1.disj = Disjunction(expr=[m.d1.sub1, m.d1.sub2]) with self.assertRaises(GDP_Error): TransformationFactory('gdp.reclassify').apply_to(m)
def test_lmtd(self): m = ConcreteModel() m.x = Var(bounds=(0.1, 500), initialize=33.327) m.y = Var(bounds=(0.1, 500), initialize=14.436) m.z = Var(bounds=(0, 90), initialize=22.5653) mc_expr = mc(m.z - (m.x * m.y * (m.x + m.y) / 2) ** (1/3)) self.assertAlmostEqual(mc_expr.convex(), -407.95444629965016) self.assertAlmostEqual(mc_expr.lower(), -499.99999999999983)
def test_improved_bounds(self): m = ConcreteModel() m.x = Var(bounds=(0, 100), initialize=5) improved_bounds = ComponentMap() improved_bounds[m.x] = (10, 20) mc_expr = mc(m.x, improved_var_bounds=improved_bounds) self.assertEqual(mc_expr.lower(), 10) self.assertEqual(mc_expr.upper(), 20)
def test_fixed_var(self): m = ConcreteModel() m.x = Var(bounds=(-50, 80), initialize=3) m.y = Var(bounds=(0, 6), initialize=2) m.y.fix() mc_expr = mc(m.x * m.y) self.assertEqual(mc_expr.lower(), -100) self.assertEqual(mc_expr.upper(), 160)
def makeDisjunctWithRangeSet(): m = ConcreteModel() m.x = Var(bounds=(0, 1)) m.d1 = Disjunct() m.d1.s = RangeSet(1) m.d1.c = Constraint(rule=lambda _: m.x == 1) m.d2 = Disjunct() m.disj = Disjunction(expr=[m.d1, m.d2]) return m
def test_mc_2d(self): m = ConcreteModel() m.x = Var(bounds=(pi / 6, pi / 3), initialize=pi / 4) m.e = Expression(expr=cos(pow(m.x, 2)) * sin(pow(m.x, -3))) mc_ccVals, mc_cvVals, aff_cc, aff_cv = make2dPlot(m.e.expr, 50) self.assertAlmostEqual(mc_ccVals[1], 0.6443888590411435) self.assertAlmostEqual(mc_cvVals[1], 0.2328315489072924) self.assertAlmostEqual(aff_cc[1], 0.9674274332870583) self.assertAlmostEqual(aff_cv[1], -1.578938503009686)
def test_mc_3d(self): m = ConcreteModel() m.x = Var(bounds=(-2, 1), initialize=-1) m.y = Var(bounds=(-1, 2), initialize=0) m.e = Expression(expr=m.x * pow(exp(m.x) - m.y, 2)) ccSurf, cvSurf, ccAffine, cvAffine = make3dPlot(m.e.expr, 30) self.assertAlmostEqual(ccSurf[48], 11.5655473482574) self.assertAlmostEqual(cvSurf[48], -15.28102124928224) self.assertAlmostEqual(ccAffine[48], 11.565547348257398) self.assertAlmostEqual(cvAffine[48], -23.131094696514797)
def test_indexedvar_noindextemplate(self): st_model = CreateConcreteTwoStageScenarioTreeModel(1) st_model.StageVariables['Stage1'].add("x") st_model.StageDerivedVariables['Stage1'].add("y") st_model.NodeVariables['RootNode'].add("z") st_model.NodeDerivedVariables['RootNode'].add("q") st_model.StageCost['Stage1'] = "FirstStageCost" st_model.StageCost['Stage2'] = "SecondStageCost" scenario_tree = ScenarioTree(scenariotreeinstance=st_model) self.assertEqual(len(scenario_tree.stages), 2) self.assertEqual(len(scenario_tree.nodes), 2) self.assertEqual(len(scenario_tree.scenarios), 1) model = ConcreteModel() model.s = Set(initialize=[1,2,3]) model.x = Var(model.s) model.y = Var(model.s) model.z = Var(model.s) model.q = Var(model.s) model.FirstStageCost = Expression(expr=0.0) model.SecondStageCost = Expression(expr=0.0) model.obj = Objective(expr=0.0) scenario_tree.linkInInstances({'Scenario1': model}) root = scenario_tree.findRootNode() self.assertEqual(len(root._variable_ids), 12) self.assertEqual(len(root._standard_variable_ids), 6) self.assertEqual(len(root._derived_variable_ids), 6) for name in ("x", "y", "z", "q"): for index in model.s: self.assertEqual( (name,index) in root._name_index_to_id, True)
def test_fixed_var(self): m = ConcreteModel() m.x = Var(bounds=(-50, 80), initialize=3) m.y = Var(bounds=(0, 6), initialize=2) m.y.fix() mc_expr = mc(m.x * m.y) self.assertEqual(mc_expr.lower(), -100) self.assertEqual(mc_expr.upper(), 160) self.assertEqual( str(mc_expr), "[ -1.00000e+02 : 1.60000e+02 ] [ 6.00000e+00 : 6.00000e+00 ] [ ( 2.00000e+00) : ( 2.00000e+00) ]")
def test_deactivated_parent_block(self): m = ConcreteModel() m.d1 = Block() m.d1.sub1 = Disjunct() m.d1.sub2 = Disjunct() m.d1.disj = Disjunction(expr=[m.d1.sub1, m.d1.sub2]) m.d1.deactivate() TransformationFactory('gdp.reclassify').apply_to(m) self.assertIs(m.d1.type(), Block) self.assertIs(m.d1.sub1.type(), Block) self.assertIs(m.d1.sub2.type(), Block)
def test_active_parent_disjunct_target(self): m = ConcreteModel() m.d1 = Disjunct() m.d1.sub1 = Disjunct() m.d1.sub2 = Disjunct() m.d1.disj = Disjunction(expr=[m.d1.sub1, m.d1.sub2]) TransformationFactory('gdp.bigm').apply_to(m, targets=m.d1.disj) m.d1.indicator_var.fix(1) TransformationFactory('gdp.reclassify').apply_to(m) self.assertIs(m.d1.type(), Block) self.assertIs(m.d1.sub1.type(), Block) self.assertIs(m.d1.sub2.type(), Block)
def test_trig(self): m = ConcreteModel() m.x = Var(bounds=(pi / 4, pi / 2), initialize=pi / 4) mc_expr = mc(tan(atan((m.x)))) self.assertAlmostEqual(mc_expr.lower(), pi / 4) self.assertAlmostEqual(mc_expr.upper(), pi / 2) m.y = Var(bounds=(0, sin(pi / 4)), initialize=0) mc_expr = mc(asin((m.y))) self.assertEqual(mc_expr.lower(), 0) self.assertAlmostEqual(mc_expr.upper(), pi / 4) m.z = Var(bounds=(0, cos(pi / 4)), initialize=0) mc_expr = mc(acos((m.z))) self.assertAlmostEqual(mc_expr.lower(), pi / 4) self.assertAlmostEqual(mc_expr.upper(), pi / 2)
def test_singletonvar_wildcardtemplate(self): st_model = CreateConcreteTwoStageScenarioTreeModel(1) st_model.StageVariables['Stage1'].add("x[*]") st_model.StageDerivedVariables['Stage1'].add("y[*]") st_model.NodeVariables['RootNode'].add("z[*]") st_model.NodeDerivedVariables['RootNode'].add("q[*]") st_model.StageCost['Stage1'] = "FirstStageCost" st_model.StageCost['Stage2'] = "SecondStageCost" scenario_tree = ScenarioTree(scenariotreeinstance=st_model) self.assertEqual(len(scenario_tree.stages), 2) self.assertEqual(len(scenario_tree.nodes), 2) self.assertEqual(len(scenario_tree.scenarios), 1) model = ConcreteModel() model.x = Var() model.y = Var() model.z = Var() model.q = Var() model.FirstStageCost = Expression(expr=0.0) model.SecondStageCost = Expression(expr=0.0) model.obj = Objective(expr=0.0) scenario_tree.linkInInstances({'Scenario1': model}) root = scenario_tree.findRootNode() self.assertEqual(len(root._variable_ids), 4) self.assertEqual(len(root._standard_variable_ids), 2) self.assertEqual(len(root._derived_variable_ids), 2) for name in ("x", "y", "z", "q"): for index in [None]: self.assertEqual( (name,index) in root._name_index_to_id, True)
def select_tear_mip_model(self, G): """ Generate a model for selecting tears from the given graph Returns ------- model bin_list A list of the binary variables representing each edge, indexed by the edge index of the graph """ model = ConcreteModel() bin_list = [] for i in range(G.number_of_edges()): # add a binary "torn" variable for every edge vname = "edge%s" % i var = Var(domain=Binary) bin_list.append(var) model.add_component(vname, var) # var containing the maximum number of times any cycle is torn mct = model.max_cycle_tears = Var() _, cycleEdges = self.all_cycles(G) for i in range(len(cycleEdges)): ecyc = cycleEdges[i] # expression containing sum of tears for each cycle ename = "cycle_sum%s" % i expr = Expression(expr=sum(bin_list[i] for i in ecyc)) model.add_component(ename, expr) # every cycle must have at least 1 tear cname_min = "cycle_min%s" % i con_min = Constraint(expr=expr >= 1) model.add_component(cname_min, con_min) # mct >= cycle_sum for all cycles, thus it becomes the max cname_mct = mct.name + "_geq%s" % i con_mct = Constraint(expr=mct >= expr) model.add_component(cname_mct, con_mct) # weigh the primary objective much greater than the secondary obj_expr = 1000 * mct + sum(var for var in bin_list) model.obj = Objective(expr=obj_expr, sense=minimize) return model, bin_list
def test_deactivate_nested_disjunction(self): m = ConcreteModel() m.d1 = Disjunct() m.d1.d1 = Disjunct() m.d1.d2 = Disjunct() m.d1.disj = Disjunction(expr=[m.d1.d1, m.d1.d2]) m.d2 = Disjunct() m.disj = Disjunction(expr=[m.d1, m.d2]) m.d1.deactivate() TransformationFactory('gdp.bigm').apply_to(m) # for disj in m.component_data_objects(Disjunction, active=True): # print(disj.name) # There should be no active Disjunction objects. self.assertIsNone( next(m.component_data_objects(Disjunction, active=True), None))
def makeThreeTermDisj_IndexedConstraints(): m = ConcreteModel() m.I = [1, 2, 3] m.x = Var(m.I, bounds=(0, 10)) def c_rule(b, i): m = b.model() return m.x[i] >= i def d_rule(d, j): m = d.model() d.c = Constraint(m.I[:j], rule=c_rule) m.d = Disjunct(m.I, rule=d_rule) m.disjunction = Disjunction(expr=[m.d[i] for i in m.I]) return m
def makeTwoTermDisj(): m = ConcreteModel() m.a = Var(bounds=(2, 7)) m.x = Var(bounds=(4, 9)) def d_rule(disjunct, flag): m = disjunct.model() if flag: disjunct.c1 = Constraint(expr=m.a == 0) disjunct.c2 = Constraint(expr=m.x <= 7) else: disjunct.c = Constraint(expr=m.a >= 5) m.d = Disjunct([0, 1], rule=d_rule) m.disjunction = Disjunction(expr=[m.d[0], m.d[1]]) return m
def _create_model(self, ctype, **kwds): self.model = ConcreteModel() self.model.x = Var() self.model.IDX = Set(initialize=sorted(range(1000000))) self.model.del_component('test_component') self.model.test_component = \ ctype(self.model.IDX, **kwds)
def test_powers(self): m = ConcreteModel() m.x = Var(bounds=(0, 2), initialize=1) m.y = Var(bounds=(1e-4, 2), initialize=1) with self.assertRaisesRegexp(MCPP_Error, "Log with negative values in range"): mc(m.x ** 1.5) mc_expr = mc(m.y ** 1.5) self.assertAlmostEqual(mc_expr.lower(), 1e-4**1.5) self.assertAlmostEqual(mc_expr.upper(), 2**1.5) mc_expr = mc(m.y ** m.x) self.assertAlmostEqual(mc_expr.lower(), 1e-4**2) self.assertAlmostEqual(mc_expr.upper(), 4) m.z = Var(bounds=(-1, 1), initialize=0) mc_expr = mc(m.z ** 2) self.assertAlmostEqual(mc_expr.lower(), 0) self.assertAlmostEqual(mc_expr.upper(), 1)
def makeTwoTermIndexedDisjunction_BoundedVars(): m = ConcreteModel() m.s = Set(initialize=[1, 2, 3]) m.a = Var(m.s, bounds=(-100, 100)) def disjunct_rule(d, s, flag): m = d.model() if flag: d.c = Constraint(expr=m.a[s] >= 6) else: d.c = Constraint(expr=m.a[s] <= 3) m.disjunct = Disjunct(m.s, [0, 1], rule=disjunct_rule) def disjunction_rule(m, s): return [m.disjunct[s, flag] for flag in [0, 1]] m.disjunction = Disjunction(m.s, rule=disjunction_rule) return m
def makeTwoTermDisj_IndexedConstraints_BoundedVars(): # same concept as above, but bounded variables m = ConcreteModel() m.s = Set(initialize=[1, 2]) m.lbs = Param(m.s, initialize={1: 2, 2: 4}) m.ubs = Param(m.s, initialize={1: 7, 2: 6}) def bounds_rule(m, s): return (m.lbs[s], m.ubs[s]) m.a = Var(m.s, bounds=bounds_rule) def d_rule(disjunct, flag): m = disjunct.model() def true_rule(d, s): return m.a[s] == 0 def false_rule(d, s): return m.a[s] >= 5 if flag: disjunct.c = Constraint(m.s, rule=true_rule) else: disjunct.c = Constraint(m.s, rule=false_rule) m.disjunct = Disjunct([0, 1], rule=d_rule) m.disjunction = Disjunction(expr=[m.disjunct[0], m.disjunct[1]]) return m
def makeTwoTermDisjOnBlock(): m = ConcreteModel() m.b = Block() m.a = Var(bounds=(0, 5)) # On a whim, verify that the decorator notation works @m.b.Disjunct([0, 1]) def disjunct(disjunct, flag): m = disjunct.model() if flag: disjunct.c = Constraint(expr=m.a <= 3) else: disjunct.c = Constraint(expr=m.a == 0) @m.b.Disjunction() def disjunction(m): return [m.disjunct[0], m.disjunct[1]] return m
def makeThreeTermIndexedDisj(): m = ConcreteModel() m.s = Set(initialize=[1, 2]) m.a = Var(m.s, bounds=(2, 7)) def d_rule(disjunct, flag, s): m = disjunct.model() if flag == 0: disjunct.c = Constraint(expr=m.a[s] == 0) elif flag == 1: disjunct.c = Constraint(expr=m.a[s] >= 5) else: disjunct.c = Constraint(expr=inequality(2, m.a[s], 4)) m.disjunct = Disjunct([0, 1, 2], m.s, rule=d_rule) def disj_rule(m, s): return [m.disjunct[0, s], m.disjunct[1, s], m.disjunct[2, s]] m.disjunction = Disjunction(m.s, rule=disj_rule) return m
def makeTwoTermDisj_BlockOnDisj(): m = ConcreteModel() m.x = Var(bounds=(0, 1000)) m.y = Var(bounds=(0, 800)) def disj_rule(d, flag): m = d.model() if flag: d.b = Block() d.b.c = Constraint(expr=m.x == 0) d.add_component('b.c', Constraint(expr=m.y >= 9)) d.b.anotherblock = Block() d.b.anotherblock.c = Constraint(expr=m.y >= 11) d.bb = Block([1]) d.bb[1].c = Constraint(expr=m.x == 0) else: d.c = Constraint(expr=m.x >= 80) m.evil = Disjunct([0, 1], rule=disj_rule) m.disjunction = Disjunction(expr=[m.evil[0], m.evil[1]]) return m
class ComponentPerformanceBase(object): @classmethod def _create_model(self, ctype, **kwds): self.model = ConcreteModel() self.model.x = Var() self.model.IDX = Set(initialize=sorted(range(1000000))) self.model.del_component('test_component') self.model.test_component = \ ctype(self.model.IDX, **kwds) @classmethod def setUp(self): if self.model is None: self._setup() @classmethod def setUpClass(self): self.model = None @classmethod def tearDownClass(self): self.model = None def test_0_setup(self): # Needed so that the time to set up the model is not included in # the subsequent performance tests. This test is named so that # it should appear first in the set of tests run by this test class pass def test_iteration(self): cnt = 0 for cdata in self.model.component_data_objects(self.model.test_component.type()): cnt += 1 self.assertTrue(cnt > 0) if self.model.test_component.type() in (Set, Var): self.assertEqual(cnt, len(self.model.test_component) + 1) else: self.assertEqual(cnt, len(self.model.test_component))
def makeDisjunctionsOnIndexedBlock(): m = ConcreteModel() m.s = Set(initialize=[1, 2]) m.a = Var(m.s, bounds=(0, 70)) @m.Disjunct(m.s, [0, 1]) def disjunct1(disjunct, s, flag): m = disjunct.model() if not flag: disjunct.c = Constraint(expr=m.a[s] == 0) else: disjunct.c = Constraint(expr=m.a[s] >= 7) def disjunction1_rule(m, s): return [m.disjunct1[s, flag] for flag in [0, 1]] m.disjunction1 = Disjunction(m.s, rule=disjunction1_rule) m.b = Block([0, 1]) m.b[0].x = Var(bounds=(-2, 2)) def disjunct2_rule(disjunct, flag): if not flag: disjunct.c = Constraint(expr=m.b[0].x <= 0) else: disjunct.c = Constraint(expr=m.b[0].x >= 0) m.b[0].disjunct = Disjunct([0, 1], rule=disjunct2_rule) def disjunction(b, i): return [b.disjunct[0], b.disjunct[1]] m.b[0].disjunction = Disjunction([0], rule=disjunction) m.b[1].y = Var(bounds=(-3, 3)) m.b[1].disjunct0 = Disjunct() m.b[1].disjunct0.c = Constraint(expr=m.b[1].y <= 0) m.b[1].disjunct1 = Disjunct() m.b[1].disjunct1.c = Constraint(expr=m.b[1].y >= 0) m.b[1].disjunction = Disjunction( expr=[m.b[1].disjunct0, m.b[1].disjunct1]) return m
def define_model(**kwds): model = ConcreteModel() model.x = Var(INDEX_SET, bounds=(-5,4)) # domain variable model.Fx = Var(INDEX_SET) # range variable model.p = Param(INDEX_SET, initialize=1.0) model.obj = Objective(expr=sum_product(model.Fx), sense=kwds.pop('sense',maximize)) model.piecewise = Piecewise(INDEX_SET,model.Fx,model.x, pw_pts=DOMAIN_PTS, f_rule=F, **kwds) #Fix the answer for testing purposes model.set_answer_constraint1 = Constraint(expr= model.x[1,0] == -5.0) model.set_answer_constraint2 = Constraint(expr= model.x[2,0] == -3.0) model.set_answer_constraint3 = Constraint(expr= model.x[3,0] == -2.5) model.set_answer_constraint4 = Constraint(expr= model.x[4,0] == -1.5) model.set_answer_constraint5 = Constraint(expr= model.x[5,0] == 2.0) model.set_answer_constraint6 = Constraint(expr= model.x[6,0] == 3.5) model.set_answer_constraint7 = Constraint(expr= model.x[7,0] == 4.0) model.set_answer_constraint8 = Constraint(expr= model.x[1,1] == -5.0) model.set_answer_constraint9 = Constraint(expr= model.x[2,1] == -3.0) model.set_answer_constraint10 = Constraint(expr= model.x[3,1] == -2.5) model.set_answer_constraint11 = Constraint(expr= model.x[4,1] == -1.5) model.set_answer_constraint12 = Constraint(expr= model.x[5,1] == 2.0) model.set_answer_constraint13 = Constraint(expr= model.x[6,1] == 3.5) model.set_answer_constraint14 = Constraint(expr= model.x[7,1] == 4.0) return model
def test_fix_value(self): m = ConcreteModel() m.iv = AutoLinkedBooleanVar() m.biv = AutoLinkedBinaryVar(m.iv) m.iv.associate_binary_var(m.biv) m.iv.fix() self.assertTrue(m.iv.is_fixed()) self.assertTrue(m.biv.is_fixed()) self.assertIsNone(m.iv.value) self.assertIsNone(m.biv.value) m.iv.fix(True) self.assertEqual(m.iv.value, True) self.assertEqual(m.biv.value, 1) m.iv.fix(False) self.assertEqual(m.iv.value, False) self.assertEqual(m.biv.value, 0) m.iv.fix(None) self.assertEqual(m.iv.value, None) self.assertEqual(m.biv.value, None) m.biv.fix(1) self.assertEqual(m.iv.value, True) self.assertEqual(m.biv.value, 1) with LoggingIntercept() as LOG: m.biv.fix(0.5) self.assertEqual( LOG.getvalue().strip(), "Setting Var 'biv' to a " "value `0.5` (float) not in domain Binary.") self.assertEqual(m.iv.value, None) self.assertEqual(m.biv.value, 0.5) with LoggingIntercept() as LOG: m.biv.fix(0.55, True) self.assertEqual(LOG.getvalue().strip(), "") self.assertEqual(m.iv.value, None) self.assertEqual(m.biv.value, 0.55) m.biv.fix(0) self.assertEqual(m.iv.value, False) self.assertEqual(m.biv.value, 0) eps = AutoLinkedBinaryVar.INTEGER_TOLERANCE / 10 # Note that fixing to a near-True value will toggle the iv with LoggingIntercept() as LOG: m.biv.fix(1 - eps) self.assertEqual( LOG.getvalue().strip(), "Setting Var 'biv' to a " "value `%s` (float) not in domain Binary." % (1 - eps)) self.assertEqual(m.iv.value, True) self.assertEqual(m.biv.value, 1 - eps) with LoggingIntercept() as LOG: m.biv.fix(eps, True) self.assertEqual(LOG.getvalue().strip(), "") self.assertEqual(m.iv.value, False) self.assertEqual(m.biv.value, eps) m.iv.fix(True) self.assertEqual(m.iv.value, True) self.assertEqual(m.biv.value, 1) m.iv.fix(False) self.assertEqual(m.iv.value, False) self.assertEqual(m.biv.value, 0)
def _compute_entity_alone_profits( self, quarter: pd.Timestamp) -> Dict[int, float]: """ Profit (or cost) of export, import, peak under balance constraint. No exchange between entities. Only one problem gathering all the entities is solved, but no variable is shared among entities. :param quarter: current quarter start time. :return: A dict entity_id -> entity_alone_profit. """ model = ConcreteModel() # Sets self._add_sets(model) # Variables self._add_grid_vars(model) model.peak = Var(model.entities, within=NonNegativeReals) # Entity peak [kW] model.J = Var(model.entities, within=Reals) # Entity profit [EUR] def entity_balance_rule(m, e, p): # Fix variables depending on the net position. (Note: If position is 0, fix all to zero.) if is_zero(self._net_position(e, p, quarter)): m.imp_grid[e, p].fix(0) m.exp_grid[e, p].fix(0) return Constraint.Skip elif self._net_position(e, p, quarter) > 0: # export position, can fix imports to zero m.imp_grid[e, p].fix(0) elif self._net_position(e, p, quarter) < 0: # import position, can fix exports to zero m.exp_grid[e, p].fix(0) return m.exp_grid[e, p] - m.imp_grid[e, p] == self._net_position( e, p, quarter) model.entity_balance = Constraint(model.entities, model.periods, rule=entity_balance_rule) def entity_peak_rule(m, e): """ """ lhs = sum(m.imp_grid[e, p] for p in model.periods) / self.n_periods_in_quarter rhs = self.entities[e].past_peak + m.peak[e] return lhs <= rhs model.entity_peak = Constraint(model.entities, rule=entity_peak_rule) def entity_profit_rule(m: ConcreteModel, e: int): expr = 0 # Energy for p in model.periods: expr += m.exp_grid[e, p] * self._sale_price( e, p, quarter) * self.period_duration_in_hours expr -= m.imp_grid[e, p] * self._purchase_price( e, p, quarter) * self.period_duration_in_hours # Capacity expr -= m.peak[e] * self.entities[e].peak_price return model.J[e] == expr model.entity_profit = Constraint(model.entities, rule=entity_profit_rule) model.obj = Objective(expr=sum(model.J[e] for e in model.entities), sense=maximize) self._solve(model, name="entity") entity_alone_profits = {e: model.J[e].value for e in model.entities} for e in model.entities: self.entities[e].past_peak = max(self.entities[e].past_peak, model.peak[e].value) # DEBUG print("Entity %d peak: " % e, self.entities[e].past_peak) return entity_alone_profits
def _generate_model(self): self.model = ConcreteModel() model = self.model model._name = self.description model.s = Set(initialize=[1,2]) model.x_unused = Var(within=Integers) model.x_unused.stale = False model.x_unused_initialy_stale = Var(within=Integers) model.x_unused_initialy_stale.stale = True model.X_unused = Var(model.s, within=Integers) model.X_unused_initialy_stale = Var(model.s, within=Integers) for i in model.s: model.X_unused[i].stale = False model.X_unused_initialy_stale[i].stale = True model.x = Var(within=IntegerInterval(bounds=(None,None))) model.x.stale = False model.x_initialy_stale = Var(within=Integers) model.x_initialy_stale.stale = True model.X = Var(model.s, within=Integers) model.X_initialy_stale = Var(model.s, within=Integers) for i in model.s: model.X[i].stale = False model.X_initialy_stale[i].stale = True model.obj = Objective(expr= model.x + \ model.x_initialy_stale + \ sum_product(model.X) + \ sum_product(model.X_initialy_stale)) model.c = ConstraintList() model.c.add( model.x >= 1 ) model.c.add( model.x_initialy_stale >= 1 ) model.c.add( model.X[1] >= 0 ) model.c.add( model.X[2] >= 1 ) model.c.add( model.X_initialy_stale[1] >= 0 ) model.c.add( model.X_initialy_stale[2] >= 1 ) # Test that stale flags do not get updated # on inactive blocks (where "inactive blocks" mean blocks # that do NOT follow a path of all active parent blocks # up to the top-level model) flat_model = model.clone() model.b = Block() model.B = Block(model.s) model.b.b = flat_model.clone() model.B[1].b = flat_model.clone() model.B[2].b = flat_model.clone() model.b.deactivate() model.B.deactivate() model.b.b.activate() model.B[1].b.activate() model.B[2].b.deactivate() assert model.b.active is False assert model.B[1].active is False assert model.B[1].active is False assert model.b.b.active is True assert model.B[1].b.active is True assert model.B[2].b.active is False
def _get_block_model(self): model = ConcreteModel() model.s = Set(initialize=[1, 2]) b = Block(concrete=True) b.s = Set(initialize=[1, 2]) b.x = Var() b.X = Var(model.s) model.b1 = b.clone() model.b2 = b.clone() model.b3 = b.clone() model.b4 = b.clone() model.B1 = Block(model.s, rule=lambda _, i: b.clone()) model.B2 = Block(model.s, rule=lambda _, i: b.clone()) model.B3 = Block(model.s, rule=lambda _, i: b.clone()) model.B4 = Block(model.s, rule=lambda _, i: b.clone()) model.FirstStageCost = Expression(expr=0.0) model.SecondStageCost = Expression(expr=0.0) model.obj = Objective(expr=0.0) return model
def makeModel(): """ This is a single-level reformulation of a bilevel model. We project out the dual variables to recover the reformulation in the original space. """ m = ConcreteModel() m.x = Var(bounds=(0, 2)) m.y = Var(domain=NonNegativeReals) m.lamb = Var([1, 2], domain=NonNegativeReals) m.M = Param([1, 2], mutable=True, default=100) m.u = Var([1, 2], domain=Binary) m.primal1 = Constraint(expr=m.x - 0.01 * m.y <= 1) m.dual1 = Constraint(expr=1 - m.lamb[1] - 0.01 * m.lamb[2] == 0) @m.Constraint([1, 2]) def bound_lambdas(m, i): return m.lamb[i] <= m.u[i] * m.M[i] m.bound_y = Constraint(expr=m.y <= 1000 * (1 - m.u[1])) m.dual2 = Constraint(expr=-m.x + 0.01 * m.y + 1 <= (1 - m.u[2]) * 1000) return m
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)
def test_outofbounds(self): m = ConcreteModel() m.x = Var(bounds=(-1, 5), initialize=2) with self.assertRaisesRegex(MCPP_Error, '.*Log with negative values in range'): mc(log(m.x))
# ___________________________________________________________________________ # # Pyomo: Python Optimization Modeling Objects # Copyright 2017 National Technology and Engineering Solutions of Sandia, LLC # Under the terms of Contract DE-NA0003525 with National Technology and # Engineering Solutions of Sandia, LLC, the U.S. Government retains certain # rights in this software. # This software is distributed under the 3-clause BSD License. # ___________________________________________________________________________ from pyomo.core import ConcreteModel, Var, Objective, Constraint, Integers model = ConcreteModel() model.x = Var(bounds=(1,None), within=Integers) model.y = Var(bounds=(1,None), within=Integers) model.o = Objective(expr=model.x-model.x) model.c = Constraint(expr=model.x+model.y >= 3)
def get_mock_model(self): model = ConcreteModel() model.x = Var(within=Binary) model.con = Constraint(expr=model.x >= 1) model.obj = Objective(expr=model.x) return model
def get_model(flag, fixprim, fixdual): model = ConcreteModel() model.obj = Param(default=20) model.n = Param(default=7) model.m = Param(default=7) model.N = RangeSet(1, model.n) model.M = RangeSet(1, model.m) def c_rule(model, j): return 5 if j < 5 else 9.0 / 2 model.c = Param(model.N) def b_rule(model, i): if i == 4: i = 5 elif i == 5: i = 4 return 5 if i < 5 else 7.0 / 2 model.b = Param(model.M) def A_rule(model, i, j): if i == 4: i = 5 elif i == 5: i = 4 return 2 if i == j else 1 model.A = Param(model.M, model.N) model.x = Var(model.N, within=NonNegativeReals) model.y = Var(model.M, within=NonNegativeReals) model.xx = Var([1, 2], model.N, within=NonNegativeReals) model.yy = Var([1, 2], model.M, within=NonNegativeReals) if flag: model.ydiff = Objective(expr=model.yy[2, fixdual] - model.yy[1, fixdual]) def yext_rule(model, k): return sum(model.b[i] * model.yy[k, i] for i in model.M) == model.obj model.yext = Constraint([1, 2]) def dualcons_rule(model, k, j): return sum(model.A[i, j] * model.yy[k, i] for i in model.N) <= model.c[j] model.dualcons = Constraint([1, 2], model.N) else: model.xdiff = Objective(expr=model.xx[2, fixprim] - model.xx[1, fixprim]) def xext_rule(model, k): return sum(model.c[j] * model.xx[k, j] for j in model.N) == model.obj model.xext = Constraint([1, 2]) def primcons_rule(model, k, i): return sum(model.A[i, j] * model.xx[k, j] for j in model.M) >= model.b[i] model.primcons = Constraint([1, 2], model.M) model.create() return model
def test_empty_model(self): """Test with an empty model.""" empty_model = ConcreteModel() model_size = build_model_size_report(empty_model) for obj in model_size.activated.values(): self.assertEqual(obj, 0)
def define_model(**kwds): model = ConcreteModel() model.x1 = Var(bounds=(-5, 4)) # domain variable model.x2 = Var(bounds=(-5, 4)) # domain variable model.x3 = Var(bounds=(-5, 4)) # domain variable model.x4 = Var(bounds=(-5, 4)) # domain variable model.x5 = Var(bounds=(-5, 4)) # domain variable model.x6 = Var(bounds=(-5, 4)) # domain variable model.x7 = Var(bounds=(-5, 4)) # domain variable model.Fx1 = Var() # range variable model.Fx2 = Var() # range variable model.Fx3 = Var() # range variable model.Fx4 = Var() # range variable model.Fx5 = Var() # range variable model.Fx6 = Var() # range variable model.Fx7 = Var() # range variable model.obj = Objective(expr=model.Fx1 + model.Fx2 + model.Fx3 + model.Fx4 + model.Fx5 + model.Fx6 + model.Fx7, sense=kwds.pop('sense', maximize)) model.piecewise1 = Piecewise(model.Fx1, model.x1, pw_pts=DOMAIN_PTS, f_rule=F, **kwds) model.piecewise2 = Piecewise(model.Fx2, model.x2, pw_pts=DOMAIN_PTS, f_rule=F, **kwds) model.piecewise3 = Piecewise(model.Fx3, model.x3, pw_pts=DOMAIN_PTS, f_rule=F, **kwds) model.piecewise4 = Piecewise(model.Fx4, model.x4, pw_pts=DOMAIN_PTS, f_rule=F, **kwds) model.piecewise5 = Piecewise(model.Fx5, model.x5, pw_pts=DOMAIN_PTS, f_rule=F, **kwds) model.piecewise6 = Piecewise(model.Fx6, model.x6, pw_pts=DOMAIN_PTS, f_rule=F, **kwds) model.piecewise7 = Piecewise(model.Fx7, model.x7, pw_pts=DOMAIN_PTS, f_rule=F, **kwds) #Fix the answer for testing purposes model.set_answer_constraint1 = Constraint(expr=model.x1 == -5.0) model.set_answer_constraint2 = Constraint(expr=model.x2 == -3.0) model.set_answer_constraint3 = Constraint(expr=model.x3 == -2.5) model.set_answer_constraint4 = Constraint(expr=model.x4 == -1.5) model.set_answer_constraint5 = Constraint(expr=model.x5 == 2.0) model.set_answer_constraint6 = Constraint(expr=model.x6 == 3.5) model.set_answer_constraint7 = Constraint(expr=model.x7 == 4.0) return model
def _compute_community_repartition( self, quarter: pd.Timestamp, entity_alone_profits: Dict[int, float]) -> Dict[int, pd.DataFrame]: """ Repartition of profit for a quarter. The model solves a first problem where the pareto superior condition ensures the profit in the community is at least as good as the profit alone. Then a second phase is run to attemp to equalize the profits over entities (max margin approach). :param quarter: current quarter start time. :param entity_alone_profits: output of _compute_entity_alone_profits. :return: A dict entity_id -> dataframe with average results over quarter. """ model = ConcreteModel() # Sets self._add_sets(model) # Variables # Primal self._add_grid_vars(model) model.exp_com = Var(model.entities, model.periods, within=NonNegativeReals ) # Power sent to the community over period [kW] model.imp_com = Var( model.entities, model.periods, within=NonNegativeReals ) # Energy imported from the community over period [kW] model.peak_MU = Var( model.entities, within=NonNegativeReals) # Entity peak, community mode [kW] # Profit repartition threshold model.alpha = Var(within=NonNegativeReals) # Dual model.price_com = Var(model.entities, model.periods, within=Reals) model.mu = Var(model.periods, within=Reals) model.phi_peak = Var(within=NonNegativeReals) # Profit model.J_MU = Var(model.entities, within=Reals) # Expressions def profit_expression_rule(m, e): expr = 0 # Energy for p in model.periods: expr += m.exp_grid[e, p] * self._sale_price( e, p, quarter) * self.period_duration_in_hours expr -= m.imp_grid[e, p] * self._purchase_price( e, p, quarter) * self.period_duration_in_hours expr += m.exp_com[e, p] * m.price_com[ e, p] * self.period_duration_in_hours expr -= m.imp_com[e, p] * m.price_com[ e, p] * self.period_duration_in_hours # Storage if self.entities[e].storage is not None: s: Storage = self.entities[e].storage expr += m.exp_com[ e, p] / s.discharge_efficiency * s.usage_fee * self.period_duration_in_hours expr += m.imp_com[ e, p] * s.charge_efficiency * s.usage_fee * self.period_duration_in_hours # Capacity expr -= m.peak_MU[e] * self.community_peak_price return m.J_MU[e] == expr model.profit_MU_def = Constraint(model.entities, rule=profit_expression_rule) # Constraints # Primal def entity_balance_rule(m, e, p): # Fix variables depending on the net position. (Note: If position is 0, fix all to zero.) if is_zero(self._net_position(e, p, quarter)): m.imp_grid[e, p].fix(0) m.imp_com[e, p].fix(0) m.exp_grid[e, p].fix(0) m.exp_com[e, p].fix(0) return Constraint.Skip elif self._net_position(e, p, quarter) > 0: # export position, can fix imports to zero m.imp_grid[e, p].fix(0) m.imp_com[e, p].fix(0) elif self._net_position(e, p, quarter) < 0: # import position, can fix exports to zero m.exp_grid[e, p].fix(0) m.exp_com[e, p].fix(0) return m.exp_grid[e, p] - m.imp_grid[e, p] + m.exp_com[ e, p] - m.imp_com[e, p] == self._net_position(e, p, quarter) model.entity_balance = Constraint(model.entities, model.periods, rule=entity_balance_rule) def com_balance_rule(m, p): return sum(m.exp_com[e, p] - m.imp_com[e, p] for e in model.entities) == 0 model.com_balance = Constraint(model.periods, rule=com_balance_rule) def global_peak_rule(m): """ :param m: Pyomo model :param p: time period :return: constraint on the peak of the community """ lhs = sum(m.imp_grid[e, p] for (e, p) in model.entities * model.periods) / self.n_periods_in_quarter rhs = self.community_past_peak + sum(m.peak_MU[e] for e in model.entities) return lhs <= rhs model.global_peak = Constraint(rule=global_peak_rule) # Dual def dual_exp_grid_rule(m, e, p): """ Dual constraint for the export to grid variable :param m: Pyomo model :param e: entity :param p: time period :return: inequality constraint """ return m.price_com[e, p] >= self._sale_price(e, p, quarter) model.dual_exp_grid = Constraint(model.entities, model.periods, rule=dual_exp_grid_rule) def dual_imp_grid_rule(m, e, p): """ Dual constraint for the import from grid variable :param m: Pyomo model :param e: entity :param p: time period :return: inequality constraint """ expr = -m.price_com[e, p] + m.phi_peak / self.period_duration_in_hours return expr >= -self._purchase_price(e, p, quarter) model.dual_imp_grid = Constraint(model.entities, model.periods, rule=dual_imp_grid_rule) def dual_peak_rule(m): """ Dual constraint for the entity peak variables :param m: Pyomo model :param e: entity :return: inequality constraint """ return -m.phi_peak >= -self.community_peak_price model.dual_peak = Constraint(rule=dual_peak_rule) def dual_exp_com_rule(m, e, p): if self._net_position(e, p, quarter) > 0: # export position return m.price_com[e, p] - m.mu[p] == -self.community_tariff else: return m.price_com[e, p] - m.mu[p] >= -self.community_tariff model.dual_exp_com = Constraint(model.entities, model.periods, rule=dual_exp_com_rule) def dual_imp_com_rule(m, e, p): if self._net_position(e, p, quarter) < 0: # import position return -m.price_com[e, p] + m.mu[p] == -self.community_tariff else: return -m.price_com[e, p] + m.mu[p] >= -self.community_tariff model.dual_imp_com = Constraint(model.entities, model.periods, rule=dual_imp_com_rule) # Strong duality def strong_duality_rule(m): """ Strong duality constraint. :param m: Pyomo model :return: Equality constraint """ dual_obj = 0 for p in model.periods: for e in model.entities: dual_obj += m.price_com[e, p] * self._net_position( e, p, quarter) * self.period_duration_in_hours dual_obj += self.community_past_peak * model.phi_peak primal_obj = 0 for e in model.entities: for p in model.periods: # Energy primal_obj += m.exp_grid[e, p] * self._sale_price( e, p, quarter) * self.period_duration_in_hours primal_obj -= m.imp_grid[e, p] * self._purchase_price( e, p, quarter) * self.period_duration_in_hours primal_obj += ( m.exp_com[e, p] - m.imp_com[e, p] ) * self.community_tariff * self.period_duration_in_hours # Capacity primal_obj -= m.peak_MU[e] * DEFAULT_PEAK_PRICE if self.entities[e].storage is not None: s: Storage = self.entities[e].storage primal_obj += m.exp_com[ e, p] / s.discharge_efficiency * s.usage_fee * self.period_duration_in_hours primal_obj += m.imp_com[ e, p] * s.charge_efficiency * s.usage_fee * self.period_duration_in_hours return dual_obj == primal_obj model.strong_duality = Constraint(rule=strong_duality_rule) # Upper level def pareto_superior_rule(m, e): # TODO return (m.J_MU[e] - entity_alone_profits[e]) / abs(entity_alone_profits[e]) >= m.alpha return m.J_MU[e] >= entity_alone_profits[e] def pareto_superior_rule_phase_2(m, e): if not is_zero(entity_alone_profits[e]): return (m.J_MU[e] - entity_alone_profits[e]) / abs( entity_alone_profits[e]) >= m.alpha else: return m.J_MU[e] >= entity_alone_profits[e] model.pareto_superior_cdt = Constraint(model.entities, rule=pareto_superior_rule) model.objective = Objective(expr=sum( (model.J_MU[e]) for e in model.entities), sense=maximize) self._solve(model) # PHASE 2 -> max margin profit repartition def community_minimum_profit_rule(m): return sum((model.J_MU[e]) for e in model.entities) >= model.objective.expr model.community_minimum_profit = Constraint( rule=community_minimum_profit_rule) model.pareto_superior_cdt.deactivate() model.pareto_superior_cdt_phase2 = Constraint( model.entities, rule=pareto_superior_rule_phase_2) model.objective.deactivate() model.objective_phase2 = Objective(expr=model.alpha, sense=maximize) self._solve(model) print("ALPHA = %.2f %%" % (model.alpha.value * 100)) # Average results over quarter quarter_results = {e: None for e in self.entities} tmp_results = {e: [] for e in model.entities} for p in model.periods: for e in model.entities: tmp_results[e].append([ quarter + timedelta(minutes=p - 1), model.price_com[e, p].value, model.exp_grid[e, p].value, model.imp_grid[e, p].value, model.exp_com[e, p].value, model.imp_com[e, p].value ]) detailed_results = { e: pd.DataFrame(v, columns=[ "DateTime", "price_com", "exp_grid", "imp_grid", "exp_com", "imp_com" ]) for (e, v) in tmp_results.items() } for e in self.entities: quarter_results[e] = detailed_results[e].mean() num = (detailed_results[e]["exp_com"] - detailed_results[e]["imp_com"] ) * detailed_results[e]["price_com"] num = num.sum() den = (quarter_results[e]["exp_com"] - quarter_results[e]["imp_com"]) if not (is_zero(den)): quarter_results[e][ "price_com"] = num / den / self.n_periods_in_quarter quarter_results[e] = quarter_results[e].round(decimals=5) # Update the past_peak of the community self.community_past_peak = max( self.community_past_peak, sum(model.peak_MU[e].value for e in model.entities)) # print("com peak: ", self.community_past_peak) # Store entitiy profits for verification for e in model.entities: self.comparison_df[e].append( [quarter, entity_alone_profits[e], model.J_MU[e].value]) return quarter_results
def run_pyomo(options=Options(), parser=None): data = Options(options=options) if options.model.filename == '': parser.print_help() return Container() try: pyomo.scripting.util.setup_environment(data) pyomo.scripting.util.apply_preprocessing(data, parser=parser) except: # TBD: I should be able to call this function in the case of # an exception to perform cleanup. However, as it stands # calling finalize with its default keyword value for # model(=None) results in an a different error related to # task port values. Not sure how to interpret that. pyomo.scripting.util.finalize(data, model=ConcreteModel(), instance=None, results=None) raise else: if data.error: # TBD: I should be able to call this function in the case of # an exception to perform cleanup. However, as it stands # calling finalize with its default keyword value for # model(=None) results in an a different error related to # task port values. Not sure how to interpret that. pyomo.scripting.util.finalize(data, model=ConcreteModel(), instance=None, results=None) return Container() #pragma:nocover try: model_data = pyomo.scripting.util.create_model(data) except: # TBD: I should be able to call this function in the case of # an exception to perform cleanup. However, as it stands # calling finalize with its default keyword value for # model(=None) results in an a different error related to # task port values. Not sure how to interpret that. pyomo.scripting.util.finalize(data, model=ConcreteModel(), instance=None, results=None) raise else: if (((not options.runtime.logging == 'debug') and \ options.model.save_file) or \ options.runtime.only_instance): pyomo.scripting.util.finalize(data, model=model_data.model, instance=model_data.instance, results=None) return Container(instance=model_data.instance) try: opt_data = pyomo.scripting.util.apply_optimizer( data, instance=model_data.instance) pyomo.scripting.util.process_results(data, instance=model_data.instance, results=opt_data.results, opt=opt_data.opt) pyomo.scripting.util.apply_postprocessing(data, instance=model_data.instance, results=opt_data.results) except: # TBD: I should be able to call this function in the case of # an exception to perform cleanup. However, as it stands # calling finalize with its default keyword value for # model(=None) results in an a different error related to # task port values. Not sure how to interpret that. pyomo.scripting.util.finalize(data, model=ConcreteModel(), instance=None, results=None) raise else: pyomo.scripting.util.finalize(data, model=model_data.model, instance=model_data.instance, results=opt_data.results) return Container(options=options, instance=model_data.instance, results=opt_data.results, local=opt_data.local)
def define_model(**kwds): model = ConcreteModel() model.x = Var(INDEX_SET, bounds=(0, 6)) # domain variable model.Fx = Var(INDEX_SET) # range variable model.p = Param(INDEX_SET, initialize=1.0, mutable=True) model.obj = Objective(expr=sum_product(model.Fx), sense=kwds.pop('sense', maximize)) model.piecewise = Piecewise(INDEX_SET, model.Fx, model.x, pw_pts=DOMAIN_PTS, f_rule=F, **kwds) #Fix the answer for testing purposes model.set_answer_constraint1 = Constraint(expr=model.x[1] == 0.0) model.set_answer_constraint2 = Constraint(expr=model.x[2] == 3.0) model.set_answer_constraint3 = Constraint(expr=model.x[3] == 5.5) model.set_answer_constraint4 = Constraint(expr=model.x[4] == 6.0) return model
# ___________________________________________________________________________ # # Pyomo: Python Optimization Modeling Objects # Copyright 2017 National Technology and Engineering Solutions of Sandia, LLC # Under the terms of Contract DE-NA0003525 with National Technology and # Engineering Solutions of Sandia, LLC, the U.S. Government retains certain # rights in this software. # This software is distributed under the 3-clause BSD License. # ___________________________________________________________________________ from pyomo.core import ConcreteModel, Var, Objective, Constraint, maximize model = ConcreteModel() model.x = Var(bounds=(1,None)) model.y = Var(bounds=(1,None)) model.o = Objective(expr=model.x-model.x, sense=maximize) model.c = Constraint(expr=model.x+model.y >= 3)
def test_synchronize_value(self): m = ConcreteModel() m.iv = AutoLinkedBooleanVar() m.biv = AutoLinkedBinaryVar(m.iv) m.iv.associate_binary_var(m.biv) self.assertIsNone(m.iv.value) self.assertIsNone(m.biv.value) # Note: test the following twice to exercise the "no update" # situation, and to ensure no infinite loops m.iv = True self.assertEqual(m.iv.value, True) self.assertEqual(m.biv.value, 1) m.iv = True self.assertEqual(m.iv.value, True) self.assertEqual(m.biv.value, 1) m.iv = False self.assertEqual(m.iv.value, False) self.assertEqual(m.biv.value, 0) m.iv = False self.assertEqual(m.iv.value, False) self.assertEqual(m.biv.value, 0) m.iv = None self.assertEqual(m.iv.value, None) self.assertEqual(m.biv.value, None) m.iv = None self.assertEqual(m.iv.value, None) self.assertEqual(m.biv.value, None) m.biv = 1 self.assertEqual(m.iv.value, True) self.assertEqual(m.biv.value, 1) m.biv = 1 self.assertEqual(m.iv.value, True) self.assertEqual(m.biv.value, 1) eps = AutoLinkedBinaryVar.INTEGER_TOLERANCE / 10 m.biv = None self.assertEqual(m.iv.value, None) self.assertEqual(m.biv.value, None) m.biv = None self.assertEqual(m.iv.value, None) self.assertEqual(m.biv.value, None) m.biv.value = 1 - eps self.assertEqual(m.iv.value, True) self.assertEqual(m.biv.value, 1 - eps) m.biv.value = 1 - eps self.assertEqual(m.iv.value, True) self.assertEqual(m.biv.value, 1 - eps) m.biv.value = eps self.assertEqual(m.iv.value, False) self.assertEqual(m.biv.value, eps) m.biv.value = eps self.assertEqual(m.iv.value, False) self.assertEqual(m.biv.value, eps) m.biv.value = 0.5 self.assertEqual(m.iv.value, None) self.assertEqual(m.biv.value, 0.5) m.biv.value = 0.5 self.assertEqual(m.iv.value, None) self.assertEqual(m.biv.value, 0.5)
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[5] self.assertEqual(value(cons.lower), 0) self.assertIs(cons.body, m.y) cons = constraints[6] self.assertEqual(value(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[2] self.assertEqual(value(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[4] 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(value(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(value(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[2].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(6))
def test_cast_to_binary(self): m = ConcreteModel() m.iv = AutoLinkedBooleanVar() m.biv = AutoLinkedBinaryVar(m.iv) m.iv.associate_binary_var(m.biv) m.biv = 1 deprecation_msg = ( "Implicit conversion of the Boolean indicator_var 'iv'") out = StringIO() with LoggingIntercept(out): self.assertEqual(m.iv.lb, 0) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): self.assertEqual(m.iv.ub, 1) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): self.assertEqual(m.iv.bounds, (0, 1)) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): m.iv.lb = 1 self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): m.iv.ub = 1 self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): m.iv.bounds = (1, 1) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): m.iv.setlb(1) self.assertEqual(m.biv.lb, 1) m.biv.setlb(0) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): m.iv.setub(0) self.assertEqual(m.biv.ub, 0) m.biv.setub(1) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): self.assertIs(abs(m.iv).args[0], m.biv) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): with self.assertRaisesRegex( PyomoException, r"Cannot convert non-constant Pyomo " r"numeric value \(biv\) to bool"): bool(m.iv) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): with self.assertRaisesRegex( TypeError, r"Implicit conversion of Pyomo numeric " r"value \(biv\) to float"): float(m.iv) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): with self.assertRaisesRegex( TypeError, r"Implicit conversion of Pyomo numeric " r"value \(biv\) to int"): int(m.iv) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): self.assertIs((-m.iv).args[1], m.biv) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): self.assertIs(+m.iv, m.biv) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): self.assertTrue(m.iv.has_lb()) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): self.assertTrue(m.iv.has_ub()) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): self.assertTrue(m.iv.is_binary()) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): self.assertFalse(m.iv.is_continuous()) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): self.assertTrue(m.iv.is_integer()) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): self.assertEqual(m.iv.polynomial_degree(), 1) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): self.assertIs((m.iv == 0).args[0], m.biv) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): self.assertIs((m.iv <= 0).args[0], m.biv) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): self.assertIs((m.iv >= 0).args[1], m.biv) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): self.assertIs((m.iv < 0).args[0], m.biv) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): self.assertIs((m.iv > 0).args[1], m.biv) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): self.assertIs((m.iv + 1).args[0], m.biv) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): self.assertIs((m.iv - 1).args[0], m.biv) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): self.assertIs((m.iv * 2).args[1], m.biv) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): self.assertIs((m.iv / 2).args[1], m.biv) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): self.assertIs((m.iv**2).args[0], m.biv) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): self.assertIs((1 + m.iv).args[1], m.biv) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): self.assertIs((1 - m.iv).args[1].args[1], m.biv) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): self.assertIs((2 * m.iv).args[1], m.biv) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): self.assertIs((2 / m.iv).args[1], m.biv) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): self.assertIs((2**m.iv).args[1], m.biv) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): a = m.iv a += 1 self.assertIs(a.args[0], m.biv) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): a = m.iv a -= 1 self.assertIs(a.args[0], m.biv) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): a = m.iv a *= 2 self.assertIs(a.args[1], m.biv) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): a = m.iv a /= 2 self.assertIs(a.args[1], m.biv) self.assertIn(deprecation_msg, out.getvalue()) out = StringIO() with LoggingIntercept(out): a = m.iv a **= 2 self.assertIs(a.args[0], m.biv) self.assertIn(deprecation_msg, out.getvalue())
def device_scheduler( device_constraints: List[DataFrame], ems_constraints: DataFrame, commitment_quantities: List[Series], commitment_downwards_deviation_price: Union[List[Series], List[float]], commitment_upwards_deviation_price: Union[List[Series], List[float]], ) -> Tuple[List[Series], List[float]]: """Schedule devices given constraints on a device and EMS level, and given a list of commitments by the EMS. The commitments are assumed to be with regards to the flow of energy to the device (positive for consumption, negative for production). The solver minimises the costs of deviating from the commitments, and returns the costs per commitment. Device constraints are on a device level. Handled constraints (listed by column name): max: maximum stock assuming an initial stock of zero (e.g. in MWh or boxes) min: minimum stock assuming an initial stock of zero derivative max: maximum flow (e.g. in MW or boxes/h) derivative min: minimum flow derivative equals: exact amount of flow EMS constraints are on an EMS level. Handled constraints (listed by column name): derivative max: maximum flow derivative min: minimum flow Commitments are on an EMS level. Parameter explanations: commitment_quantities: amounts of flow specified in commitments (both previously ordered and newly requested) - e.g. in MW or boxes/h commitment_downwards_deviation_price: penalty for downwards deviations of the flow - e.g. in EUR/MW or EUR/(boxes/h) - either a single value (same value for each flow value) or a Series (different value for each flow value) commitment_upwards_deviation_price: penalty for upwards deviations of the flow All Series and DataFrames should have the same resolution. For now we pass in the various constraints and prices as separate variables, from which we make a MultiIndex DataFrame. Later we could pass in a MultiIndex DataFrame directly. """ # If the EMS has no devices, don't bother if len(device_constraints) == 0: return [], [] * len(commitment_quantities) # Check if commitments have the same time window and resolution as the constraints start = device_constraints[0].index.values[0] resolution = to_timedelta(device_constraints[0].index.freq) end = device_constraints[0].index.values[-1] + resolution if len(commitment_quantities) != 0: start_c = commitment_quantities[0].index.values[0] resolution_c = to_timedelta(commitment_quantities[0].index.freq) end_c = commitment_quantities[0].index.values[-1] + resolution if not (start_c == start and end_c == end): raise Exception( "Not implemented for different time windows.\n(%s,%s)\n(%s,%s)" % (start, end, start_c, end_c)) if resolution_c != resolution: raise Exception( "Not implemented for different resolutions.\n%s\n%s" % (resolution, resolution_c)) # Turn prices per commitment into prices per commitment flow if len(commitment_downwards_deviation_price) != 0: if all(not isinstance(price, Series) for price in commitment_downwards_deviation_price): commitment_downwards_deviation_price = [ initialize_series(price, start, end, resolution) for price in commitment_downwards_deviation_price ] if len(commitment_upwards_deviation_price) != 0: if all(not isinstance(price, Series) for price in commitment_upwards_deviation_price): commitment_upwards_deviation_price = [ initialize_series(price, start, end, resolution) for price in commitment_upwards_deviation_price ] # Determine appropriate overall bounds for power and price min_down_price = min(min(p) for p in commitment_downwards_deviation_price) max_down_price = max(max(p) for p in commitment_downwards_deviation_price) min_up_price = min(min(p) for p in commitment_upwards_deviation_price) max_up_price = max(max(p) for p in commitment_upwards_deviation_price) overall_min_price = min(min_down_price, min_up_price) overall_max_price = max(max_down_price, max_up_price) overall_min_power = min(ems_constraints["derivative min"]) overall_max_power = max(ems_constraints["derivative max"]) model = ConcreteModel() # Add indices for devices (d), datetimes (j) and commitments (c) model.d = RangeSet(0, len(device_constraints) - 1, doc="Set of devices") model.j = RangeSet(0, len(device_constraints[0].index.values) - 1, doc="Set of datetimes") model.c = RangeSet(0, len(commitment_quantities) - 1, doc="Set of commitments") # Add parameters def commitment_quantity_select(m, c, j): v = commitment_quantities[c].iloc[j] if isnan(v): # Discount this nan commitment by setting the prices to 0 commitment_downwards_deviation_price[c].iloc[j] = 0 commitment_upwards_deviation_price[c].iloc[j] = 0 return 0 else: return v def price_down_select(m, c, j): return commitment_downwards_deviation_price[c].iloc[j] def price_up_select(m, c, j): return commitment_upwards_deviation_price[c].iloc[j] def device_max_select(m, d, j): v = device_constraints[d]["max"].iloc[j] if isnan(v): return infinity else: return v def device_min_select(m, d, j): v = device_constraints[d]["min"].iloc[j] if isnan(v): return -infinity else: return v def device_derivative_max_select(m, d, j): max_v = device_constraints[d]["derivative max"].iloc[j] equal_v = device_constraints[d]["derivative equals"].iloc[j] if isnan(max_v) and isnan(equal_v): return infinity else: return nanmin([max_v]) def device_derivative_min_select(m, d, j): min_v = device_constraints[d]["derivative min"].iloc[j] equal_v = device_constraints[d]["derivative equals"].iloc[j] if isnan(min_v) and isnan(equal_v): return -infinity else: return nanmax([min_v]) def device_derivative_equal_select(m, d, j): min_v = device_constraints[d]["derivative min"].iloc[j] equal_v = device_constraints[d]["derivative equals"].iloc[j] if isnan(equal_v): return 0 else: return nanmax([equal_v]) def ems_derivative_max_select(m, j): v = ems_constraints["derivative max"].iloc[j] if isnan(v): return infinity else: return v def ems_derivative_min_select(m, j): v = ems_constraints["derivative min"].iloc[j] if isnan(v): return -infinity else: return v model.commitment_quantity = Param(model.c, model.j, initialize=commitment_quantity_select) model.up_price = Param(model.c, model.j, initialize=price_up_select) model.down_price = Param(model.c, model.j, initialize=price_down_select) model.device_max = Param(model.d, model.j, initialize=device_max_select) model.device_min = Param(model.d, model.j, initialize=device_min_select) model.device_derivative_max = Param( model.d, model.j, initialize=device_derivative_max_select) model.device_derivative_min = Param( model.d, model.j, initialize=device_derivative_min_select) model.device_derivative_equal = Param( model.d, model.j, initialize=device_derivative_equal_select) model.ems_derivative_max = Param(model.j, initialize=ems_derivative_max_select) model.ems_derivative_min = Param(model.j, initialize=ems_derivative_min_select) # Add variables model.power = Var( model.d, model.j, domain=Reals, initialize=0, bounds=(overall_min_power, overall_max_power), ) # Add constraints as a tuple of (lower bound, value, upper bound) def device_bounds(m, d, j): return ( m.device_min[d, j], sum(m.power[d, k] for k in range(0, j + 1)), m.device_max[d, j], ) def device_derivative_bounds(m, d, j): return ( m.device_derivative_min[d, j], m.power[d, j] - m.device_derivative_equal[d, j], m.device_derivative_max[d, j], ) def ems_derivative_bounds(m, j): return m.ems_derivative_min[j], sum( m.power[:, j]), m.ems_derivative_max[j] model.device_energy_bounds = Constraint(model.d, model.j, rule=device_bounds) model.device_power_bounds = Constraint(model.d, model.j, rule=device_derivative_bounds) model.ems_power_bounds = Constraint(model.j, rule=ems_derivative_bounds) # Add logical disjunction for deviations model.price = Var(model.c, model.j, initialize=0, bounds=(overall_min_price, overall_max_price)) def up_linker(b, c, d, j): # print("In up linker") m = b.model() ems_power_in_j = sum(m.power[d, j] for d in m.d) ems_power_deviation = ems_power_in_j - m.commitment_quantity[c, j] # try: # print(value(ems_power_deviation)) # except: # pass b.linker = Constraint(expr=m.price[c, j] == m.up_price[c, j]) b.constr = Constraint(expr=ems_power_deviation >= 0) b.BigM = Suffix(direction=Suffix.LOCAL) b.BigM[b.linker] = 10e5 return def down_linker(b, c, d, j): # print("In down linker") m = b.model() ems_power_in_j = sum(m.power[d, j] for d in m.d) ems_power_deviation = ems_power_in_j - m.commitment_quantity[c, j] # try: # print(value(ems_power_deviation)) # except: # pass b.linker = Constraint(expr=m.price[c, j] == m.down_price[c, j]) b.constr = Constraint(expr=ems_power_deviation <= 0) b.BigM = Suffix(direction=Suffix.LOCAL) b.BigM[b.linker] = 10e5 return # def zero_linker(b, c, d, j): # #print("In down linker") # m = b.model() # ems_power_in_j = sum(m.power[d, j] for d in m.d) # ems_power_deviation = ems_power_in_j - m.commitment_quantity[c, j] # #try: # #print(value(ems_power_deviation)) # #except: # #pass # b.linker = Constraint(expr=m.price[c, j] == 0) # b.constr = Constraint(expr=ems_power_deviation == 0) # #b.BigM = Suffix(direction=Suffix.LOCAL) # #b.BigM[b.linker] = 10e10 # return model.up_deviation = Disjunct(model.c, model.d, model.j, rule=up_linker) model.down_deviation = Disjunct(model.c, model.d, model.j, rule=down_linker) # model.zero_deviation = Disjunct(model.c, model.d, model.j, rule=zero_linker) def bind_prices(m, c, d, j): return [ model.up_deviation[c, d, j], model.down_deviation[c, d, j], # model.zero_deviation[c, d, j] ] model.up_or_down_deviation = Disjunction(model.c, model.d, model.j, rule=bind_prices, xor=True) # Add objective def cost_function(m): costs = 0 for j in m.j: for c in m.c: ems_power_in_j = sum(m.power[d, j] for d in m.d) ems_power_deviation = ems_power_in_j - m.commitment_quantity[c, j] costs += ems_power_deviation * m.price[c, j] return costs model.costs = Objective(rule=cost_function, sense=minimize) # def xfrm(m): # TransformationFactory('gdp.chull').apply_to(m) # model.xfrm = BuildAction(rule=xfrm) # Transform and solve xfrm = TransformationFactory("gdp.bigm") xfrm.apply_to(model) solver = SolverFactory( "cplex", executable="D:/CPLEX/Studio/cplex/bin/x64_win64/cplex") # solver.options['CPXchgprobtype'] = "CPXPROB_QP" # solver.options["solver"] = "CPXqpopt" solver.options["qpmethod"] = 1 solver.options["optimalitytarget"] = 3 # solver.options["acceptable_constr_viol_tol"] = 10 # solver.options['acceptable_tol'] = 1 # solver.options['acceptable_dual_inf_tol'] = 10 # solver.options['acceptable_compl_inf_tol'] = 10 results = solver.solve(model, tee=False) planned_costs = value(model.costs) planned_power_per_device = [] for d in model.d: planned_device_power = [ round(model.power[d, j].value, 3) for j in model.j ] planned_power_per_device.append( initialize_series(planned_device_power, start=start, end=end, resolution=resolution)) # model.display() # results.pprint() # model.down_deviation.pprint() # model.up_deviation.pprint() # model.power.pprint() # print(planned_power_per_device) # input() # Redo the cost calculation, because before the solver actually approximated the prices. def redo_cost_calculation(m): commitments_costs = [] for c in m.c: commitment_cost = 0 for j in m.j: ems_power_in_j = sum(m.power[d, j] for d in m.d) ems_power_deviation = ems_power_in_j - m.commitment_quantity[c, j] if value(ems_power_deviation) >= 0: commitment_cost += round( value(ems_power_deviation * m.up_price[c, j]), 3) else: commitment_cost += round( value(ems_power_deviation * m.down_price[c, j]), 3) commitments_costs.append(commitment_cost) return commitments_costs planned_costs_per_commitment = redo_cost_calculation(model) # print(planned_costs_per_commitment) return planned_power_per_device, planned_costs_per_commitment
def test_construct_implicit_disjuncts(self): m = ConcreteModel() m.x = Var() m.y = Var() m.d = Disjunction(expr=[m.x <= 0, m.y >= 1]) self.assertEqual(len(m.component_map(Disjunction)), 1) self.assertEqual(len(m.component_map(Disjunct)), 1) implicit_disjuncts = list(m.component_map(Disjunct).keys()) self.assertEqual(implicit_disjuncts[0][:2], "d_") disjuncts = m.d.disjuncts self.assertEqual(len(disjuncts), 2) self.assertIs(disjuncts[0].parent_block(), m) self.assertIs(disjuncts[0].constraint[1].body, m.x) self.assertIs(disjuncts[1].parent_block(), m) self.assertIs(disjuncts[1].constraint[1].body, m.y) # Test that the implicit disjuncts get a unique name m.add_component('e_disjuncts', Var()) m.e = Disjunction(expr=[m.y <= 0, m.x >= 1]) self.assertEqual(len(m.component_map(Disjunction)), 2) self.assertEqual(len(m.component_map(Disjunct)), 2) implicit_disjuncts = list(m.component_map(Disjunct).keys()) self.assertEqual(implicit_disjuncts[1][:12], "e_disjuncts_") disjuncts = m.e.disjuncts self.assertEqual(len(disjuncts), 2) self.assertIs(disjuncts[0].parent_block(), m) self.assertIs(disjuncts[0].constraint[1].body, m.y) self.assertIs(disjuncts[1].parent_block(), m) self.assertIs(disjuncts[1].constraint[1].body, m.x) self.assertEqual(len(disjuncts[0].parent_component().name), 13) self.assertEqual(disjuncts[0].name[:12], "e_disjuncts_") # Test that the implicit disjuncts can be lists/tuples/generators def _gen(): yield m.y <= 4 yield m.x >= 5 m.f = Disjunction(expr=[[m.y <= 0, m.x >= 1], ( m.y <= 2, m.x >= 3), _gen()]) self.assertEqual(len(m.component_map(Disjunction)), 3) self.assertEqual(len(m.component_map(Disjunct)), 3) implicit_disjuncts = list(m.component_map(Disjunct).keys()) self.assertEqual(implicit_disjuncts[2][:12], "f_disjuncts") disjuncts = m.f.disjuncts self.assertEqual(len(disjuncts), 3) self.assertIs(disjuncts[0].parent_block(), m) self.assertIs(disjuncts[0].constraint[1].body, m.y) self.assertEqual(disjuncts[0].constraint[1].upper, 0) self.assertIs(disjuncts[0].constraint[2].body, m.x) self.assertEqual(disjuncts[0].constraint[2].lower, 1) self.assertIs(disjuncts[1].parent_block(), m) self.assertIs(disjuncts[1].constraint[1].body, m.y) self.assertEqual(disjuncts[1].constraint[1].upper, 2) self.assertIs(disjuncts[1].constraint[2].body, m.x) self.assertEqual(disjuncts[1].constraint[2].lower, 3) self.assertIs(disjuncts[2].parent_block(), m) self.assertIs(disjuncts[2].constraint[1].body, m.y) self.assertEqual(disjuncts[2].constraint[1].upper, 4) self.assertIs(disjuncts[2].constraint[2].body, m.x) self.assertEqual(disjuncts[2].constraint[2].lower, 5) self.assertEqual(len(disjuncts[0].parent_component().name), 11) self.assertEqual(disjuncts[0].name, "f_disjuncts[0]")
def criticalityCheck(self, x, y, z, rom_params, worstcase=False, M=[0.0]): model = self.model self.setVarValue(x=x, y=y, z=z) self.setBound(x, y, z, 1e10) self.deactiveExtraConObj() self.activateRomCons(x, rom_params) optGJH = SolverFactory('contrib.gjh') optGJH.solve(model, tee=False, symbolic_solver_labels=True) g, J, varlist, conlist = model._gjh_info l = ConcreteModel() l.v = Var(varlist, domain=Reals) for i in varlist: #dummy = model.find_component(i) l.v[i] = 0.0 l.v[i].setlb(-1.0) l.v[i].setub(1.0) if worstcase: if M.all() == 0.0: print( 'WARNING: worstcase criticality was requested but Jacobian error bound is zero' ) l.t = Var(range(0, self.ly), domain=Reals) for i in range(0, self.ly): l.t[i].setlb(-M[i]) l.t[i].setub(M[i]) def linConMaker(l, i): # i should be range(len(conlist) - 1) # because last element of conlist is the objective con_i = model.find_component(conlist[i]) isEquality = con_i.equality isROM = False if conlist[i][:7] == '.' + self.TRF.name + '.rom': isROM = True romIndex = int(filter(str.isdigit, conlist[i])) # This is very inefficient # Fix this later if these problems get big # This is the ith row of J times v Jv = sum(x[2] * l.v[varlist[x[1]]] for x in J if x[0] == i) if isEquality: if worstcase and isROM: return Jv + l.t[romIndex] == 0 else: return Jv == 0 else: lo = con_i.lower up = con_i.upper if lo is not None: level = lo.value - con_i.lslack() if up is not None: return (lo.value <= level + Jv <= up.value) else: return (lo.value <= level + Jv) elif up is not None: level = up.value - con_i.uslack() return (level + Jv <= up.value) else: raise Exception( "This constraint seems to be neither equality or inequality: " + conlist(i)) l.lincons = Constraint(range(len(conlist) - 1), rule=linConMaker) l.obj = Objective(expr=sum(x[1] * l.v[varlist[x[0]]] for x in g)) # Calculate gradient norm for scaling purposes gfnorm = sqrt(sum(x[1]**2 for x in g)) opt = SolverFactory(self.config.solver) opt.options.update(self.config.solver_options) #opt.options['halt_on_ampl_error'] = 'yes' #opt.options['max_iter'] = 5000 results = opt.solve(l, keepfiles=self.keepfiles, tee=self.stream_solver) if ((results.solver.status == SolverStatus.ok) and (results.solver.termination_condition == TerminationCondition.optimal)): l.solutions.load_from(results) if gfnorm > 1: return True, abs(l.obj()) / gfnorm else: return True, abs(l.obj()) else: print("Waring: Crticality check fails with solver Status: " + str(results.solver.status)) print("And Termination Conditions: " + str(results.solver.termination_condition)) return False, infinity
def test_abs(self): m = ConcreteModel() m.x = Var(bounds=(-1, 1), initialize=0) mc_expr = mc(abs((m.x))) self.assertEqual(mc_expr.lower(), 0) self.assertEqual(mc_expr.upper(), 1)
def test_multiindexedvar_singlewildcardtemplate(self): st_model = CreateConcreteTwoStageScenarioTreeModel(1) st_model.StageVariables['Stage1'].add("x[*,* ]") st_model.StageDerivedVariables['Stage1'].add("y[ *,*]") st_model.NodeVariables['RootNode'].add("z[*,*]") st_model.NodeDerivedVariables['RootNode'].add("q[ * , * ]") st_model.StageCost['Stage1'] = "FirstStageCost" st_model.StageCost['Stage2'] = "SecondStageCost" scenario_tree = ScenarioTree(scenariotreeinstance=st_model) self.assertEqual(len(scenario_tree.stages), 2) self.assertEqual(len(scenario_tree.nodes), 2) self.assertEqual(len(scenario_tree.scenarios), 1) model = ConcreteModel() model.s = Set(initialize=[(1, 'a'), (2, 'b'), (3, 'c')]) model.x = Var(model.s) model.y = Var(model.s) model.z = Var(model.s) model.q = Var(model.s) model.FirstStageCost = Expression(expr=0.0) model.SecondStageCost = Expression(expr=0.0) model.obj = Objective(expr=0.0) root = scenario_tree.findRootNode() root_nonant_names = _get_names(_get_nonant_list(model, root)) root_derived_nonant_names = _get_names( _get_derived_nonant_list(model, root)) assert len(root_nonant_names) == 6 assert len(root_derived_nonant_names) == 6 for name in ("x", "z"): indexed_var = model.find_component(name) for index in model.s: var = indexed_var[index] assert var.name in root_nonant_names for name in ("y", "q"): indexed_var = model.find_component(name) for index in model.s: var = indexed_var[index] assert var.name in root_derived_nonant_names
def test_deactivate(self): m = ConcreteModel() m.x = Var() m.d1 = Disjunct() m.d1.constraint = Constraint(expr=m.x <= 0) m.d = Disjunction(expr=[m.d1, m.x >= 1, m.x >= 5]) d2 = m.d.disjuncts[1].parent_component() self.assertEqual(len(m.component_map(Disjunction)), 1) self.assertEqual(len(m.component_map(Disjunct)), 2) self.assertIsNot(m.d1, d2) self.assertTrue(m.d1.active) self.assertTrue(d2.active) self.assertTrue(m.d.disjuncts[0].active) self.assertTrue(m.d.disjuncts[1].active) self.assertTrue(m.d.disjuncts[2].active) self.assertFalse(m.d.disjuncts[0].indicator_var.is_fixed()) self.assertFalse(m.d.disjuncts[1].indicator_var.is_fixed()) self.assertFalse(m.d.disjuncts[2].indicator_var.is_fixed()) m.d.disjuncts[0].deactivate() self.assertFalse(m.d1.active) self.assertTrue(d2.active) self.assertFalse(m.d.disjuncts[0].active) self.assertTrue(m.d.disjuncts[1].active) self.assertTrue(m.d.disjuncts[2].active) self.assertTrue(m.d.disjuncts[0].indicator_var.is_fixed()) self.assertFalse(m.d.disjuncts[1].indicator_var.is_fixed()) self.assertFalse(m.d.disjuncts[2].indicator_var.is_fixed()) m.d.disjuncts[1].deactivate() self.assertFalse(m.d1.active) self.assertTrue(d2.active) self.assertFalse(m.d.disjuncts[0].active) self.assertFalse(m.d.disjuncts[1].active) self.assertTrue(m.d.disjuncts[2].active) self.assertTrue(m.d.disjuncts[0].indicator_var.is_fixed()) self.assertTrue(m.d.disjuncts[1].indicator_var.is_fixed()) self.assertFalse(m.d.disjuncts[2].indicator_var.is_fixed()) d2.deactivate() self.assertFalse(m.d1.active) self.assertFalse(d2.active) self.assertFalse(m.d.disjuncts[0].active) self.assertFalse(m.d.disjuncts[1].active) self.assertFalse(m.d.disjuncts[2].active) self.assertTrue(m.d.disjuncts[0].indicator_var.is_fixed()) self.assertTrue(m.d.disjuncts[1].indicator_var.is_fixed()) self.assertTrue(m.d.disjuncts[2].indicator_var.is_fixed()) m.d.disjuncts[2].activate() self.assertFalse(m.d1.active) self.assertTrue(d2.active) self.assertFalse(m.d.disjuncts[0].active) self.assertFalse(m.d.disjuncts[1].active) self.assertTrue(m.d.disjuncts[2].active) self.assertTrue(m.d.disjuncts[0].indicator_var.is_fixed()) self.assertTrue(m.d.disjuncts[1].indicator_var.is_fixed()) self.assertFalse(m.d.disjuncts[2].indicator_var.is_fixed()) d2.activate() self.assertFalse(m.d1.active) self.assertTrue(d2.active) self.assertFalse(m.d.disjuncts[0].active) self.assertTrue(m.d.disjuncts[1].active) self.assertTrue(m.d.disjuncts[2].active) self.assertTrue(m.d.disjuncts[0].indicator_var.is_fixed()) self.assertFalse(m.d.disjuncts[1].indicator_var.is_fixed()) self.assertFalse(m.d.disjuncts[2].indicator_var.is_fixed()) m.d1.activate() self.assertTrue(m.d1.active) self.assertTrue(d2.active) self.assertTrue(m.d.disjuncts[0].active) self.assertTrue(m.d.disjuncts[1].active) self.assertTrue(m.d.disjuncts[2].active) self.assertFalse(m.d.disjuncts[0].indicator_var.is_fixed()) self.assertFalse(m.d.disjuncts[1].indicator_var.is_fixed()) self.assertFalse(m.d.disjuncts[2].indicator_var.is_fixed())
def _generate_model(self): self.model = ConcreteModel() model = self.model model._name = self.description model.s = RangeSet(1, 12) model.x = Var(model.s) model.x[1].setlb(-1) model.x[1].setub(1) model.x[2].setlb(-1) model.x[2].setub(1) model.obj = Objective(expr=sum(model.x[i] * ((-1)**(i + 1)) for i in model.x.index_set())) model.c = ConstraintList() # to make the variable used in the constraint match the name model.c.add(Constraint.Skip) model.c.add(Constraint.Skip) model.c.add(model.x[3] >= -1.) model.c.add(model.x[4] <= 1.) model.c.add(model.x[5] == -1.) model.c.add(model.x[6] == -1.) model.c.add(model.x[7] == 1.) model.c.add(model.x[8] == 1.) model.c.add((-1., model.x[9], -1.)) model.c.add((-1., model.x[10], -1.)) model.c.add((1., model.x[11], 1.)) model.c.add((1., model.x[12], 1.)) cdata = model.c.add((0, 1, 3)) assert cdata.lower == 0 assert cdata.upper == 3 assert cdata.body() == 1 assert not cdata.equality cdata = model.c.add((0, 2, 3)) assert cdata.lower == 0 assert cdata.upper == 3 assert cdata.body() == 2 assert not cdata.equality cdata = model.c.add((0, 1, None)) assert cdata.lower == 0 assert cdata.upper is None assert cdata.body() == 1 assert not cdata.equality cdata = model.c.add((None, 0, 1)) assert cdata.lower is None assert cdata.upper == 1 assert cdata.body() == 0 assert not cdata.equality cdata = model.c.add((1, 1)) assert cdata.lower == 1 assert cdata.upper == 1 assert cdata.body() == 1 assert cdata.equality model.fixed_var = Var() model.fixed_var.fix(1.0) cdata = model.c.add((0, 1 + model.fixed_var, 3)) cdata = model.c.add((0, 2 + model.fixed_var, 3)) cdata = model.c.add((0, model.fixed_var, None)) cdata = model.c.add((None, model.fixed_var, 1)) cdata = model.c.add((model.fixed_var, 1)) model.c_inactive = ConstraintList() # to make the variable used in the constraint match the name model.c_inactive.add(Constraint.Skip) model.c_inactive.add(Constraint.Skip) model.c_inactive.add(model.x[3] >= -2.) model.c_inactive.add(model.x[4] <= 2.) compile_block_linear_constraints(model, 'Amatrix')
def generate_structured_model(self): """ Using the community map and the original model used to create this community map, we will create structured_model, which will be based on the original model but will place variables, constraints, and objectives into or outside of various blocks (communities) based on the community map. Returns ------- structured_model: Block a Pyomo model that reflects the nature of the community map """ # Initialize a new model (structured_model) which will contain variables and constraints in blocks based on # their respective communities within the CommunityMap structured_model = ConcreteModel() # Create N blocks (where N is the number of communities found within the model) structured_model.b = Block([0, len(self.community_map) - 1, 1]) # values given for (start, stop, step) # Initialize a ComponentMap that will map a variable from the model (for example, old_model.x1) used to # create the CommunityMap to a list of variables in various blocks that were created based on this # variable (for example, [structured_model.b[0].x1, structured_model.b[3].x1]) blocked_variable_map = ComponentMap() # Example key-value pair -> {original_model.x1 : [structured_model.b[0].x1, structured_model.b[3].x1]} # TODO - Consider changing structure of the next two for loops to be more efficient (maybe loop through # constraints and add variables as you go) (but note that disconnected variables would be # missed with this strategy) # First loop through community_map to add all the variables to structured_model before we add constraints # that use those variables for community_key, community in self.community_map.items(): _, variables_in_community = community # Loop through all of the variables (from the original model) in the given community for stored_variable in variables_in_community: # Construct a new_variable whose attributes are determined by querying the variable from the # original model new_variable = Var(domain=stored_variable.domain, bounds=stored_variable.bounds) # Add this new_variable to its block/community and name it using the string of the variable from the # original model structured_model.b[community_key].add_component( str(stored_variable), new_variable) # Since there could be multiple variables 'x1' (such as # structured_model.b[0].x1, structured_model.b[3].x1, etc), we need to create equality constraints # for all of the variables 'x1' within structured_model (this is the purpose of blocked_variable_map) # Here we update blocked_variable_map to keep track of what equality constraints need to be made variable_in_new_model = structured_model.find_component( new_variable) blocked_variable_map[ stored_variable] = blocked_variable_map.get( stored_variable, []) + [variable_in_new_model] # Now that we have all of our variables within the model, we will initialize a dictionary that used to # replace variables within constraints to other variables (in our case, this will convert variables from the # original model into variables from the new model (structured_model)) replace_variables_in_expression_map = dict() # Loop through community_map again, this time to add constraints (with replaced variables) for community_key, community in self.community_map.items(): constraints_in_community, _ = community # Loop through all of the constraints (from the original model) in the given community for stored_constraint in constraints_in_community: # Now, loop through all of the variables within the given constraint expression for variable_in_stored_constraint in identify_variables( stored_constraint.expr): # Loop through each of the "blocked" variables that a variable is mapped to and update # replace_variables_in_expression_map if a variable has a "blocked" form in the given community # What this means is that if we are looping through constraints in community 0, then it would be # best to change a variable x1 into b[0].x1 as opposed to b[2].x1 or b[5].x1 (assuming all of these # blocked versions of the variable x1 exist (which depends on the community map)) variable_in_current_block = False for blocked_variable in blocked_variable_map[ variable_in_stored_constraint]: if 'b[%d]' % community_key in str(blocked_variable): # Update replace_variables_in_expression_map accordingly replace_variables_in_expression_map[ id(variable_in_stored_constraint )] = blocked_variable variable_in_current_block = True if not variable_in_current_block: # Create a version of the given variable outside of blocks then add it to # replace_variables_in_expression_map new_variable = Var( domain=variable_in_stored_constraint.domain, bounds=variable_in_stored_constraint.bounds) # Add the new variable just as we did above (but now it is not in any blocks) structured_model.add_component( str(variable_in_stored_constraint), new_variable) # Update blocked_variable_map to keep track of what equality constraints need to be made variable_in_new_model = structured_model.find_component( new_variable) blocked_variable_map[ variable_in_stored_constraint] = blocked_variable_map.get( variable_in_stored_constraint, []) + [variable_in_new_model] # Update replace_variables_in_expression_map accordingly replace_variables_in_expression_map[ id(variable_in_stored_constraint )] = variable_in_new_model # TODO - Is there a better way to check whether something is actually an objective? (as done below) # Check to see whether 'stored_constraint' is actually an objective (since constraints and objectives # grouped together) if self.with_objective and isinstance( stored_constraint, (_GeneralObjectiveData, Objective)): # If the constraint is actually an objective, we add it to the block as an objective new_objective = Objective(expr=replace_expressions( stored_constraint.expr, replace_variables_in_expression_map)) structured_model.b[community_key].add_component( str(stored_constraint), new_objective) else: # Construct a constraint based on the expression within stored_constraint and the dict we have # created for the purpose of replacing the variables within the constraint expression new_constraint = Constraint(expr=replace_expressions( stored_constraint.expr, replace_variables_in_expression_map)) # Add this new constraint to the corresponding community/block with its name as the string of the # constraint from the original model structured_model.b[community_key].add_component( str(stored_constraint), new_constraint) # If with_objective was set to False, that means we might have missed an objective function within the # original model if not self.with_objective: # Construct a new dictionary for replacing the variables (replace_variables_in_objective_map) which will # be specific to the variables in the objective function, since there is the possibility that the # objective contains variables we have not yet seen (and thus not yet added to our new model) for objective_function in self.model.component_data_objects( ctype=Objective, active=self.use_only_active_components, descend_into=True): for variable_in_objective in identify_variables( objective_function): # Add all of the variables in the objective function (not within any blocks) # Check to make sure a form of the variable has not already been made outside of the blocks if structured_model.find_component( str(variable_in_objective)) is None: new_variable = Var(domain=variable_in_objective.domain, bounds=variable_in_objective.bounds) structured_model.add_component( str(variable_in_objective), new_variable) # Again we update blocked_variable_map to keep track of what # equality constraints need to be made variable_in_new_model = structured_model.find_component( new_variable) blocked_variable_map[ variable_in_objective] = blocked_variable_map.get( variable_in_objective, []) + [variable_in_new_model] # Update the dictionary that we will use to replace the variables replace_variables_in_expression_map[id( variable_in_objective)] = variable_in_new_model else: for version_of_variable in blocked_variable_map[ variable_in_objective]: if 'b[' not in str(version_of_variable): replace_variables_in_expression_map[ id(variable_in_objective )] = version_of_variable # Now we will construct a new objective function based on the one from the original model and then # add it to the new model just as we have done before new_objective = Objective(expr=replace_expressions( objective_function.expr, replace_variables_in_expression_map)) structured_model.add_component(str(objective_function), new_objective) # Now, we need to create equality constraints for all of the different "versions" of a variable (such # as x1, b[0].x1, b[2].x2, etc.) # Create a constraint list for the equality constraints structured_model.equality_constraint_list = ConstraintList( doc="Equality Constraints for the different " "forms of a given variable") # Loop through blocked_variable_map and create constraints accordingly for variable, duplicate_variables in blocked_variable_map.items(): # variable -> variable from the original model # duplicate_variables -> list of variables in the new model # Create a list of all the possible equality constraints that need to be made equalities_to_make = combinations(duplicate_variables, 2) # Loop through the list of two-variable tuples and create an equality constraint for those two variables for variable_1, variable_2 in equalities_to_make: structured_model.equality_constraint_list.add( expr=variable_1 == variable_2) # Return 'structured_model', which is essentially identical to the original model but now has all of the # variables, constraints, and objectives placed into blocks based on the nature of the CommunityMap return structured_model
def create_linear_dual_from(block, fixed=None, unfixed=None): """ Construct a block that represents the dual of the given block. The resulting block contains variables and constraints whose names are the dual names of the primal block. Note that this involves a many string operations. A quicker operations could be executed, but it would generate a dual representation that is difficult to interpret. Note that the dualization of a maximization problem is performed by negating objective and right-hand side coefficients after dualizing the corresponding minimization problem. This suggestion is made by Dimitri Bertsimas and John Tsitsiklis in section 4.2 page 143 of "Introduction to Linear Optimization" Arguments: block: A Pyomo block or model unfixed: An iterable object with Variable and VarData values that are not fixed variables. All other variables are assumed to be fixed. fixed: An iterable object with Variable and VarData values that are fixed. All other variables are assumed not fixed. Returns: If the block is a model object, then this returns a ConcreteModel. Otherwise, it returns a Block. """ # # Collect vardata that needs to be fixed # fixed_modelvars = {} if fixed or unfixed: # # Collect model variables # modelvars = {} # # vardata in objectives # for obj in block.component_objects(Objective, active=True): for ndx in obj: #odata = generate_standard_repn(obj[ndx].expr, compute_values=False) for vdata in identify_variables(obj[ndx].expr, include_fixed=False): id_ = id(vdata) if not id_ in modelvars: modelvars[id_] = vdata # # vardata in constraints # for con in block.component_objects(Constraint, active=True): for ndx in con: #cdata = generate_standard_repn(con[ndx].body, compute_values=False) for vdata in identify_variables(con[ndx].body, include_fixed=False): id_ = id(vdata) if not id_ in modelvars: modelvars[id_] = vdata # # Fix everything that isn't specified as unfixed # if unfixed: unfixed_vars = set() for v in unfixed: if v.is_indexed(): for vardata in v.values(): unfixed_vars.add( id(vardata) ) else: unfixed_vars.add( id(v) ) for id_, vdata in modelvars.items(): if id_ not in unfixed_vars: fixed_modelvars[id_] = vdata # # ... or fix everything that is specified as fixed # elif fixed: fixed_vars = set() for v in fixed: if v.is_indexed(): for vardata in v.values(): fixed_vars.add( id(vardata) ) else: fixed_vars.add( id(v) ) for id_ in fixed_vars: if id_ in modelvars: fixed_modelvars[id_] = modelvars[id_] A, b_coef, obj_constant, c_rhs, c_sense, d_sense, v_domain =\ collect_dual_representation(block, fixed_modelvars) # # Construct the block # if isinstance(block, Model): dual = ConcreteModel() else: dual = Block() dual.construct() _vars = {} # Return variable object from name and index (if applicable) def getvar(name, ndx=None): v = _vars.get((name, ndx), None) if v is None: v = Var() if ndx is None: v_name = name elif isinstance(ndx, tuple): v_name = "%s[%s]" % (name, ','.join(map(str, ndx))) else: v_name = "%s[%s]" % (name, str(ndx)) setattr(dual, v_name, v) _vars[name, ndx] = v return v # # Construct the objective # The dualization of a maximization problem is handled by simply negating the # objective and left-hand side coefficients while keeping the dual sense. # if d_sense == minimize: dual.o = Objective(expr=obj_constant + sum(- b_coef[name, ndx]*getvar(name, ndx) for name, ndx in b_coef), sense=d_sense) rhs_multiplier = -1 else: dual.o = Objective(expr=obj_constant + sum(b_coef[name, ndx]*getvar(name, ndx) for name, ndx in b_coef), sense=d_sense) rhs_multiplier = 1 # # Construct the constraints from dual A matrix # for cname in A: for ndx, terms in A[cname].items(): # Build left-hand side of constraint expr = 0 for term in terms: expr += term.coef * getvar(term.var, term.ndx) # # Assign right-hand side coefficient # Note that rhs_multiplier is 1 if the dual is a maximization problem and -1 otherwise # rhsval = rhs_multiplier*c_rhs.get((cname, ndx), 0.0) # Using the correct inequality or equality if c_sense[cname, ndx] == 'e': e = expr - rhsval == 0 elif c_sense[cname, ndx] == 'l': e = expr - rhsval <= 0 else: e = expr - rhsval >= 0 c = Constraint(expr=e) # Build constraint name if ndx is None: c_name = cname elif isinstance(ndx, tuple): c_name = "%s[%s]" % (cname, ','.join(map(str, ndx))) else: c_name = "%s[%s]" % (cname, str(ndx)) # Add new constraint along with its name to the dual setattr(dual, c_name, c) # Set variable domains for (name, ndx), domain in v_domain.items(): v = getvar(name, ndx) #flag = type(ndx) is tuple and (ndx[-1] == 'lb' or ndx[-1] == 'ub') if domain == 1: v.domain = NonNegativeReals elif domain == -1: v.domain = NonPositiveReals else: # This is possible when the variable's corresponding constraint is an equality v.domain = Reals return dual