Add more constraint features

master
Alinson S. Xavier 5 years ago
parent b5e602cdc1
commit 5e1f26e4b0
No known key found for this signature in database
GPG Key ID: DCA0DAD4D2F58624

@ -4,8 +4,6 @@
import logging import logging
import re import re
import sys import sys
from dataclasses import dataclass
from enum import Enum
from io import StringIO from io import StringIO
from random import randint from random import randint
from typing import List, Any, Dict, Optional, Hashable from typing import List, Any, Dict, Optional, Hashable
@ -444,6 +442,14 @@ class GurobiSolver(InternalSolver):
) )
if self._has_lp_solution: if self._has_lp_solution:
constr.dual_value = gp_constr.pi constr.dual_value = gp_constr.pi
constr.sa_rhs_up = gp_constr.sarhsup
constr.sa_rhs_low = gp_constr.sarhslow
if gp_constr.cbasis == 0:
constr.basis_status = "b"
elif gp_constr.cbasis == -1:
constr.basis_status = "n"
else:
raise Exception(f"unknown cbasis: {gp_constr.cbasis}")
if self._has_lp_solution or self._has_mip_solution: if self._has_lp_solution or self._has_mip_solution:
constr.slack = gp_constr.slack constr.slack = gp_constr.slack
return constr return constr
@ -452,6 +458,22 @@ class GurobiSolver(InternalSolver):
def are_callbacks_supported(self) -> bool: def are_callbacks_supported(self) -> bool:
return True return True
@overrides
def get_constraint_attrs(self) -> List[str]:
return [
"basis_status",
"category",
"dual_value",
"lazy",
"lhs",
"rhs",
"sa_rhs_down",
"sa_rhs_up",
"sense",
"slack",
"user_features",
]
class GurobiTestInstanceInfeasible(Instance): class GurobiTestInstanceInfeasible(Instance):
@overrides @overrides

@ -246,3 +246,10 @@ class InternalSolver(ABC, EnforceOverrides):
callback or user cuts callback. callback or user cuts callback.
""" """
return False return False
@abstractmethod
def get_constraint_attrs(self) -> List[str]:
"""
Returns a list of constraint attributes supported by this solver.
"""
pass

@ -435,6 +435,19 @@ class BasePyomoSolver(InternalSolver):
def are_callbacks_supported(self) -> bool: def are_callbacks_supported(self) -> bool:
return False return False
@overrides
def get_constraint_attrs(self) -> List[str]:
return [
"category",
"dual_value",
"lazy",
"lhs",
"rhs",
"sense",
"slack",
"user_features",
]
class PyomoTestInstanceInfeasible(Instance): class PyomoTestInstanceInfeasible(Instance):
@overrides @overrides

@ -2,7 +2,7 @@
# Copyright (C) 2020-2021, UChicago Argonne, LLC. All rights reserved. # Copyright (C) 2020-2021, UChicago Argonne, LLC. All rights reserved.
# Released under the modified BSD license. See COPYING.md for more details. # Released under the modified BSD license. See COPYING.md for more details.
from typing import Any from typing import Any, Dict
from miplearn.features import Constraint from miplearn.features import Constraint
from miplearn.solvers.internal import InternalSolver from miplearn.solvers.internal import InternalSolver
@ -12,7 +12,7 @@ from miplearn.solvers.internal import InternalSolver
# This file is in the main source folder, so that it can be called from Julia. # This file is in the main source folder, so that it can be called from Julia.
def _round_constraints(constraints): def _round_constraints(constraints: Dict[str, Constraint]) -> Dict[str, Constraint]:
for (cname, c) in constraints.items(): for (cname, c) in constraints.items():
for attr in ["slack", "dual_value"]: for attr in ["slack", "dual_value"]:
if getattr(c, attr) is not None: if getattr(c, attr) is not None:
@ -20,6 +20,20 @@ def _round_constraints(constraints):
return constraints return constraints
def _remove_unsupported_constr_attrs(
solver: InternalSolver,
constraints: Dict[str, Constraint],
):
for (cname, c) in constraints.items():
to_remove = []
for k in c.__dict__.keys():
if k not in solver.get_constraint_attrs():
to_remove.append(k)
for k in to_remove:
setattr(c, k, None)
return constraints
def run_internal_solver_tests(solver: InternalSolver) -> None: def run_internal_solver_tests(solver: InternalSolver) -> None:
run_basic_usage_tests(solver.clone()) run_basic_usage_tests(solver.clone())
run_warm_start_tests(solver.clone()) run_warm_start_tests(solver.clone())
@ -76,6 +90,8 @@ def run_basic_usage_tests(solver: InternalSolver) -> None:
# Fetch constraints (after-lp) # Fetch constraints (after-lp)
assert_equals( assert_equals(
_round_constraints(solver.get_constraints()), _round_constraints(solver.get_constraints()),
_remove_unsupported_constr_attrs(
solver,
{ {
"eq_capacity": Constraint( "eq_capacity": Constraint(
lazy=False, lazy=False,
@ -84,8 +100,12 @@ def run_basic_usage_tests(solver: InternalSolver) -> None:
sense="<", sense="<",
slack=0.0, slack=0.0,
dual_value=13.538462, dual_value=13.538462,
sa_rhs_down=None,
sa_rhs_up=69.0,
basis_status="n",
) )
}, },
),
) )
# Solve MIP # Solve MIP

Loading…
Cancel
Save