Skip to content

Commit

Permalink
Beginning of mixed form LP dal, no parameterized, with tests that don…
Browse files Browse the repository at this point in the history
…'t work
  • Loading branch information
emma58 committed May 23, 2024
1 parent 601471f commit 16fdff4
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 3 deletions.
63 changes: 60 additions & 3 deletions pyomo/core/plugins/transform/lp_dual.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from pyomo.common.dependencies import scipy
from pyomo.core import (
ConcreteModel,
Block,
Var,
Constraint,
Objective,
Expand Down Expand Up @@ -47,6 +48,18 @@ def var_list(x):
raise ValueError("Expected Var or list of Vars.\n\tReceived %s" % type(x))


class _LPDualData(AutoSlots.Mixin):
__slots__ = ('primal_var', 'dual_var', 'primal_constraint', 'dual_constraint')
def __init__(self):
self.primal_var = {}
self.dual_var = {}
self.primal_constraint = ComponentMap()
self.dual_constraint = ComponentMap()


Block.register_private_data_initializer(_LPDualData)


@TransformationFactory.register(
'core.lp_dual', 'Generate the linear programming dual of the given model'
)
Expand Down Expand Up @@ -118,13 +131,17 @@ def _take_dual(self, model):
rows = range(A_transpose.shape[0])
cols = range(A_transpose.shape[1])
dual.x = Var(cols, domain=NonNegativeReals)
trans_info = model.private_data()
for j, (primal_cons, ineq) in enumerate(std_form.rows):
if primal_sense is minimize and ineq == 1:
dual.x[j].domain = NonPositiveReals
elif primal_sense is maximzie and ineq == -1:
elif primal_sense is maximize and ineq == -1:
dual.x[j].domain = NonPositiveReals
from pytest import set_trace
set_trace()
if ineq == 0:
# equality
dual.x[j].domain = Reals
trans_info.primal_constraint[dual.x[j]] = primal_cons
trans_info.dual_var[primal_cons] = dual.x[j]

dual.constraints = Constraint(rows)
for i, primal in enumerate(std_form.columns):
Expand Down Expand Up @@ -154,6 +171,8 @@ def _take_dual(self, model):
dual.constraints[i] = (
sum(A_transpose[i, j] * dual.x[j] for j in cols) == std_form.c[0, i]
)
trans_info.dual_constraint[primal] = dual.constraints[i]
trans_info.primal_var[dual.constraints[i]] = primal

dual.obj = Objective(
expr=sum(std_form.rhs[j] * dual.x[j] for j in cols), sense=-primal_sense
Expand All @@ -163,3 +182,41 @@ def _take_dual(self, model):

def _take_parameterized_dual(self, model, wrt):
pass

def get_primal_constraint(self, model, dual_var):
primal_constraint = model.private_data().primal_constraint
if dual_var in primal_constraint:
return primal_constraint[dual_var]
else:
raise ValueError(
"It does not appear that Var '%s' is a dual variable on model '%s'"
% (dual_var.name, model.name)
)

def get_dual_constraint(self, model, primal_var):
dual_constraint = model.private_data().dual_constraint
if primal_var in dual_constraint:
return dual_constraint[primal_var]
else:
raise ValueError(
"It does not appear that Var '%s' is a primal variable from model '%s'"
% (primal_var.name, model.name)
)

def get_primal_var(self, model, dual_constraint):
primal_var = model.private_data().primal_var
if dual_constraint in primal_var:
return primal_var[dual_constraint]
else:
raise ValueError(
"It does not appear that Constraint '%s' is a dual constraint on "
"model '%s'" % (dual_constraint.name, model.name))

def get_dual_var(self, model, primal_constraint):
dual_var = model.private_data().dual_var
if primal_constraint in dual_var:
return dual_var[primal_constraint]
else:
raise ValueError(
"It does not appear that Constraint '%s' is a primal constraint from "
"model '%s'" % (primal_constraint.name, model.name))
47 changes: 47 additions & 0 deletions pyomo/core/tests/unit/test_lp_dual.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,50 @@ def test_lp_dual(self):

lp_dual = TransformationFactory('core.lp_dual')
dual = lp_dual.create_using(m)

alpha = lp_dual.get_dual_var(m.c1)
beta = lp_dual.get_dual_var(m.c2)
lamb = lp_dual.get_dual_var(m.c3)
xi = lp_dual.get_dual_var(m.c4)

self.assertIs(lp_dual.get_primal_constraint[alpha], m.c1)
self.assertIs(lp_dual.get_primal_constraint[beta], m.c2)
self.assertIs(lp_dual.get_primal_constraint[lamb], m.c3)
self.assertIs(lp_dual.get_primal_constraint[xi], m.c4)

dx = lp_dual.get_dual_constraint[m.x]
dy = lp_dual.get_dual_constraint[m.y]
dz = lp_dual.get_dual_constraint[m.z]

self.assertIs(lp_dual.get_primal_var[dx], m.x)
self.assertIs(lp_dual.get_primal_var[dy], m.y)
self.assertIs(lp_dual.get_primal_var[dz], m.z)

self.assertIsInstance(alpha, Var)
self.assertIs(alpha.domain, NonPositiveReals)
self.assertEqual(alpha.ub, 0)
self.assertIsNone(alpha.lb)
self.assertIsInstance(beta, Var)
self.assertIs(alpha.domain, NonNegativeReals)
self.assertEqual(alpha.lb, 0)
self.assertIsNone(alpha.ub)
self.assertIsInstance(lamb, Var)
self.assertIs(lamb.domain, Reals)
self.assertIsNone(lamb.ub)
self.assertIsNone(lamb.lb)
self.assertIsInstance(xi, Var)
self.assertIs(xi.domain, NonPositiveReals)
self.assertEqual(xi.ub, 0)
self.assertIsNone(xi.lb)

self.assertIsInstance(dx, Constraint)
self.assertIsInstance(dy, Constraint)
self.assertIsInstance(dz, Constraint)

assertExpressionsEqual(
self,
dx.expr,
-4 * alpha + beta <= 1
)

# TODO: map objectives, and test them

0 comments on commit 16fdff4

Please sign in to comment.