Loading...
Searching...
No Matches
Models

Describes how models are represented in idol.

What is a Model and What Can You Do with It?

Mathematical optimization problems are modeled using the Model class. A model consists of a collection of variables and constraints together with an objective function. It is created by invoking the constructor of Model and passing an environment as its first argument.

Env env;
Model model(env); // Creates an empty model.

Here, we first create a new optimization environment, then create an optimization model. Note that the newly created model does not yet contain any variable or constraint. All models are treated as minimization problems. This is not a real restriction, however, since \( \max_{x\in X} f(x) = - \min_{x\in X} -f(x) \) holds for any function \( f \) and any set \( X \).

Another way to create a model is by importing it from an .mps or an .lp file. To do this, you will need to rely on an external solver. In what follows, we use GLPK, which is an open-source solver which can be easily installed on your computer.

Env env;
auto model = GLPK::read_from_file("/path/to/some/file.mps");

The decision to rely on external solvers is justified by two main considerations. First, idol is typically used in combination with such solvers anyway to efficiently solve optimization problems. Second, it is generally safer to leverage well-established solver implementations, which have been extensively tested over many years, to handle any mistake or ambiguity.

Now that we have a model imported, we can safely iterate over its variables and constraints. This can be done as follows.

for (const auto& var : model.vars()) {
std::cout << var.name() << std::endl;
}

Here, we use the Model::vars method to get access to the variables of the model and write down their names. Note that you can also use the operator<<(std::ostream\&, const Model\&) function to print the model to the console, or to a file. This can be useful for debugging.

Once we have iterated over the variables, we may want to iterate over constraints as well. To do so, we can use the Model::ctrs method for linear constraints, the Model::qctrs method for quadratic constraints, and the Model::sosctrs() method for SOS-type constraints. The next code snippet shows how to get the number of variables and constraints in the model.

std::cout << "N. of vars: " << model.vars().size() << '\n';
std::cout << "N. of linear ctrs: " << model.ctrs().size() << '\n';
std::cout << "N. of quad. ctrs: " << model.qctrs().size() << '\n';
std::cout << "N. of SOS ctrs: " << model.sosctrs().size() << '\n';

To obtain model-specific information about a variable, a constraint, or the objective function, idol provides methods of the form Model::get_<X>_<Y>(const <T>&), where X denotes the type of object—such as var, ctr, qctr, sosctr, or obj, and Y specifies the particular attribute to access, for example lb, type, or column for variables. To give a specific example, the following code snippet counts the number of binary variables in the model.

unsigned int n_binary_vars = 0;
// Iterate over all variables in the model.
for (const auto& var : model.vars()) {
// Get the variable type in this model.
const auto type = model.get_var_type(var);
// Check type is binary.
if (type == Binary) {
++n_binary_vars;
}
}

The complete set of information that can be accessed through a model is described in detail in the respective page, i.e., that on variables, constraints or objective function.

Copying and Moving Models

In most practical situations, it is preferable to avoid copying a model. Instead, one should often pass a reference to it to auxiliary functions. For this reason, the copy constructor of the Model class is declared private. If copying a model is indeed required, the Model::copy method and the move constructor can be used. The following example illustrates this usage.

Model copy_and_relax_integrality(const Model& t_model) {
auto result = t_model.copy();
for (const auto& var : result.vars()) {
result.set_var_type(var, Continuous);
}
return std::move(result);
}
const auto model = Gurobi::read_from_file("problem.lp");
auto continuous_relaxation = copy_and_relax_integrality(model);

Here, continuous_relaxation is now an independent copy of the original model and is being modified without altering its source model.