1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
/*!
Totsu ([凸](http://www.decodeunicode.org/en/u+51F8) in Japanese) means convex.

<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>

This crate for Rust provides **a first-order conic linear program solver**.

# Target problem

A common target problem is continuous scalar **convex optimization** such as LP, QP, QCQP, SOCP and SDP.
Each of those problems can be represented as a conic linear program:
\\[
\begin{array}{ll}
{\rm minimize} & c^T x \\\\
{\rm subject \ to} & A x + s = b \\\\
& s \in \mathcal{K},
\end{array}
\\]
where
* variables \\( x \in \mathbb{R}^n,\ s \in \mathbb{R}^m \\)
* \\( c \in \mathbb{R}^n \\) as an objective linear operator 
* \\( A \in \mathbb{R}^{m \times n} \\) and \\( b \in \mathbb{R}^m \\) as constraint linear operators 
* a nonempty, closed, convex cone \\( \mathcal{K} \\).

# Algorithm and design concepts

The author combines the two papers
[\[1\]](https://ieeexplore.ieee.org/abstract/document/6126441)
[\[2\]](https://arxiv.org/abs/1312.3039)
so that the homogeneous self-dual embedding matrix in [\[2\]](https://arxiv.org/abs/1312.3039)
is formed as a linear operator in [\[1\]](https://ieeexplore.ieee.org/abstract/document/6126441).

A core method [`solver::Solver::solve`] takes the following arguments:
* objective and constraint linear operators that implement [`operator::Operator`] trait and
* a projection onto a cone that implements [`cone::Cone`] trait.

Therefore solving a specific problem requires an implementation of those traits.
You can use pre-defined implementations (see [`problem`]),
as well as construct a user-defined tailored version for the reason of functionality and efficiency.
Modules [`operator`] and [`cone`] include several basic structs
that implement [`operator::Operator`] and [`cone::Cone`] trait.

Core linear algebra operations that [`solver::Solver`] requires
are abstracted by [`linalg::LinAlg`] trait,
while subtrait [`linalg::LinAlgEx`] is used for [`operator`],
[`cone`] and [`problem`] modules.
This crate includes two [`linalg::LinAlgEx`] implementors:
* [`linalg::FloatGeneric`] -
  `num::Float`-generic implementation (pure Rust but slow)
* [`linalg::F64LAPACK`] -
  `f64`-specific implementation using `cblas-sys` and `lapacke-sys`.

## Features

### Using [`linalg::F64LAPACK`]

```toml
[dependencies.totsu]
version = "0.8.0"
features = ["f64lapack"]
```

In addition you need a
[BLAS/LAPACK source](https://github.com/blas-lapack-rs/blas-lapack-rs.github.io/wiki#sources) to link.

### Without `std`

This crate can be used without the standard library (`#![no_std]`).
Use this in `Cargo.toml`:

```toml
[dependencies.totsu]
version = "0.8.0"
default-features = false
features = ["libm"]
```

Some module and structs are not availale in this case:
* [`problem`]
* [`operator::MatBuild`]

## Changelog

Changelog is available in [CHANGELOG.md](https://github.com/convexbrain/Totsu/blob/master/solver_rust_conic/CHANGELOG.md).

# Examples
## QP

```
# #[cfg(feature = "f64lapack")]
# use intel_mkl_src as _;
use float_eq::assert_float_eq;
use totsu::prelude::*;
use totsu::operator::MatBuild;
use totsu::problem::ProbQP;

//env_logger::init();

type LA = FloatGeneric<f64>;
type AMatBuild = MatBuild<LA, f64>;
type AProbQP = ProbQP<LA, f64>;
type ASolver = Solver<LA, f64>;

let n = 2; // x0, x1
let m = 1;
let p = 0;

// (1/2)(x - a)^2 + const
let mut sym_p = AMatBuild::new(MatType::SymPack(n));
sym_p[(0, 0)] = 1.;
sym_p[(1, 1)] = 1.;

let mut vec_q = AMatBuild::new(MatType::General(n, 1));
vec_q[(0, 0)] = -(-1.); // -a0
vec_q[(1, 0)] = -(-2.); // -a1

// 1 - x0/b0 - x1/b1 <= 0
let mut mat_g = AMatBuild::new(MatType::General(m, n));
mat_g[(0, 0)] = -1. / 2.; // -1/b0
mat_g[(0, 1)] = -1. / 3.; // -1/b1

let mut vec_h = AMatBuild::new(MatType::General(m, 1));
vec_h[(0, 0)] = -1.;

let mat_a = AMatBuild::new(MatType::General(p, n));

let vec_b = AMatBuild::new(MatType::General(p, 1));

let s = ASolver::new().par(|p| {
   p.max_iter = Some(100_000);
});
let mut qp = AProbQP::new(sym_p, vec_q, mat_g, vec_h, mat_a, vec_b, s.par.eps_zero);
let rslt = s.solve(qp.problem()).unwrap();

assert_float_eq!(rslt.0[0..2], [2., 0.].as_ref(), abs_all <= 1e-3);
```

## Other examples

You can find other [tests](https://github.com/convexbrain/Totsu/tree/master/solver_rust_conic/tests) of pre-defined problems.
More practical [examples](https://github.com/convexbrain/Totsu/tree/master/examples) are also available.

## References

1. T. Pock and A. Chambolle.
   "Diagonal preconditioning for first order primal-dual algorithms in convex optimization."
   2011 International Conference on Computer Vision. IEEE, 2011.
1. B. O’donoghue, et al.
   "Conic optimization via operator splitting and homogeneous self-dual embedding."
   Journal of Optimization Theory and Applications 169.3 (2016): 1042-1068.
1. N. Parikh and S. Boyd.
   "Proximal algorithms."
   Foundations and Trends in optimization 1.3 (2014): 127-239.
1. Mosek ApS.
   "MOSEK modeling cookbook."
   (2020).
1. S. Boyd and L. Vandenberghe.
   "Convex Optimization."
   (2004).
*/

#![no_std]
#[cfg(feature = "std")]
extern crate std;

pub mod solver; // core, Float
mod utils;

pub mod linalg;
pub mod operator;
pub mod cone;

#[cfg(feature = "std")]
pub mod problem;

/// Prelude
pub mod prelude // core, Float
{
    pub use super::solver::{Solver, SolverError, SolverParam};
    pub use super::linalg::{LinAlg, LinAlgEx, FloatGeneric};
    pub use super::operator::{Operator, MatType, MatOp};
    pub use super::cone::{Cone, ConeZero, ConeRPos, ConeSOC, ConePSD};
}

// TODO: more tests