Model concepts¶
MIP++'s portable interface is specified by C++ concepts, defined in
mippp/model_concepts.hpp.
The model concepts describe what every backend of a given problem class
provides; the capability concepts describe optional features that vary per
backend (see the feature matrices).
Use them to make generic code self-documenting and to fail at compile time instead of at runtime:
template <typename M>
requires milp_model<M> && has_candidate_solution_callback<M>
void solve_tsp(M & model, const instance & data);
static_assert(has_dual_solution<highs_lp>);
Writing solver-generic code shows the patterns; this page is the catalogue.
Every model type also exposes the member types used throughout the interface:
M::variable and M::constraint (lightweight strongly-typed handles),
M::scalar (the coefficient type, double on current backends), and
M::variable_params (the designated-initializer options struct
{.obj_coef, .lower_bound, .upper_bound}). The aliases
model_variable_t<M>, model_constraint_t<M>, model_scalar_t<M> and
model_variable_params_t<M> name them without a typename.
Concept declared ≠ backend provides
A few concepts below are specified but satisfied by no backend yet;
they are marked (no backend yet) and appear on the
roadmap. They are still worth
using today in if constexpr branches and requires clauses — generic
code written against them starts using the native path the day a backend
provides it.
Model concepts¶
| Concept | Requires |
|---|---|
lp_model |
The modeling core: set_minimization / set_maximization; add_variable(s) (with optional variable_params and id-lambdas); set_objective / set_objective_offset; add_constraint / add_constraints; num_variables / num_constraints; solve; solve_status; get_solution / get_solution_value. |
milp_model |
lp_model, plus add_integer_variable(s), add_binary_variable(s), and per-variable type changes set_continuous / set_integer / set_binary. |
qp_model |
lp_model, plus set_objective accepting a quadratic expression. |
sized_model |
num_entries() (number of nonzeros). |
Solve status¶
solve_status() is required by lp_model itself: every model class returns a std::variant over the tag hierarchy of namespace status (optimal and its refinements, infeasible_or_unbounded with its refinements infeasible and unbounded, interrupted, failed, numerical_failure, out_of_memory, limit_reached and its five refinements, unknown). Query it with is<S>(r) (exact tag), is_a<S>(r) (whole branch) and status::solution_available(r); the variant type is model_solve_status_t<M>. Two concepts refine what a given model class can report:
| Concept | Provides |
|---|---|
has_lp_status |
The status variant can report infeasible and unbounded as distinct tags, not only the coarse infeasible_or_unbounded. |
has_refinable_lp_status |
The variant carries the exact infeasible_or_unbounded tag and the model provides refine_lp_status() to resolve it into infeasible or unbounded — possibly by re-solving; a no-op on any other status. |
See Status, limits and tolerances for the hierarchy and how to branch on it.
Limits¶
| Concept | Provides |
|---|---|
has_time_limit |
set_time_limit(std::chrono duration), get_time_limit(). |
has_iteration_limit |
set_iteration_limit(n), get_iteration_limit(). |
has_node_limit |
set_node_limit(n), get_node_limit(). |
has_solution_limit |
set_solution_limit(n), get_solution_limit(). |
has_memory_limit |
set_memory_limit(size) for any memory_size unit, get_memory_limit(). |
Each limit concept additionally requires that the matching status::*_limit
tag is among those the backend's solve_status() can return — a limit you can
set is a limit you can detect.
Solution information¶
| Concept | Provides |
|---|---|
has_dual_solution |
get_dual_solution(), indexed by constraint handles. |
has_reduced_costs |
get_reduced_costs(), indexed by variable handles. |
has_lp_basis |
get_basis(), whose is_basic(v/c) and get_status(v/c) report the LP basis (statuses in namespace basis_status). (no backend yet) |
has_lp_basis_warm_start |
has_lp_basis, plus set_basis(b) and the basis mutators set_basic / set_nonbasic / set_status. (no backend yet) |
Reading and modifying the model¶
| Concept | Provides |
|---|---|
has_readable_objective |
get_objective(), get_objective_coefficient(v), get_objective_offset(). |
has_modifiable_objective |
set_objective_coefficient(v, s), add_objective(expr). |
has_readable_variables_bounds |
get_variable_lower_bound(v), get_variable_upper_bound(v). |
has_modifiable_variables_bounds |
set_variable_lower_bound(v, s), set_variable_upper_bound(v, s). |
has_readable_constraints |
get_constraint(c) plus the three finer-grained concepts has_readable_constraint_lhs / _sense / _rhs. |
has_modifiable_constraint_lhs / _sense / _rhs |
set_constraint_lhs(c, entries), set_constraint_sense(c, s), set_constraint_rhs(c, s). |
See Re-solving and model updates.
Names¶
| Concept | Provides |
|---|---|
has_named_variables |
set_variable_name / get_variable_name, add_named_variable(s) (including the lazily-named id-lambda + name-lambda form). |
has_named_constraints |
set_constraint_name / get_constraint_name. |
Special constraints¶
| Concept | Provides |
|---|---|
has_indicator_constraints |
add_indicator_constraint(v, value, constraint) returning a constraint handle — the constraint holds whenever binary variable v takes value. (no backend yet: gurobi_milp and cplex_milp provide the function, but declare it void, so the concept is false; see Special constraints) |
has_sos1_constraints |
add_sos1_constraint(variables). (no backend yet) |
has_sos2_constraints |
add_sos2_constraint(variables). (no backend yet) |
Algorithmic building blocks¶
| Concept | Provides |
|---|---|
has_add_column |
add_column(entries, params) from (constraint, coefficient) pairs — see Column generation. |
has_remove_variable |
remove_variable(v), remove_variables(range). |
has_mip_start |
add_mip_start(entries) from (variable, value) pairs. |
has_candidate_solution_callback |
set_candidate_solution_callback(f) where f takes the backend's candidate_solution_callback_handle — see Branch-and-cut. |
has_node_relaxation_callback |
set_node_relaxation_callback(f), for user cuts on fractional solutions. (no backend yet) |
Tolerances¶
| Concept | Provides |
|---|---|
has_feasibility_tolerance |
get/set_feasibility_tolerance. |
has_optimality_tolerance |
get/set_optimality_tolerance. |
has_integrality_tolerance |
get/set_integrality_tolerance. (no backend yet) |
Expression concepts¶
The expression layer has concepts of its own, defined in
linear_expression.hpp
and
linear_constraint.hpp:
linear_expression— anything withlinear_terms()(a range of(variable, coefficient)pairs) andconstant(). Variable handles,xsumresults, and operator combinations all satisfy it, and model functions accept any type that does — you can pass your own expression types.linear_constraint— anything withlinear_terms(),sense()(constraint_sense::less_equal/equal/greater_equal), andrhs().
These are the extension points: a function like add_constraint is written
against the concept, never against a concrete expression class. Their
sub-concepts — ownership, multipass, and the diagnostics they drive — are
covered in Inside the expression layer.