Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add qp support for highs #3531

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
2 changes: 1 addition & 1 deletion pyomo/contrib/appsi/solvers/highs.py
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,7 @@ def _set_objective(self, obj):
)

repn = generate_standard_repn(
obj.expr, quadratic=False, compute_values=False
obj.expr, quadratic=True, compute_values=False
)
if repn.nonlinear_expr is not None:
raise DegreeError(
Expand Down
91 changes: 54 additions & 37 deletions pyomo/contrib/appsi/solvers/tests/test_highs_persistent.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,11 @@
import sys

import pyomo.common.unittest as unittest
import pyomo.environ as pe
import pyomo.environ as pyo

from pyomo.common.log import LoggingIntercept
from pyomo.common.tee import capture_output
from pyomo.contrib.appsi.solvers.highs import Highs
from pyomo.contrib.appsi.base import TerminationCondition


opt = Highs()
Expand All @@ -28,16 +27,16 @@

class TestBugs(unittest.TestCase):
def test_mutable_params_with_remove_cons(self):
m = pe.ConcreteModel()
m.x = pe.Var(bounds=(-10, 10))
m.y = pe.Var()
m = pyo.ConcreteModel()
m.x = pyo.Var(bounds=(-10, 10))
m.y = pyo.Var()

m.p1 = pe.Param(mutable=True)
m.p2 = pe.Param(mutable=True)
m.p1 = pyo.Param(mutable=True)
m.p2 = pyo.Param(mutable=True)

m.obj = pe.Objective(expr=m.y)
m.c1 = pe.Constraint(expr=m.y >= m.x + m.p1)
m.c2 = pe.Constraint(expr=m.y >= -m.x + m.p2)
m.obj = pyo.Objective(expr=m.y)
m.c1 = pyo.Constraint(expr=m.y >= m.x + m.p1)
m.c2 = pyo.Constraint(expr=m.y >= -m.x + m.p2)

m.p1.value = 1
m.p2.value = 1
Expand All @@ -52,19 +51,19 @@ def test_mutable_params_with_remove_cons(self):
self.assertAlmostEqual(res.best_feasible_objective, -8)

def test_mutable_params_with_remove_vars(self):
m = pe.ConcreteModel()
m.x = pe.Var()
m.y = pe.Var()
m = pyo.ConcreteModel()
m.x = pyo.Var()
m.y = pyo.Var()

m.p1 = pe.Param(mutable=True)
m.p2 = pe.Param(mutable=True)
m.p1 = pyo.Param(mutable=True)
m.p2 = pyo.Param(mutable=True)

m.y.setlb(m.p1)
m.y.setub(m.p2)

m.obj = pe.Objective(expr=m.y)
m.c1 = pe.Constraint(expr=m.y >= m.x + 1)
m.c2 = pe.Constraint(expr=m.y >= -m.x + 1)
m.obj = pyo.Objective(expr=m.y)
m.c1 = pyo.Constraint(expr=m.y >= m.x + 1)
m.c2 = pyo.Constraint(expr=m.y >= -m.x + 1)

m.p1.value = -10
m.p2.value = 10
Expand All @@ -83,16 +82,16 @@ def test_mutable_params_with_remove_vars(self):
def test_fix_and_unfix(self):
# Tests issue https://github.com/Pyomo/pyomo/issues/3127

m = pe.ConcreteModel()
m.x = pe.Var(domain=pe.Binary)
m.y = pe.Var(domain=pe.Binary)
m.fx = pe.Var(domain=pe.NonNegativeReals)
m.fy = pe.Var(domain=pe.NonNegativeReals)
m.c1 = pe.Constraint(expr=m.fx <= m.x)
m.c2 = pe.Constraint(expr=m.fy <= m.y)
m.c3 = pe.Constraint(expr=m.x + m.y <= 1)
m = pyo.ConcreteModel()
m.x = pyo.Var(domain=pyo.Binary)
m.y = pyo.Var(domain=pyo.Binary)
m.fx = pyo.Var(domain=pyo.NonNegativeReals)
m.fy = pyo.Var(domain=pyo.NonNegativeReals)
m.c1 = pyo.Constraint(expr=m.fx <= m.x)
m.c2 = pyo.Constraint(expr=m.fy <= m.y)
m.c3 = pyo.Constraint(expr=m.x + m.y <= 1)

m.obj = pe.Objective(expr=m.fx * 0.5 + m.fy * 0.4, sense=pe.maximize)
m.obj = pyo.Objective(expr=m.fx * 0.5 + m.fy * 0.4, sense=pyo.maximize)

opt = Highs()

Expand Down Expand Up @@ -157,21 +156,21 @@ def test_capture_highs_output(self):
self.assertEqual(ref, OUT.getvalue()[-len(ref) :])

def test_warm_start(self):
m = pe.ConcreteModel()
m = pyo.ConcreteModel()

# decision variables
m.x1 = pe.Var(domain=pe.Integers, name="x1", bounds=(0, 10))
m.x2 = pe.Var(domain=pe.Reals, name="x2", bounds=(0, 10))
m.x3 = pe.Var(domain=pe.Binary, name="x3")
m.x1 = pyo.Var(domain=pyo.Integers, name="x1", bounds=(0, 10))
m.x2 = pyo.Var(domain=pyo.Reals, name="x2", bounds=(0, 10))
m.x3 = pyo.Var(domain=pyo.Binary, name="x3")

# objective function
m.OBJ = pe.Objective(expr=(3 * m.x1 + 2 * m.x2 + 4 * m.x3), sense=pe.maximize)
m.OBJ = pyo.Objective(expr=(3 * m.x1 + 2 * m.x2 + 4 * m.x3), sense=pyo.maximize)

# constraints
m.C1 = pe.Constraint(expr=m.x1 + m.x2 <= 9)
m.C2 = pe.Constraint(expr=3 * m.x1 + m.x2 <= 18)
m.C3 = pe.Constraint(expr=m.x1 <= 7)
m.C4 = pe.Constraint(expr=m.x2 <= 6)
m.C1 = pyo.Constraint(expr=m.x1 + m.x2 <= 9)
m.C2 = pyo.Constraint(expr=3 * m.x1 + m.x2 <= 18)
m.C3 = pyo.Constraint(expr=m.x1 <= 7)
m.C4 = pyo.Constraint(expr=m.x2 <= 6)

# MIP start
m.x1 = 4
Expand All @@ -180,6 +179,24 @@ def test_warm_start(self):

# solving process
with capture_output() as output:
pe.SolverFactory("appsi_highs").solve(m, tee=True, warmstart=True)
pyo.SolverFactory("appsi_highs").solve(m, tee=True, warmstart=True)
log = output.getvalue()
self.assertIn("MIP start solution is feasible, objective value is 25", log)

def test_qp(self):
# test issue #3381
m = pyo.ConcreteModel()

m.x1 = pyo.Var(name='x1', domain=pyo.Reals)
m.x2 = pyo.Var(name='x2', domain=pyo.Reals)

# Quadratic Objective function
m.obj = pyo.Objective(expr=m.x1 * m.x1 + m.x2 * m.x2, sense=pyo.minimize)

m.con1 = pyo.Constraint(expr=m.x1 >= 1)
m.con2 = pyo.Constraint(expr=m.x2 >= 1)

opt = Highs()
opt.solve(m)
self.assertAlmostEqual(m.x1.value, 1, places=5)
self.assertAlmostEqual(m.x2.value, 1, places=5)
Loading