Expand description
§MosekModel library
MosekModel is a crate for setting up conic optimization models. The crate does not directly link to a solver - these links are implemented in separate crates, currently:
mosekcomodel_moseka backend for MOSEK via mosek.rust, supporting- Linear and conic variables and constraints
- Integer variables
- Disjunctive constraints
mosekcomodel_highsa backend for HIGHS, supporting- Linear constraints
- Integer Variables The crate defines a dummy backend that allows inputting data, but cannot solve, write or do anything useful with it.
The [Model] object encapsulates a model of the form $$ \begin{array}{ll} \mathrm{min/max} & c^t x \\ \mathrm{such\ that} & A x + b \in K_c\\ & X \in K_x \end{array} $$
where \(K_c = K_{c_0}\times\cdots\times K_{c_m}\), \(K_x = K_{x_0} \times\cdots\times K_{x_n}\), each \(K_{c_i}\) and \(K_{x_i}\) is a conic domain from the currently supported set plus an offset:
- Non-positive or non-negative orthant (see nonpositive, nonnegative, less_than and greater_than).
- Unbounded values (see unbounded).
- Fixed values (see zero and equal_to)
- Second order cone(s) (see in_quadratic_cone, in_quadratic_cones): $$ \left\{ x \in R^n | x_1^2 \geq \left\Vert x_2^2 + \cdots + x_n^2 \right\Vert^2, x₁ \geq 0 \right\} $$
- Rotated second order cone(s) (see in_rotated_quadratic_cone, in_rotated_quadratic_cones): $$ \left\{ x \in R^n | \frac{1}{2} x_1 x_2 \geq \left\Vert x_3^2 + \cdots + x_n^2 \right\Vert^2, x_1, x_2 \geq 0 \right\} $$
- Primal power cone(s) (see in_power_cone, in_power_cones): $$ \left\{ x \in R^n | x_2^{\beta_1} \cdots x_k^{\beta_k} \geq \sqrt{x_{k+1}^2 \cdots x_n^2}, x_0,\ldots, x_k \geq 0 \right\} $$
- Dual power cone(s) (see in_dual_power_cone, in_dual_power_cones): $$ \left\{ x \in R^n | (x_1/\beta_1)^{\beta_1} \cdots (x_k)^{\beta_k} \geq \sqrt{x_{k+1}^2 \cdots x_n^2}, x_0,\ldots, x_k \geq 0 \right\} $$
- Primal exponential cone(s) (see in_exponential_cone, in_exponential_cones): $$ \left\{ x \in R^3 | x_1 \geq x_1 e^{x_3/x_2}, x_0, x_1 \geq 0 \right\} $$
- Dual exponential cone(s) (see in_dual_exponential_cone, in_dual_exponential_cones): $$ \left\{ x \in R^3 | x_1 \geq -x_3 e^{-1} e^{x_2/x_3}, x_3 \geq 0, x_1 \geq 0 \right\} $$
- Primal geometric mean cone(s) (see in_geometric_mean_cone, in_geometric_mean_cones): $$ \left\{ x \in R^n| (x_1\cdots x_{n-1})^{1/(n-1)} |x_n|, x_1,\ldots,x_{n-1} \geq 0\right\} $$
- Dual geometric mean cone(s) (see in_dual_geometric_mean_cone, in_dual_geometric_mean_cones): $$ \left\{ x \in R^n | (n-1)(x_1 \cdots x_{n-1})^{1/(n-1)} |x_n|, x_1,\ldots,x_{n-1} \geq 0\right\} $$
- Scaled vectorized positive semidefinite cone(s) (see in_svecpsd_cone, in_svecpsd_cones). For a
ndimensional positive symmetric matrix this is the scaled lower triangular part of the matrix in column-major format, i.e. $$ \left\{ x \in R^{n(n+1)/2} | \mathrm{sMat}(x) \in S_+^n \right\} $$ where $$ \mathrm{sMat}(x) = \left[ \begin{array}{cccc} x_1 & x_2/\sqrt{2} & \cdots & x_n/\sqrt{2} \\ x_2/\sqrt{2} & x_n+1 & \cdots & x_{2n-1}/\sqrt{2} \\ & & \cdots & \\ x_n/\sqrt{2} & x_{2n-1}/\sqrt{2} & \cdots & x_{n(n+1_/2}^2 \end{array} \right] $$ - Symmetric positive semidefinite cones $$ X \in \mathcal{S}^n_+ $$
§Expressions and shapes
The central traits for expressions are ExprTrait, which all objects that must act as
expressions have to implement, and IntoExpr which is anything that can be turned into an
ExprTrait. For example, Variable Vec<f64>, f64 and NDArray implement IntoExpr since
they can be turned into a expression, while the various expression structs (e.g. Expr,
expr::ExprAdd, expr::ExprStack etc.) implement ExprTrait. Note that expressions are consumed when
creating new expressions, while variables and constants can be passed by reference and will be
cloned. This is because the expression constructing functions accept IntoExprs rather than
ExprTraits. For example, an add function might look like this:
use mosekcomodel::{ExprTrait,IntoExpr};
struct ExprAdd<const N : usize,E1,E2>
where
E1 : ExprTrait<N>,
E2 : ExprTrait<N>
{
e1 : E1,
e2 : E2
}
fn add<const N : usize, E1,E2>( e1 : E1, e2 : E2 ) -> ExprAdd<N,E1::Result,E2::Result>
where E1 : IntoExpr<N>,
E2 : IntoExpr<N>
{
ExprAdd{
e1 : e1.into_expr(),
e2 : e2.into_expr()
}
}Now, when IntoExpr is implemented for all ExprTrait, as well as for both &Variable<N> and
for Variable<N>, we can pass an expression, a variable or a variable reference to the
function.
Constraint, domains, variables and expressions have shapes, and the latter three can be either dense or sparse meanning that some entries are fixed to zero. A shaped variable, expression and constraint is basically a multi-dimensional array of scalar variables, affine expressions and scalar constraints respectively.
When reshaping an object it is important to understand the order of the scalar elements in the
multi-dimensional array. In MosekModel everything is in row-major order, i.e. for a
two-dimensional array, where the first dimension is the height and the second is the width
$$
\left[\begin{array}{cc} a & b \\ c & d \end{array}\right]
$$
the elements are ordered as [a,b,c,d]. More generally, elements are ordered by inner
dimension first.
A scalar is an n-dimensional object with n=0.
In MosekModel the dimension of variables, constraints, expressions and domains are part of
the object type, so only correct combinations of dimensionality are allowed. The actual shapes
still have to be checked at runtime.
§Domains
A domain is an object that indicates things like type (cone type or domain type), cone parameters, right-hand sides, shape and sparsity pattern. This is used when creating constraint or variables to define their properties. Normally, the domain is not created directly, but rather an object implementing IntoDomain (for variables) or IntoShapedDomain (for constraints) is created and passed to the relevant function that will then validate it. Such an object may be incomplete and even inconsistent. It is completed and validated when used to create varibles and constraints.
§Constraints and Variables
Variables and constraints are created through the [Model] object. Functions creating variables
and constraints have two versions, a try_ and a plain version. The former will return a
Result::Err whenever an error was encountered that left the [Model] in a consistent state.
The latter version will panic! on any error.
§Variables
When a Variable is created in a model as [Model::variable], the model adds the necessary internal information to map a linear variable index to something in the underlying task, but after that, a variable is essentially a list of indexes of the scalar variables t a shape and sparsity. Variable objects can be stacked, indexed and sliced to obtain new variable objects.
When a model has been optimized, the variable object is used to access the parts of the solution it represents through the [Model] object.
§Constraints
A constraint is created in a [Model] from an expression (something implementing ExprTrait) and a domain using [Model::constraint]. The sparsity pattern of the domain is ignored, and a constraint is always dense. When a constraint has been created it can be indexed, sliced and stacked like a variable, and it can be used to access the relevant parts of the solution through the [Model] object.
§Expression
An expression is an n-dimensional array of scalar affine expressions. Anything that implements
the trait ExprTrait can be used as an N-dimensional expression.
§Note
Please note that the package is still somewhat exprimental.
§Example: lo1
Simple linear example:
// Importing everything from mosekcomodel provides all basic functionality.
use mosekcomodel::*;
use mosekcomodel::dummy::Model;
// Create a model with the name 'lo1'
let mut m = Model::new(Some("lo1"));
let a0 = vec![ 3.0, 1.0, 2.0, 0.0 ];
let a1 = vec![ 2.0, 1.0, 3.0, 1.0 ];
let a2 = vec![ 0.0, 2.0, 0.0, 3.0 ];
let c = vec![ 3.0, 1.0, 5.0, 1.0 ];
// Redirect log output from the solver to stdout for debugging.
// if uncommented.
m.set_log_handler(|msg| print!("{}",msg));
// Create variable 'x' of length 4
let x = m.variable(Some("x"), greater_than(vec![0.0,0.0,0.0,0.0]));
// Create constraints
_ = m.constraint(None, x.index(1), less_than(10.0));
_ = m.constraint(Some("c1"), x.dot(a0.as_slice()), equal_to(30.0));
_ = m.constraint(Some("c2"), x.dot(a1.as_slice()), greater_than(15.0));
_ = m.constraint(Some("c3"), x.dot(a2.as_slice()), less_than(25.0));
// Set the objective function to (c^t * x)
m.objective(Some("obj"), Sense::Maximize, x.dot(c.as_slice()));The project does not include a solver directly, but it is possible to solve (currently linear-only) models by using the OptServer backend to offload to a MOSEK OptServer instance, for example solve.mosek.com:30080 or an instance running locally:
use mosekcomodel::*;
use mosekcomodel::optserver::Model;
let mut m = Model::new(Some("lo1"));
// ...
let x = m.variable(Some("x"), greater_than(vec![0.0,0.0,0.0,0.0]));
// ...
m.set_parameter((), optserver::SolverAddress("solve.mosek.com:30080".to_string()));
m.solve();
let (psta,dsta) = m.solution_status(SolutionType::Default);
println!("Status = {:?}/{:?}",psta,dsta);
let xx = m.primal_solution(SolutionType::Default,&x);
println!("x = {:?}", xx);
§Example: portfolio_1_basic
Example using second order cones to model risk in a basic portfolio model.
use mosekcomodel::*;
use mosekcomodel::dummy::Model;
// Computes the optimal portfolio for a given risk
//
// # Arguments
// * `n` Number of assets
// * `mu` An n dimmensional vector of expected returns
// * `gt` A matrix with n columns so (GT')*GT = covariance matrix
// * `x0` Initial holdings
// * `w` Initial cash holding
// * `gamma` Maximum risk (=std. dev) accepted
fn basic_markowitz( n : usize,
mu : &[f64],
gt : &NDArray<2>,
x0 : &[f64],
w : f64,
gamma : f64) -> Model {
let mut model = Model::new(Some("Basic Markowitz"));
// Redirect log output from the solver to stdout for debugging.
// if uncommented.
model.set_log_handler(|msg| print!("{}",msg));
// Defines the variables (holdings). Shortselling is not allowed.
let x = model.variable(Some("x"), greater_than(vec![0.0;n]));
// Maximize expected return
model.objective(Some("obj"), Sense::Maximize, x.dot(mu));
// The amount invested must be identical to intial wealth
model.constraint(Some("budget"), x.sum(), equal_to(w+x0.iter().sum::<f64>()));
// Imposes a bound on the risk
model.constraint(Some("risk"),
vstack![Expr::from(gamma).reshape(&[1]),
gt.mul(&x)], in_quadratic_cone());
model
}
const N : usize = 8;
const W : f64 = 59.0;
let mu = [0.07197349, 0.15518171, 0.17535435, 0.0898094 , 0.42895777, 0.39291844, 0.32170722, 0.18378628];
let x0 = [8.0, 5.0, 3.0, 5.0, 2.0, 9.0, 3.0, 6.0];
let gamma = 36.0;
let GT = matrix::dense([N,N],vec![
0.30758, 0.12146, 0.11341, 0.11327, 0.17625, 0.11973, 0.10435, 0.10638,
0. , 0.25042, 0.09946, 0.09164, 0.06692, 0.08706, 0.09173, 0.08506,
0. , 0. , 0.19914, 0.05867, 0.06453, 0.07367, 0.06468, 0.01914,
0. , 0. , 0. , 0.20876, 0.04933, 0.03651, 0.09381, 0.07742,
0. , 0. , 0. , 0. , 0.36096, 0.12574, 0.10157, 0.0571 ,
0. , 0. , 0. , 0. , 0. , 0.21552, 0.05663, 0.06187,
0. , 0. , 0. , 0. , 0. , 0. , 0.22514, 0.03327,
0. , 0. , 0. , 0. , 0. , 0. , 0. , 0.2202 ]);
_ = basic_markowitz( N, &mu, >, &x0, W, gamma);Re-exports§
pub use constraint::Constraint;pub use constraint::ConstraintDomain;pub use model::Sense;pub use model::SolutionType;pub use model::SolutionStatus;pub use model::ModelItem;pub use model::ModelItemIndex;pub use model::VarDomainTrait;pub use model::SolverParameterValue;pub use model::BaseModelTrait;pub use model::VectorConeModelTrait;pub use model::PSDModelTrait;pub use model::ModelAPI;pub use model::Solution;pub use matrix::Matrix;pub use matrix::NDArray;pub use matrix::IntoIndexes;pub use expr::ExprTrait;pub use expr::ExprRightMultipliable;pub use expr::ExprLeftMultipliable;pub use expr::ModelExprIndex;pub use expr::IntoExpr;pub use expr::Expr;pub use expr::RightDottable;pub use expr::stack;pub use expr::hstack;pub use expr::vstack;pub use expr::stackvec;pub use expr::sumvec;pub use variable::Variable;pub use domain::IntoDomain;pub use domain::IntoShapedDomain;pub use domain::LinearDomain;pub use domain::VectorDomain;pub use domain::PSDDomain;pub use domain::LinearDomainType;pub use domain::VectorDomainTrait;pub use domain::OffsetTrait;pub use domain::LinearRangeDomain;pub use domain::ScalablePSDDomain;pub use domain::ScalableVectorDomain;pub use domain::ScalableLinearRange;pub use domain::LinearProtoDomain;pub use domain::PSDProtoDomain;pub use domain::VectorProtoDomain;pub use domain::unbounded;pub use domain::less_than;pub use domain::greater_than;pub use domain::nonnegative;pub use domain::nonpositive;pub use domain::zero;pub use domain::zeros;pub use domain::equal_to;pub use domain::in_quadratic_cone;pub use domain::in_quadratic_cones;pub use domain::in_svecpsd_cone;pub use domain::in_svecpsd_cones;pub use domain::in_rotated_quadratic_cone;pub use domain::in_rotated_quadratic_cones;pub use domain::in_geometric_mean_cone;pub use domain::in_geometric_mean_cones;pub use domain::in_dual_geometric_mean_cone;pub use domain::in_dual_geometric_mean_cones;pub use domain::in_exponential_cone;pub use domain::in_exponential_cones;pub use domain::in_dual_exponential_cone;pub use domain::in_dual_exponential_cones;pub use domain::in_power_cone;pub use domain::in_power_cones;pub use domain::in_dual_power_cone;pub use domain::in_dual_power_cones;pub use domain::in_psd_cone;pub use domain::in_psd_cones;pub use domain::in_range;pub use disjunction::ConjunctionTrait;pub use disjunction::DisjunctionTrait;
Modules§
- constraint
- disjunction
- Structures and functions for formulating disjunctive constraints.
- domain
- This module and the submodules define domain functionality.
- dummy
- This module implements a dummy backend that allows inputting data, but has no support for solving or writing data.
- experimental
- This module defines various experimental exprssions whose usefulness has not been determined yet.
- expr
- The expression building operations are used to generate linear expressions for constraints. The vast majority is implemented in ExprTrait and public functions.
- matrix
- This module provides basic array functionality.
- model
- optserver
- This module implements a backend that uses a MOSEK OptServer instance for solving, for example solve.mosek.com:30080.
- utils
- variable
- Module for Variable object and related implementations