Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions pyomo/contrib/solver/solvers/knitro/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def solve(self, model: BlockData, **kwds) -> Results:
if config.restore_variable_values_after_solve:
self._save_var_values()

with capture_output(TeeStream(self._stream, *config.tee), capture_fd=False):
with capture_output(TeeStream(self._stream, *config.tee), capture_fd=True):
self._solve(config, timer)

if config.restore_variable_values_after_solve:
Expand Down Expand Up @@ -268,4 +268,6 @@ def _get_error_type(
return NoReducedCostsError
elif item_type is ConstraintData and value_type == ValueType.DUAL:
return NoDualsError
raise DeveloperError()
raise DeveloperError(
f"Unsupported KNITRO item type {item_type} and value type {value_type}."
)
15 changes: 13 additions & 2 deletions pyomo/contrib/solver/solvers/knitro/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,13 @@ def __init__(
ConfigValue(
domain=Bool,
default=False,
doc="KNITRO solver does not allow variable removal. We can either make the variable a continuous free variable or rebuild the whole model when variable removal is attempted. When `rebuild_model_on_remove_var` is set to True, the model will be rebuilt.",
doc=(
"KNITRO solver does not allow variable removal. We can "
"either make the variable a continuous free variable or "
"rebuild the whole model when variable removal is "
"attempted. When `rebuild_model_on_remove_var` is set to "
"True, the model will be rebuilt."
),
),
)

Expand All @@ -44,6 +50,11 @@ def __init__(
ConfigValue(
domain=Bool,
default=False,
doc="To evaluate non-linear constraints, KNITRO solver sets explicit values on variables. This option controls whether to restore the original variable values after solving.",
doc=(
"To evaluate non-linear constraints, KNITRO solver sets "
"explicit values on variables. This option controls "
"whether to restore the original variable values after "
"solving."
),
),
)
38 changes: 23 additions & 15 deletions pyomo/contrib/solver/solvers/knitro/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,20 @@ def parse_bounds(
if item.fixed:
bounds_map[BoundType.EQ][i] = value(item.value)
continue
if item.has_lb():
bounds_map[BoundType.LO][i] = value(item.lb)
if item.has_ub():
bounds_map[BoundType.UP][i] = value(item.ub)
lb, ub = item.bounds
if lb is not None:
bounds_map[BoundType.LO][i] = lb
if ub is not None:
bounds_map[BoundType.UP][i] = ub
elif isinstance(item, ConstraintData):
lb, _, ub = item.to_bounded_expression(evaluate_bounds=True)
if item.equality:
bounds_map[BoundType.EQ][i] = value(item.lower)
bounds_map[BoundType.EQ][i] = lb
continue
if item.has_lb():
bounds_map[BoundType.LO][i] = value(item.lower)
if item.has_ub():
bounds_map[BoundType.UP][i] = value(item.upper)
if lb is not None:
bounds_map[BoundType.LO][i] = lb
if ub is not None:
bounds_map[BoundType.UP][i] = ub
return bounds_map


Expand Down Expand Up @@ -85,7 +87,7 @@ def api_set_param(param_type: int) -> Callable[..., None]:
return knitro.KN_set_double_param
elif param_type == knitro.KN_PARAMTYPE_STRING:
return knitro.KN_set_char_param
raise DeveloperError()
raise DeveloperError(f"Unsupported KNITRO parameter type: {param_type}")


def api_get_values(
Expand All @@ -101,15 +103,17 @@ def api_get_values(
return knitro.KN_get_con_dual_values
elif value_type == ValueType.PRIMAL:
return knitro.KN_get_con_values
raise DeveloperError()
raise DeveloperError(
f"Unsupported KNITRO item type or value type: {item_type}, {value_type}"
)


def api_add_items(item_type: type[ItemType]) -> Callable[..., Optional[list[int]]]:
if item_type is VarData:
return knitro.KN_add_vars
elif item_type is ConstraintData:
return knitro.KN_add_cons
raise DeveloperError()
raise DeveloperError(f"Unsupported KNITRO item type: {item_type}")


def api_set_bnds(
Expand All @@ -129,13 +133,15 @@ def api_set_bnds(
return knitro.KN_set_con_lobnds
elif bound_type == BoundType.UP:
return knitro.KN_set_con_upbnds
raise DeveloperError()
raise DeveloperError(
f"Unsupported KNITRO item type or bound type: {item_type}, {bound_type}"
)


def api_set_types(item_type: type[ItemType]) -> Callable[..., None]:
if item_type is VarData:
return knitro.KN_set_var_types
raise DeveloperError()
raise DeveloperError(f"Unsupported KNITRO item type: {item_type}")


def api_add_struct(is_obj: bool, structure_type: StructureType) -> Callable[..., None]:
Expand All @@ -153,7 +159,9 @@ def api_add_struct(is_obj: bool, structure_type: StructureType) -> Callable[...,
return knitro.KN_add_con_linear_struct
elif structure_type == StructureType.QUADRATIC:
return knitro.KN_add_con_quadratic_struct
raise DeveloperError()
raise DeveloperError(
f"Unsupported KNITRO structure type: is_obj={is_obj}, structure_type={structure_type}"
)


class Engine:
Expand Down
3 changes: 2 additions & 1 deletion pyomo/contrib/solver/solvers/knitro/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from pyomo.contrib.solver.solvers.knitro.typing import Function
from pyomo.core.base.block import BlockData
from pyomo.core.base.constraint import Constraint, ConstraintData
from pyomo.core.base.enums import SortComponents
from pyomo.core.base.expression import Expression
from pyomo.core.base.objective import Objective, ObjectiveData
from pyomo.core.base.var import VarData
Expand Down Expand Up @@ -51,7 +52,7 @@ def get_active_constraints(block: BlockData) -> list[ConstraintData]:

"""
generator = block.component_data_objects(
Constraint, descend_into=True, active=True, sort=True
Constraint, descend_into=True, active=True, sort=SortComponents.deterministic
)
return list(generator)

Expand Down
29 changes: 29 additions & 0 deletions pyomo/contrib/solver/tests/solvers/test_knitro_direct.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________

import io
from contextlib import redirect_stdout

import pyomo.common.unittest as unittest

from pyomo.contrib.solver.solvers.knitro.config import KnitroConfig
Expand Down Expand Up @@ -87,6 +90,32 @@ class TestKnitroDirectSolver(unittest.TestCase):
def setUp(self):
self.opt = KnitroDirectSolver()

def test_solve_tee(self):
m = pyo.ConcreteModel()
m.x = pyo.Var(initialize=1.5, bounds=(-5, 5))
m.y = pyo.Var(initialize=1.5, bounds=(-5, 5))
m.obj = pyo.Objective(
expr=(1.0 - m.x) + 100.0 * (m.y - m.x), sense=pyo.minimize
)
stream = io.StringIO()
with redirect_stdout(stream):
self.opt.solve(m, tee=True)
output = stream.getvalue()
self.assertTrue(bool(output.strip()))

def test_solve_no_tee(self):
m = pyo.ConcreteModel()
m.x = pyo.Var(initialize=1.5, bounds=(-5, 5))
m.y = pyo.Var(initialize=1.5, bounds=(-5, 5))
m.obj = pyo.Objective(
expr=(1.0 - m.x) + 100.0 * (m.y - m.x), sense=pyo.minimize
)
stream = io.StringIO()
with redirect_stdout(stream):
self.opt.solve(m, tee=False)
output = stream.getvalue()
self.assertFalse(bool(output.strip()))

def test_solve(self):
m = pyo.ConcreteModel()
m.x = pyo.Var(initialize=1.5, bounds=(-5, 5))
Expand Down
Loading