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
// Copyright 2018 Paul Scott
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Model interface for solvers.
use crate::expr::{Expression, Par, Retrieve, Store, Var, ID};
//pub enum VarType {
// Continuous,
// Integer,
// Binary,
//}
/// Constraint identifier.
#[derive(Debug, Clone, Copy)]
pub struct Con(pub ID);
/// Interface for a mathematical program with continuous variables.
///
/// # Panics
///
/// Expect a panic, either our of bounds or otherwise, if a variable or
/// parameter is used in this model that was not directly returned by the
/// `add_var` or `add_par` methods. Check individual implementations of trait
/// for details of when these panics could occur.
pub trait Model {
/// Add variable to model with lower / upper bounds and initial value.
fn add_var(&mut self, lb: f64, ub: f64, init: f64) -> Var;
/// Add parameter to model with starting value.
fn add_par(&mut self, val: f64) -> Par;
/// Add a constraint to the model with lower and upper bounds.
///
/// To have no lower / upper bounds set them to `std::f64::NEG_INFINITY` /
/// `std::f64::INFINITY` respectively.
fn add_con<E: Into<Expression>>(&mut self, expr: E, lb: f64, ub: f64) -> Con;
/// Set objective of model.
fn set_obj<E: Into<Expression>>(&mut self, expr: E);
/// Change a parameter's value.
fn set_par(&mut self, par: Par, val: f64);
/// Change the initial value of a variable.
fn set_init(&mut self, var: Var, init: f64);
/// Solve the model.
fn solve(&mut self) -> (SolutionStatus, Option<Solution>);
/// Solve the model using a previous solution as a warm start.
fn warm_solve(&mut self, sol: Solution) -> (SolutionStatus, Option<Solution>);
}
// Not used yet
//pub trait MIModel {
// fn add_ivar(&mut self, lb: f64, ub: f64) -> Var;
// fn add_bvar(&mut self, lb: f64, ub: f64) -> Var;
//}
/// Status of the solution.
#[derive(PartialEq, Debug)]
pub enum SolutionStatus {
/// Problem successfully solved.
Solved,
/// Problem appears to be infeasible.
Infeasible,
/// An error occurred during the solve process.
Error,
/// Other currrently unhandled solver status returned.
Other,
}
/// Data for a valid solution.
#[derive(Default)]
pub struct Solution {
/// Objective value.
pub obj_val: f64,
/// Store of variable and parameter values.
pub store: Store,
/// Constraint Lagrange / KKT multipliers.
pub con_mult: Vec<f64>,
/// Variable lower bound KKT multipliers.
pub var_lb_mult: Vec<f64>,
/// Variable upper bound KKT multipliers.
pub var_ub_mult: Vec<f64>,
}
impl Solution {
pub fn new() -> Self {
Self::default()
}
/// Calculate the value of an expression using the solution.
pub fn value(&self, expr: &Expression) -> f64 {
match expr {
Expression::ExprFix(e) => (e.f)(&self.store.vars, &self.store.pars),
Expression::ExprFixSum(es) => {
let mut val = 0.0;
for e in es {
val += (e.f)(&self.store.vars, &self.store.pars);
}
val
}
Expression::ExprDyn(e) => {
let mut ns = Vec::new();
e.expr.eval(&self.store, &mut ns)
}
Expression::ExprDynSum(es) => {
let mut ns = Vec::new();
let mut val = 0.0;
for e in es {
val += e.expr.eval(&self.store, &mut ns);
}
val
}
}
}
/// Get the value of variable for solution.
pub fn var(&self, v: Var) -> f64 {
self.store.var(v)
}
/// Get the constraint KKT / Lagrange multiplier.
pub fn con_mult(&self, Con(cid): Con) -> f64 {
self.con_mult[cid]
}
// Could write versions that take Expr, and try and match ops[0] to Var
/// Get the variable lower bound constraint KKT / Lagrange multiplier.
pub fn var_lb_mult(&self, Var(vid): Var) -> f64 {
self.var_lb_mult[vid]
}
/// Get the variable upper bound constraint KKT / Lagrange multiplier.
pub fn var_ub_mult(&self, Var(vid): Var) -> f64 {
self.var_ub_mult[vid]
}
}