5 Design Overview

5.1 Modeling

Optimizer API for Rust is an interface for specifying optimization problems directly in matrix form. It means that an optimization problem such as:

\[\begin{split}\begin{array}{ll} \minimize & c^Tx \\ \st & Ax\leq b,\\ & x\in \mathcal{K} \end{array}\end{split}\]

is specified by describing the matrix \(A\), vectors \(b,c\) and a list of cones \(\mathcal{K}\) directly.

The main characteristics of this interface are:

  • Simplicity: once the problem data is assembled in matrix form, it is straightforward to input it into the optimizer.

  • Exploiting sparsity: data is entered in sparse format, enabling huge, sparse problems to be defined and solved efficiently.

  • Efficiency: the Optimizer API incurs almost no overhead between the user’s representation of the problem and MOSEK’s internal one.

Optimizer API for Rust does not aid with modeling. It is the user’s responsibility to express the problem in MOSEK’s standard form, introducing, if necessary, auxiliary variables and constraints. See Sec. 12 (Problem Formulation and Solutions) for the precise formulations of problems MOSEK solves.

5.2 “Hello World!” in MOSEK

Here we present the most basic workflow pattern when using Optimizer API for Rust.

Creating an environment and task

Optionally, an interaction with MOSEK using Optimizer API for Rust can begin by creating a MOSEK environment. It coordinates the access to MOSEK from the current process.

In most cases the user does not interact directly with the environment, except for creating optimization tasks, which contain actual problem specifications and where optimization takes place. In this case the user can directly create tasks without invoking an environment, as we do here.

Defining tasks

After a task is created, the input data can be specified. An optimization problem consists of several components; objective, objective sense, constraints, variable bounds etc. See Sec. 6 (Optimization Tutorials) for basic tutorials on how to specify and solve various types of optimization problems.

Retrieving the solutions

When the model is set up, the optimizer is invoked with the call to Task.optimize. When the optimization is over, the user can check the results and retrieve numerical values. See further details in Sec. 7 (Solver Interaction Tutorials).

We refer also to Sec. 7 (Solver Interaction Tutorials) for information about more advanced mechanisms of interacting with the solver.

Source code example

Below is the most basic code sample that defines and solves a trivial optimization problem

\[\begin{split}\begin{array}{ll} \minimize & x \\ \st & 2.0 \leq x \leq 3.0. \\ \end{array}\end{split}\]

For simplicity the example does not contain any error or status checks.

Listing 5.1 “Hello World!” in MOSEK
//!
//!  Copyright : Copyright (c) MOSEK ApS, Denmark. All rights reserved.
//!
//!  File : helloworld.rs
//!
//!  The most basic example of how to get started with MOSEK.
//!

extern crate mosek;

use mosek::{Task,Boundkey,Objsense,Soltype};

fn main() -> Result<(),String> {
    /* Create the optimization task. */
    let mut task = match Task::new() {
        Some(e) => e,
        None => return Err("Failed to create task".to_string()),
        };

    task.append_vars(1)?;                           // 1 variable x
    task.put_c_j(0, 1.0)?;                          // c_0 = 1.0
    task.put_var_bound(0, Boundkey::RA, 2.0, 3.0)?; // 2.0 <= x <= 3.0
    task.put_obj_sense(Objsense::MINIMIZE)?;        // minimize

    task.optimize()?;                               // Optimize

    let mut x = vec![0.0; 1];
    task.get_xx(Soltype::ITR, x.as_mut_slice())?;   // Get solution
    println!("Solution x = {}", x[0]);              // Print solution
    return Result::Ok(());
}

#[cfg(test)]
mod tests {
    #[test]
    fn test() {
        super::main().unwrap();
    }
}