Skip to content

Commit 68b5a04

Browse files
committed
Add IIS capability for Gurobi and COPT
1 parent db70ec6 commit 68b5a04

File tree

13 files changed

+222
-49
lines changed

13 files changed

+222
-49
lines changed

include/pyoptinterface/copt_model.hpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,13 @@ extern "C"
8484
B(COPT_DeleteEnv); \
8585
B(COPT_CreateEnvConfig); \
8686
B(COPT_DeleteEnvConfig); \
87-
B(COPT_SetEnvConfig);
87+
B(COPT_SetEnvConfig); \
88+
B(COPT_ComputeIIS); \
89+
B(COPT_GetColLowerIIS); \
90+
B(COPT_GetColUpperIIS); \
91+
B(COPT_GetRowLowerIIS); \
92+
B(COPT_GetRowUpperIIS); \
93+
B(COPT_GetSOSIIS);
8894

8995
namespace copt
9096
{
@@ -288,6 +294,12 @@ class COPTModel
288294
void cb_add_user_cut(const ScalarAffineFunction &function, ConstraintSense sense, CoeffT rhs);
289295
void cb_add_user_cut(const ExprBuilder &function, ConstraintSense sense, CoeffT rhs);
290296

297+
// IIS related
298+
void computeIIS();
299+
int _get_variable_upperbound_IIS(const VariableIndex &variable);
300+
int _get_variable_lowerbound_IIS(const VariableIndex &variable);
301+
int _get_constraint_IIS(const ConstraintIndex &constraint);
302+
291303
private:
292304
MonotoneIndexer<int> m_variable_index;
293305

include/pyoptinterface/gurobi_model.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@
6767
B(GRBloadenv); \
6868
B(GRBfreeenv); \
6969
B(GRBstartenv); \
70-
B(GRBconverttofixed);
70+
B(GRBconverttofixed); \
71+
B(GRBcomputeIIS);
7172

7273
namespace gurobi
7374
{
@@ -255,6 +256,9 @@ class GurobiModel
255256
// Gurobi-specific convertofixed
256257
void _converttofixed();
257258

259+
// IIS related
260+
void computeIIS();
261+
258262
// Non-exported functions
259263
void check_error(int error);
260264

include/pyoptinterface/solver_common.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class CommercialSolverMixin : public T
5656
std::string pprint_expression(const ExprBuilder &function, int precision = 4);
5757

5858
void set_objective_as_constant(CoeffT c, ObjectiveSense sense);
59+
void set_objective_as_variable(const VariableIndex &variable, ObjectiveSense sense);
5960
};
6061

6162
template <CommercialSolverConstraint T>
@@ -327,6 +328,14 @@ void CommercialSolverMixin<T>::set_objective_as_constant(CoeffT c, ObjectiveSens
327328
get_base()->set_objective(f, sense);
328329
}
329330

331+
template <CommercialSolverConstraint T>
332+
void CommercialSolverMixin<T>::set_objective_as_variable(const VariableIndex &variable,
333+
ObjectiveSense sense)
334+
{
335+
ScalarAffineFunction f(variable);
336+
get_base()->set_objective(f, sense);
337+
}
338+
330339
/* This concept combined with partial specialization causes ICE on gcc 10 */
331340
// template <typename T>
332341
// concept VarIndexModel = requires(T *model, const VariableIndex &v) {

lib/copt_model.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,3 +1234,58 @@ void COPTModel::cb_add_user_cut(const ExprBuilder &function, ConstraintSense sen
12341234
ScalarAffineFunction f(function);
12351235
cb_add_user_cut(f, sense, rhs);
12361236
}
1237+
1238+
void COPTModel::computeIIS()
1239+
{
1240+
int error = copt::COPT_ComputeIIS(m_model.get());
1241+
check_error(error);
1242+
}
1243+
1244+
int COPTModel::_get_variable_upperbound_IIS(const VariableIndex &variable)
1245+
{
1246+
auto column = _checked_variable_index(variable);
1247+
int retval;
1248+
int error = copt::COPT_GetColUpperIIS(m_model.get(), 1, &column, &retval);
1249+
check_error(error);
1250+
return retval;
1251+
}
1252+
1253+
int COPTModel::_get_variable_lowerbound_IIS(const VariableIndex &variable)
1254+
{
1255+
auto column = _checked_variable_index(variable);
1256+
int retval;
1257+
int error = copt::COPT_GetColLowerIIS(m_model.get(), 1, &column, &retval);
1258+
check_error(error);
1259+
return retval;
1260+
}
1261+
1262+
int COPTModel::_get_constraint_IIS(const ConstraintIndex &constraint)
1263+
{
1264+
int row = _checked_constraint_index(constraint);
1265+
int num = 1;
1266+
int error;
1267+
switch (constraint.type)
1268+
{
1269+
case ConstraintType::Linear: {
1270+
int lb_iis, ub_iis;
1271+
1272+
error = copt::COPT_GetRowLowerIIS(m_model.get(), num, &row, &lb_iis);
1273+
check_error(error);
1274+
1275+
error = copt::COPT_GetRowUpperIIS(m_model.get(), num, &row, &ub_iis);
1276+
check_error(error);
1277+
1278+
return lb_iis + ub_iis;
1279+
}
1280+
break;
1281+
case ConstraintType::SOS: {
1282+
int iis;
1283+
error = copt::COPT_GetSOSIIS(m_model.get(), num, &row, &iis);
1284+
check_error(error);
1285+
return iis;
1286+
}
1287+
break;
1288+
default:
1289+
throw std::runtime_error("Unknown constraint type to get IIS state");
1290+
}
1291+
}

lib/copt_model_ext.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ NB_MODULE(copt_model_ext, m)
4141
BIND_F(delete_variables)
4242
BIND_F(is_variable_active)
4343
// clang-format on
44-
.def("set_variable_bounds", &COPTModelMixin::set_variable_bounds, nb::arg("variable"),
44+
.def("set_variable_bounds", &COPTModelMixin::set_variable_bounds, nb::arg("variable"),
4545
nb::arg("lb"), nb::arg("ub"))
4646

4747
.def("get_value",
@@ -111,6 +111,10 @@ NB_MODULE(copt_model_ext, m)
111111
.def("set_objective",
112112
nb::overload_cast<const ExprBuilder &, ObjectiveSense>(&COPTModelMixin::set_objective),
113113
nb::arg("expr"), nb::arg("sense") = ObjectiveSense::Minimize)
114+
.def("set_objective",
115+
nb::overload_cast<const VariableIndex &, ObjectiveSense>(
116+
&COPTModelMixin::set_objective_as_variable),
117+
nb::arg("expr"), nb::arg("sense") = ObjectiveSense::Minimize)
114118
.def("set_objective",
115119
nb::overload_cast<CoeffT, ObjectiveSense>(&COPTModelMixin::set_objective_as_constant),
116120
nb::arg("expr"), nb::arg("sense") = ObjectiveSense::Minimize)
@@ -180,6 +184,11 @@ NB_MODULE(copt_model_ext, m)
180184
BIND_F(set_normalized_coefficient)
181185
BIND_F(get_objective_coefficient)
182186
BIND_F(set_objective_coefficient)
187+
188+
BIND_F(computeIIS)
189+
BIND_F(_get_variable_upperbound_IIS)
190+
BIND_F(_get_variable_lowerbound_IIS)
191+
BIND_F(_get_constraint_IIS)
183192
// clang-format on
184193
;
185194
}

lib/gurobi_model.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -956,6 +956,12 @@ void GurobiModel::_converttofixed()
956956
check_error(error);
957957
}
958958

959+
void GurobiModel::computeIIS()
960+
{
961+
int error = gurobi::GRBcomputeIIS(m_model.get());
962+
check_error(error);
963+
}
964+
959965
int GurobiModel::_constraint_index(const ConstraintIndex &constraint)
960966
{
961967
_update_for_constraint_index(constraint.type);

lib/gurobi_model_ext.cpp

Lines changed: 52 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -38,19 +38,19 @@ NB_MODULE(gurobi_model_ext, m)
3838
.def(nb::init<>())
3939
.def(nb::init<const GurobiEnv &>())
4040
// clang-format off
41-
BIND_F(init)
42-
BIND_F(write)
41+
BIND_F(init)
42+
BIND_F(write)
4343
// clang-format on
4444

4545
.def("add_variable", &GurobiModelMixin::add_variable,
4646
nb::arg("domain") = VariableDomain::Continuous, nb::arg("lb") = -GRB_INFINITY,
4747
nb::arg("ub") = GRB_INFINITY, nb::arg("name") = "")
4848
// clang-format off
49-
BIND_F(delete_variable)
50-
BIND_F(delete_variables)
51-
BIND_F(is_variable_active)
49+
BIND_F(delete_variable)
50+
BIND_F(delete_variables)
51+
BIND_F(is_variable_active)
5252
// clang-format on
53-
.def("set_variable_bounds", &GurobiModelMixin::set_variable_bounds, nb::arg("variable"),
53+
.def("set_variable_bounds", &GurobiModelMixin::set_variable_bounds, nb::arg("variable"),
5454
nb::arg("lb"), nb::arg("ub"))
5555

5656
.def("get_value",
@@ -122,6 +122,10 @@ NB_MODULE(gurobi_model_ext, m)
122122
nb::overload_cast<const ExprBuilder &, ObjectiveSense>(
123123
&GurobiModelMixin::set_objective),
124124
nb::arg("expr"), nb::arg("sense") = ObjectiveSense::Minimize)
125+
.def("set_objective",
126+
nb::overload_cast<const VariableIndex &, ObjectiveSense>(
127+
&GurobiModelMixin::set_objective_as_variable),
128+
nb::arg("expr"), nb::arg("sense") = ObjectiveSense::Minimize)
125129
.def(
126130
"set_objective",
127131
nb::overload_cast<CoeffT, ObjectiveSense>(&GurobiModelMixin::set_objective_as_constant),
@@ -144,12 +148,12 @@ NB_MODULE(gurobi_model_ext, m)
144148
&GurobiModelMixin::cb_add_user_cut),
145149
nb::arg("expr"), nb::arg("sense"), nb::arg("rhs"))
146150

147-
.def("optimize", &GurobiModelMixin::optimize, nb::call_guard<nb::gil_scoped_release>())
151+
.def("optimize", &GurobiModelMixin::optimize, nb::call_guard<nb::gil_scoped_release>())
148152

149153
// clang-format off
150-
BIND_F(update)
151-
BIND_F(version_string)
152-
BIND_F(get_raw_model)
154+
BIND_F(update)
155+
BIND_F(version_string)
156+
BIND_F(get_raw_model)
153157

154158
BIND_F(set_callback)
155159
BIND_F(cb_get_info_int)
@@ -160,42 +164,42 @@ NB_MODULE(gurobi_model_ext, m)
160164
BIND_F(cb_submit_solution)
161165
BIND_F(cb_exit)
162166

163-
BIND_F(raw_parameter_type)
164-
BIND_F(set_raw_parameter_int)
165-
BIND_F(set_raw_parameter_double)
166-
BIND_F(set_raw_parameter_string)
167-
BIND_F(get_raw_parameter_int)
168-
BIND_F(get_raw_parameter_double)
169-
BIND_F(get_raw_parameter_string)
170-
171-
BIND_F(raw_attribute_type)
172-
173-
BIND_F(set_model_raw_attribute_int)
174-
BIND_F(set_model_raw_attribute_double)
175-
BIND_F(set_model_raw_attribute_string)
176-
BIND_F(get_model_raw_attribute_int)
177-
BIND_F(get_model_raw_attribute_double)
178-
BIND_F(get_model_raw_attribute_string)
179-
BIND_F(get_model_raw_attribute_vector_double)
180-
BIND_F(get_model_raw_attribute_list_double)
181-
182-
BIND_F(set_variable_raw_attribute_int)
183-
BIND_F(set_variable_raw_attribute_char)
184-
BIND_F(set_variable_raw_attribute_double)
185-
BIND_F(set_variable_raw_attribute_string)
186-
BIND_F(get_variable_raw_attribute_int)
187-
BIND_F(get_variable_raw_attribute_char)
188-
BIND_F(get_variable_raw_attribute_double)
189-
BIND_F(get_variable_raw_attribute_string)
190-
191-
BIND_F(set_constraint_raw_attribute_int)
192-
BIND_F(set_constraint_raw_attribute_char)
193-
BIND_F(set_constraint_raw_attribute_double)
194-
BIND_F(set_constraint_raw_attribute_string)
195-
BIND_F(get_constraint_raw_attribute_int)
196-
BIND_F(get_constraint_raw_attribute_char)
197-
BIND_F(get_constraint_raw_attribute_double)
198-
BIND_F(get_constraint_raw_attribute_string)
167+
BIND_F(raw_parameter_type)
168+
BIND_F(set_raw_parameter_int)
169+
BIND_F(set_raw_parameter_double)
170+
BIND_F(set_raw_parameter_string)
171+
BIND_F(get_raw_parameter_int)
172+
BIND_F(get_raw_parameter_double)
173+
BIND_F(get_raw_parameter_string)
174+
175+
BIND_F(raw_attribute_type)
176+
177+
BIND_F(set_model_raw_attribute_int)
178+
BIND_F(set_model_raw_attribute_double)
179+
BIND_F(set_model_raw_attribute_string)
180+
BIND_F(get_model_raw_attribute_int)
181+
BIND_F(get_model_raw_attribute_double)
182+
BIND_F(get_model_raw_attribute_string)
183+
BIND_F(get_model_raw_attribute_vector_double)
184+
BIND_F(get_model_raw_attribute_list_double)
185+
186+
BIND_F(set_variable_raw_attribute_int)
187+
BIND_F(set_variable_raw_attribute_char)
188+
BIND_F(set_variable_raw_attribute_double)
189+
BIND_F(set_variable_raw_attribute_string)
190+
BIND_F(get_variable_raw_attribute_int)
191+
BIND_F(get_variable_raw_attribute_char)
192+
BIND_F(get_variable_raw_attribute_double)
193+
BIND_F(get_variable_raw_attribute_string)
194+
195+
BIND_F(set_constraint_raw_attribute_int)
196+
BIND_F(set_constraint_raw_attribute_char)
197+
BIND_F(set_constraint_raw_attribute_double)
198+
BIND_F(set_constraint_raw_attribute_string)
199+
BIND_F(get_constraint_raw_attribute_int)
200+
BIND_F(get_constraint_raw_attribute_char)
201+
BIND_F(get_constraint_raw_attribute_double)
202+
BIND_F(get_constraint_raw_attribute_string)
199203

200204
BIND_F(get_normalized_rhs)
201205
BIND_F(set_normalized_rhs)
@@ -205,6 +209,8 @@ NB_MODULE(gurobi_model_ext, m)
205209
BIND_F(set_objective_coefficient)
206210

207211
BIND_F(_converttofixed)
212+
213+
BIND_F(computeIIS)
208214
// clang-format on
209215
;
210216
}

lib/highs_model_ext.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ NB_MODULE(highs_model_ext, m)
104104
"set_objective",
105105
nb::overload_cast<const ExprBuilder &, ObjectiveSense>(&HighsModelMixin::set_objective),
106106
nb::arg("expr"), nb::arg("sense") = ObjectiveSense::Minimize)
107+
.def("set_objective",
108+
nb::overload_cast<const VariableIndex &, ObjectiveSense>(
109+
&HighsModelMixin::set_objective_as_variable),
110+
nb::arg("expr"), nb::arg("sense") = ObjectiveSense::Minimize)
107111
.def("set_objective",
108112
nb::overload_cast<CoeffT, ObjectiveSense>(&HighsModelMixin::set_objective_as_constant),
109113
nb::arg("expr"), nb::arg("sense") = ObjectiveSense::Minimize)

lib/mosek_model_ext.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ NB_MODULE(mosek_model_ext, m)
106106
"set_objective",
107107
nb::overload_cast<const ExprBuilder &, ObjectiveSense>(&MOSEKModelMixin::set_objective),
108108
nb::arg("expr"), nb::arg("sense") = ObjectiveSense::Minimize)
109+
.def("set_objective",
110+
nb::overload_cast<const VariableIndex &, ObjectiveSense>(
111+
&MOSEKModelMixin::set_objective_as_variable),
112+
nb::arg("expr"), nb::arg("sense") = ObjectiveSense::Minimize)
109113
.def("set_objective",
110114
nb::overload_cast<CoeffT, ObjectiveSense>(&MOSEKModelMixin::set_objective_as_constant),
111115
nb::arg("expr"), nb::arg("sense") = ObjectiveSense::Minimize)

src/pyoptinterface/_src/attributes.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ class VariableAttribute(Enum):
99
Domain = auto()
1010
PrimalStart = auto()
1111
Name = auto()
12+
IISLowerBound = auto()
13+
IISUpperBound = auto()
1214

1315

1416
var_attr_type_map = {
@@ -18,6 +20,8 @@ class VariableAttribute(Enum):
1820
VariableAttribute.PrimalStart: float,
1921
VariableAttribute.Domain: VariableDomain,
2022
VariableAttribute.Name: str,
23+
VariableAttribute.IISLowerBound: bool,
24+
VariableAttribute.IISUpperBound: bool,
2125
}
2226

2327

@@ -120,10 +124,12 @@ class ConstraintAttribute(Enum):
120124
Primal = auto()
121125
Dual = auto()
122126
# BasisStatus = auto()
127+
IIS = auto()
123128

124129

125130
constraint_attr_type_map = {
126131
ConstraintAttribute.Name: str,
127132
ConstraintAttribute.Primal: float,
128133
ConstraintAttribute.Dual: float,
134+
ConstraintAttribute.IIS: bool,
129135
}

0 commit comments

Comments
 (0)