lp_modeler/dsl/
problem.rs

1extern crate uuid;
2
3use std::collections::HashMap;
4use std::ops::AddAssign;
5
6
7use self::uuid::Uuid;
8use dsl::*;
9
10/// Enum helping to specify the objective function of the linear problem.
11///
12/// # Examples:
13///
14/// ```
15/// use lp_modeler::dsl::{LpObjective, LpProblem};
16///
17/// let mut problem = LpProblem::new("One Problem", LpObjective::Maximize);
18/// ```
19#[derive(Debug, PartialEq)]
20pub enum LpObjective {
21    Minimize,
22    Maximize,
23}
24
25pub trait Problem {
26    fn add_objective_expression(&mut self, expr_arena: &mut LpExpression);
27    fn add_constraints(&mut self, contraint_expr: &LpConstraint);
28}
29
30/// Structure used for creating the model and solving a linear problem.
31///
32/// # Examples:
33///
34/// ```
35/// use lp_modeler::dsl::*;
36/// use lp_modeler::solvers::{SolverTrait, CbcSolver, Solution};
37///
38/// let ref a = LpInteger::new("a");
39/// let ref b = LpInteger::new("b");
40/// let ref c = LpInteger::new("c");
41///
42/// let mut problem = LpProblem::new("One Problem", LpObjective::Maximize);
43/// problem += 10.0 * a + 20.0 * b;
44///
45/// problem += (500*a + 1200*b + 1500*c).le(10000);
46/// problem += (a + b*2 + c).le(10);
47/// problem += (a).le(b);
48///
49/// let solver = CbcSolver::new();
50///
51/// match solver.run(&problem) {
52/// Ok( solution ) => {
53///     println!("Status {:?}", solution.status);
54///         for (name, value) in solution.results.iter() {
55///             println!("value of {} = {}", name, value);
56///         }
57///     },
58///     Err(msg) => println!("{}", msg),
59/// }
60/// ```
61#[derive(Debug)]
62pub struct LpProblem {
63    pub name: &'static str,
64    pub unique_name: String,
65    pub objective_type: LpObjective,
66    pub obj_expr_arena: Option<LpExpression>,
67    pub constraints: Vec<LpConstraint>,
68}
69
70impl LpProblem {
71    /// Create a new problem
72    pub fn new(name: &'static str, objective: LpObjective) -> LpProblem {
73        let unique_name = format!("{}_{}", name, Uuid::new_v4());
74        LpProblem {
75            name,
76            unique_name,
77            objective_type: objective,
78            obj_expr_arena: None,
79            constraints: Vec::new(),
80        }
81    }
82
83
84    // TODO: Call once and pass into parameter
85    // TODO: Check variables on the objective function
86    pub fn variables(&self) -> HashMap<String, (usize, usize)> {
87        let mut lst: HashMap<String, (usize, usize)> = HashMap::new();
88        for constraint_index in 0..self.constraints.len() {
89            let constraint = self.constraints.get(constraint_index).unwrap();
90            constraint.var(constraint.0.get_root_index(), constraint_index, &mut lst);
91        }
92        lst
93    }
94}
95
96impl Problem for LpProblem {
97    fn add_objective_expression(&mut self, expr_arena: &mut LpExpression) {
98        if let Some(e) = &self.obj_expr_arena {
99            let mut simple_expr = expr_arena
100                .merge_cloned_arenas(&e, LpExprOp::Addition);
101            let _ = simple_expr.simplify().split_off_constant();
102            self.obj_expr_arena = Some(simple_expr);
103        } else {
104            let mut simple_expr = expr_arena.clone();
105            let _ = simple_expr.simplify().split_off_constant();
106            self.obj_expr_arena = Some(simple_expr);
107        }
108    }
109
110    fn add_constraints(&mut self, constraint_expr: &LpConstraint) {
111        self.constraints.push(constraint_expr.clone());
112    }
113}
114
115macro_rules! impl_addassign_for_generic_problem {
116    ($problem: ty) => {
117        /// Add constraints
118        impl AddAssign<LpConstraint> for $problem {
119            fn add_assign(&mut self, _rhs: LpConstraint) {
120                self.add_constraints(&_rhs);
121            }
122        }
123        /// Add an expression as an objective function
124        impl<T> AddAssign<T> for $problem
125        where
126            T: Into<LpExpression>,
127        {
128            fn add_assign(&mut self, _rhs: T) {
129                self.add_objective_expression(&mut _rhs.into());
130            }
131        }
132    };
133}
134impl_addassign_for_generic_problem!(LpProblem);