lp_modeler/dsl/
variables.rs

1/// # Module variables
2///
3use self::LpExprNode::*;
4use self::LpExprOp::*;
5
6use proc_macro2::{TokenStream};
7use quote::{quote, ToTokens};
8
9use std::convert::Into;
10use std::collections::HashMap;
11use std::fmt::Write;
12
13pub trait BoundableLp: PartialEq + Clone {
14    fn lower_bound(&self, lw: f32) -> Self;
15    fn upper_bound(&self, up: f32) -> Self;
16}
17
18// A binary variable is constrained to be either 1 or 0. Refer to the
19// [LP format documentation](https://www.gurobi.com/documentation/8.0/refman/variables.html)
20// for details.
21#[derive(Debug, Clone, PartialEq)]
22pub struct LpBinary {
23    pub name: String,
24}
25impl LpBinary {
26    pub fn new(name: &str) -> LpBinary {
27        LpBinary {
28            name: name.to_string(),
29        }
30    }
31}
32
33impl ToTokens for LpBinary {
34    fn to_tokens(&self, stream: &mut TokenStream) {
35        let name = &self.name;
36        stream.extend(quote! {
37            LpBinary{
38                name: #name,
39            }
40        });
41    }
42}
43
44#[derive(Debug, Clone, PartialEq)]
45pub struct LpInteger {
46    pub(crate) name: String,
47    pub(crate) lower_bound: Option<f32>,
48    pub(crate) upper_bound: Option<f32>,
49}
50impl LpInteger {
51    pub fn new(name: &str) -> LpInteger {
52        LpInteger {
53            name: name.to_string(),
54            lower_bound: None,
55            upper_bound: None,
56        }
57    }
58}
59impl ToTokens for LpInteger {
60    fn to_tokens(&self, stream: &mut TokenStream) {
61        let name = &self.name;
62        let lower_bound = match self.lower_bound {
63            Some(ref v) => quote!(Some(#v)),
64            None => quote!(None)
65        };
66        let upper_bound = match self.upper_bound {
67            Some(ref v) => quote!(Some(#v)),
68            None => quote!(None)
69        };
70        stream.extend(quote! {
71            LpInteger{
72                name: #name.to_string(),
73                lower_bound: #lower_bound,
74                upper_bound: #upper_bound
75            }
76        });
77    }
78}
79
80#[derive(Debug, Clone, PartialEq)]
81pub struct LpContinuous {
82    pub name: String,
83    pub lower_bound: Option<f32>,
84    pub upper_bound: Option<f32>,
85}
86impl LpContinuous {
87    pub fn new(name: &str) -> LpContinuous {
88        LpContinuous {
89            name: name.to_string(),
90            lower_bound: None,
91            upper_bound: None,
92        }
93    }
94}
95impl ToTokens for LpContinuous {
96    fn to_tokens(&self, stream: &mut TokenStream) {
97        let name = &self.name;
98        let lower_bound = match self.lower_bound {
99            Some(ref v) => quote!(Some(#v)),
100            None => quote!(None)
101        };
102        let upper_bound = match self.upper_bound {
103            Some(ref v) => quote!(Some(#v)),
104            None => quote!(None)
105        };
106        stream.extend(quote! {
107            LpContinuous{
108                name: #name.to_string(),
109                lower_bound: #lower_bound,
110                upper_bound: #upper_bound
111            }
112        });
113    }
114}
115
116macro_rules! implement_boundable {
117    ($lp_type: ident) => {
118        impl BoundableLp for $lp_type {
119            fn lower_bound(&self, lw: f32) -> $lp_type {
120                $lp_type {
121                    name: self.name.clone(),
122                    lower_bound: Some(lw),
123                    upper_bound: self.upper_bound,
124                }
125            }
126            fn upper_bound(&self, up: f32) -> $lp_type {
127                $lp_type {
128                    name: self.name.clone(),
129                    lower_bound: self.lower_bound,
130                    upper_bound: Some(up),
131                }
132            }
133        }
134    };
135}
136implement_boundable!(LpInteger);
137implement_boundable!(LpContinuous);
138
139#[derive(Debug, Clone, PartialEq)]
140pub(crate) enum LpExprOp {
141    Multiplication,
142    Addition,
143    Subtraction
144}
145
146impl ToTokens for LpExprOp {
147    fn to_tokens(&self, stream: &mut TokenStream) {
148        stream.extend(
149            match self {
150                LpExprOp::Multiplication => quote!(LpExprOp::Multiplication),
151                LpExprOp::Addition => quote!(LpExprOp::Addition),
152                LpExprOp::Subtraction => quote!(LpExprOp::Subtraction),
153            }
154        );
155    }
156}
157
158pub(crate) type LpExprArenaIndex = usize;
159
160#[derive(Debug, Clone, PartialEq)]
161pub(crate) struct LpCompExpr {
162    operation: LpExprOp,
163    left_index: LpExprArenaIndex,
164    right_index: LpExprArenaIndex
165}
166
167/// ADT for Linear Programming Expression
168#[derive(Debug, Clone, PartialEq)]
169pub(crate) enum LpExprNode {
170    ConsInt(LpInteger),
171    ConsBin(LpBinary),
172    ConsCont(LpContinuous),
173    LitVal(f32),
174    EmptyExpr,
175    LpCompExpr(LpExprOp, LpExprArenaIndex, LpExprArenaIndex)
176}
177
178impl ToTokens for LpExprNode {
179    fn to_tokens(&self, stream: &mut TokenStream) {
180        stream.extend(
181            match self {
182                LpExprNode::ConsInt(v) => quote!(LpExprNode::ConsInt(#v)),
183                LpExprNode::ConsBin(v) => quote!(LpExprNode::ConsBin(#v)),
184                LpExprNode::ConsCont(v) => quote!(LpExprNode::ConsCont(#v)),
185                LpExprNode::LpCompExpr(op, lhs, rhs) => quote!(LpExprNode::LpCompExpr(#op, #lhs, #rhs)),
186                LpExprNode::LitVal(v) =>  quote!(LpExprNode::LitVal(#v)),
187                LpExprNode::EmptyExpr => quote!(LpExprNode::EmptyExpr),
188            }
189        );
190    }
191}
192
193// Macro implementing Into<LpExprNode> for types
194macro_rules! cons_into_expr {
195    ($type_from:ty, $wrapper: ident) => {
196        impl From<$type_from> for LpExprNode {
197            fn from(from: $type_from) -> Self {
198                $wrapper(from)
199            }
200        }
201        impl<'a> From<&'a $type_from> for LpExprNode {
202            fn from(from: &'a $type_from) -> Self {
203                $wrapper((*from).clone())
204            }
205        }
206    };
207}
208cons_into_expr!(LpBinary, ConsBin);
209cons_into_expr!(LpInteger, ConsInt);
210cons_into_expr!(LpContinuous, ConsCont);
211
212macro_rules! lit_into_expr {
213    ($type_from:ty) => {
214        impl From<$type_from> for LpExprNode {
215            fn from(from: $type_from) -> Self {
216                    LitVal(from as f32)
217            }
218        }
219        impl<'a> From<&'a $type_from> for LpExprNode {
220            fn from(from: &'a $type_from) -> Self {
221                    LitVal((*from).clone() as f32)
222            }
223        }
224    };
225}
226lit_into_expr!(f32);
227lit_into_expr!(i32);
228
229#[derive(Debug, Clone, PartialEq)]
230pub struct LpExpression {
231    root: LpExprArenaIndex,
232    arena: Vec<LpExprNode>
233}
234
235impl ToTokens for LpExpression {
236    fn to_tokens(&self, stream: &mut TokenStream) {
237        let root = self.get_root_index();
238        let arena = self.arena.clone();
239        stream.extend( quote! {
240            LpExpression {
241                root: #root,
242                arena: #( struct #arena;),*
243            }
244        });
245    }
246}
247
248// Macro implementing Into<LpExpression> for types
249macro_rules! cons_into_expr_arena {
250    ($type_from:ty, $wrapper: ident) => {
251        impl From<$type_from> for LpExpression {
252            fn from(from: $type_from) -> Self {
253                LpExpression {
254                    root: 0,
255                    arena: vec![$wrapper(from); 1]
256                }
257            }
258        }
259        impl<'a> From<&'a $type_from> for LpExpression {
260            fn from(from: &'a $type_from) -> Self {
261                LpExpression {
262                    root: 0,
263                    arena: vec![$wrapper((*from).clone()); 1]
264                }
265            }
266        }
267    };
268}
269cons_into_expr_arena!(LpBinary, ConsBin);
270cons_into_expr_arena!(LpInteger, ConsInt);
271cons_into_expr_arena!(LpContinuous, ConsCont);
272
273macro_rules! lit_into_expr_arena {
274    ($type_from:ty) => {
275        impl From<$type_from> for LpExpression {
276            fn from(from: $type_from) -> Self {
277                LpExpression {
278                    root: 0,
279                    arena: vec![LitVal(from as f32); 1]
280                }
281            }
282        }
283        impl<'a> From<&'a $type_from> for LpExpression {
284            fn from(from: &'a $type_from) -> Self {
285                LpExpression {
286                    root: 0,
287                    arena: vec![LitVal((*from).clone() as f32); 1]
288                }
289            }
290        }
291    };
292}
293lit_into_expr_arena!(f32);
294lit_into_expr_arena!(i32);
295
296impl From<LpExprNode> for LpExpression {
297    fn from(expr: LpExprNode) -> Self {
298        LpExpression {
299            root: 0,
300            arena: vec![expr; 1]
301        }
302    }
303}
304
305impl From<&LpExprNode> for LpExpression {
306    fn from(expr: &LpExprNode) -> Self {
307        LpExpression {
308            root: 0,
309            arena: vec![expr.clone(); 1]
310        }
311    }
312}
313
314impl LpExpression {
315    fn new() -> Self {
316       LpExpression {
317           root: 0,
318           arena: Vec::new()
319       }
320    }
321
322    pub fn literal(value: f32) -> Self {
323        value.into()
324    }
325
326    #[cfg(test)]
327    fn build(root: LpExprArenaIndex, arena: Vec<LpExprNode>) -> Self {
328        LpExpression {
329            root: root,
330            arena: arena
331        }
332    }
333
334    pub(crate) fn get_root_index(&self) -> LpExprArenaIndex {
335        self.root
336    }
337
338    fn set_root_to_index(&mut self, root_index: LpExprArenaIndex) {
339        self.root = root_index;
340    }
341
342    fn push_as_expr<T>(&mut self, lp_expr: &T) -> LpExprArenaIndex where T: Into<LpExprNode> + Clone {
343        let index = self.arena.len();
344        self.arena.push(lp_expr.clone().into());
345        return index
346    }
347
348    fn clone_expr_at_and_push(&mut self, index: LpExprArenaIndex) -> LpExprArenaIndex {
349        let new_index = self.arena.len();
350        self.arena.push(self.expr_clone_at(index));
351        return new_index
352    }
353
354    fn overwrite_expr_at(&mut self, index: LpExprArenaIndex, lp_expr: LpExprNode) {
355       self.arena[index] = lp_expr;
356    }
357
358    pub(crate) fn expr_ref_at(&self, index: LpExprArenaIndex) -> &LpExprNode {
359        match self.arena.get(index) {
360            Some(expr) => expr,
361            None => panic!("Requested index out of bound of LpExpression vector. This should not happen.")
362        }
363    }
364
365    fn expr_clone_at(&self, index: LpExprArenaIndex) -> LpExprNode {
366        match self.arena.get(index) {
367            Some(expr) => expr.clone(),
368            None => panic!("Requested index out of bound of LpExpression vector. This should not happen.")
369        }
370    }
371
372    pub(crate) fn get_root_expr_ref(&self) -> &LpExprNode {
373        self.expr_ref_at(self.root)
374    }
375
376    pub(crate) fn split_off_constant(&mut self) -> f32 {
377        match self.expr_clone_at(self.root) {
378            LitVal(c) => {
379                self.clone_from(&LpExpression::new());
380                c
381            },
382            LpCompExpr(Addition, e1, e2) => {
383                if let LitVal(c) = self.expr_clone_at(e2) {
384                    self.set_root_to_index(e1);
385                    c
386                } else {
387                    0.0
388                }
389            },
390            LpCompExpr(Subtraction, e1, e2) => {
391                if let LitVal(c) = self.expr_clone_at(e2) {
392                    self.set_root_to_index(e1);
393                    -c
394                } else {
395                    0.0
396                }
397            },
398            _ => 0.0
399        }
400    }
401
402    pub(crate) fn merge_cloned_arenas(&self, right_lp_expr_arena: &LpExpression, operation: LpExprOp) -> Self {
403        let mut new_arena = self.clone();
404        let index_at_insertion = new_arena.push_arena_at_root(right_lp_expr_arena);
405        let new_root = new_arena.push_as_expr(
406            &LpCompExpr(operation, new_arena.get_root_index(), index_at_insertion)
407        );
408        new_arena.set_root_to_index(new_root);
409        new_arena
410    }
411
412    fn push_arena_at_root(&mut self, right_lp_expr_arena: &LpExpression) -> LpExprArenaIndex {
413        let right_root_expr_ref = right_lp_expr_arena.get_root_expr_ref();
414        let new_index_right_root = self.push_as_expr(right_root_expr_ref);
415        let mut move_stack: Vec<LpExprArenaIndex> = Vec::new();
416        move_stack.push(new_index_right_root);
417        while let Some(new_parent_index) = move_stack.pop() {
418            let lp_expr_arena = self.expr_clone_at(new_parent_index);
419            if let LpCompExpr(operation, right_arena_left_index, right_arena_right_index) = lp_expr_arena {
420                    let new_left_index = self.push_as_expr(right_lp_expr_arena.expr_ref_at(right_arena_left_index));
421                    let new_right_index = self.push_as_expr(right_lp_expr_arena.expr_ref_at(right_arena_right_index));
422                    self.overwrite_expr_at(
423                        new_parent_index,
424                        LpCompExpr(
425                            operation.clone(),
426                            new_left_index,
427                            new_right_index
428                        )
429                    );
430                    move_stack.push(new_left_index);
431                    move_stack.push(new_right_index);
432            }
433        }
434        new_index_right_root
435    }
436
437    fn clone_subtree_at_index_and_push(&mut self, index: LpExprArenaIndex) -> LpExpression {
438        let mut clone_stack: Vec<LpExprNode> = vec![self.expr_clone_at(index)];
439        let mut cloned_subtree = LpExpression::new();
440        let mut new_left_index: LpExprArenaIndex;
441        let mut new_right_index_stack: Vec<LpExprArenaIndex> = Vec::new();
442        let mut left_stack: Vec<bool> = vec![false];
443        while let (Some(expr), Some(mut left)) = (clone_stack.pop(), left_stack.pop()) {
444            if let LpCompExpr(op, left_index, right_index) = expr {
445                clone_stack.push(LpCompExpr(op, left_index, right_index));
446                left_stack.push(left);
447                clone_stack.push(self.expr_clone_at(left_index));
448                left_stack.push(true);
449                clone_stack.push(self.expr_clone_at(right_index));
450                left_stack.push(false);
451            } else {
452                if left {
453                    new_left_index = cloned_subtree.push_as_expr(&expr);
454                    while left {
455                        if let (Some(LpCompExpr(op, _, _)), Some(local_left)) = (clone_stack.pop(), left_stack.pop()) {
456                            if let Some(new_right_index) = new_right_index_stack.pop() {
457                                left = local_left;
458                                if left {
459                                    new_left_index = cloned_subtree.push_as_expr(
460                                        &LpCompExpr(op, new_left_index, new_right_index)
461                                    );
462                                } else {
463                                    new_right_index_stack.push(
464                                        cloned_subtree.push_as_expr(
465                                            &LpCompExpr(op, new_left_index, new_right_index)
466                                        )
467                                    );
468                                }
469                            } else {
470                                panic!("Found no remaining right index to match the left.")
471                            }
472                        } else {
473                            panic!("Found no parent node to match two new indices I have.");
474                        }
475                    }
476                } else {
477                    new_right_index_stack.push( cloned_subtree.push_as_expr(&expr) );
478                }
479            }
480        }
481
482        if let Some(root_index)  = new_right_index_stack.pop() {
483            cloned_subtree.set_root_to_index(root_index);
484            cloned_subtree
485        } else {
486            panic!("Got an empty new_right_index_stack. This is a bug.");
487        }
488    }
489
490    pub(crate) fn show(&self, e: &LpExprArenaIndex, with_parenthesis: bool) -> String {
491        #[derive(Clone, Copy)]
492        enum Part {
493            None,
494            Char(char),
495            Str(&'static str),
496            Elem(LpExprArenaIndex),
497        }
498        let left = if with_parenthesis { Part::Char('(') } else { Part::None };
499        let right = if with_parenthesis { Part::Char(')') } else { Part::None };
500        let op_mult = if with_parenthesis { Part::Str(" * ") } else { Part::Char(' ') };
501
502        let mut remaining: Vec<Part> = vec![Part::Elem(*e)];
503        let mut result = String::new();
504        while let Some(e) = remaining.pop() {
505            match e {
506                Part::None => {}
507                Part::Char(c) => { result.push(c) }
508                Part::Str(s) => { result.push_str(s) }
509                Part::Elem(e) => {
510                    match self.expr_ref_at(e) {
511                        LitVal(n) => write!(result, "{}", n).unwrap(),
512                        LpCompExpr(Addition, e1, e2) => {
513                            remaining.push(right);
514                            remaining.push(Part::Elem(*e2));
515                            remaining.push(Part::Str(" + "));
516                            remaining.push(Part::Elem(*e1));
517                            remaining.push(left);
518                        }
519                        LpCompExpr(Subtraction, e1, e2) => {
520                            remaining.push(right);
521                            remaining.push(Part::Elem(*e2));
522                            remaining.push(Part::Str(" - "));
523                            remaining.push(Part::Elem(*e1));
524                            remaining.push(left);
525                        }
526                        LpCompExpr(Multiplication, e1, e2) => {
527                            match self.expr_ref_at(*e1) {
528                                &LitVal(c) if c == 1.0 => {
529                                    remaining.push(right);
530                                    remaining.push(Part::Elem(*e2));
531                                    remaining.push(Part::Char(' '));
532                                    remaining.push(left);
533                                },
534                                &LitVal(c) if c == -1.0 => {
535                                    remaining.push(right);
536                                    remaining.push(Part::Elem(*e2));
537                                    remaining.push(Part::Str("-"));
538                                    remaining.push(left);
539                                }
540                                _ => {
541                                    remaining.push(right);
542                                    remaining.push(Part::Elem(*e2));
543                                    remaining.push(op_mult);
544                                    remaining.push(Part::Elem(*e1));
545                                    remaining.push(left);
546                                }
547                            }
548                        }
549                        ConsBin(LpBinary { name: ref n, .. }) => result += n,
550                        ConsInt(LpInteger { name: ref n, .. }) => result += n,
551                        ConsCont(LpContinuous { name: ref n, .. }) => result += n,
552                        EmptyExpr => { result += "EmptyExpr!!!" }
553                    }
554                }
555            }
556        }
557        result
558    }
559
560    pub(crate) fn simplify(&mut self) -> &mut Self {
561        let mut stop = false;
562        let mut lp_expr_stack: Vec<LpExprArenaIndex> = Vec::new();
563        while !stop {
564            stop = true;
565            lp_expr_stack.push(self.get_root_index());
566            while let Some(handled_expr_index) = lp_expr_stack.pop() {
567                match self.expr_clone_at(handled_expr_index) {
568                    LpCompExpr(Multiplication, left_index, right_index) => {
569                        match (self.expr_clone_at(left_index), self.expr_clone_at(right_index)) {
570                            // Trivial rule: 0 * x = 0
571                            (_, LitVal(c))
572                            | (LitVal(c), _) if c == 0.0 => {
573                                stop = false;
574                                self.overwrite_expr_at(
575                                    handled_expr_index,
576                                    LitVal(0.0),
577                                )
578                            },
579
580                            // Simplify two literals
581                            (LitVal(c1), LitVal(c2)) => {
582                                stop = false;
583                                self.overwrite_expr_at(
584                                    handled_expr_index,
585                                    LitVal(c1 * c2)
586                                )
587                            },
588
589                            // DISTRIBUTIVITY
590                            // i*(a+b) = i*a+i*b
591                            (i, LpCompExpr(Addition, a_index, b_index)) => {
592                                stop = false;
593                                let i_new_index: LpExprArenaIndex;
594                                if let LpCompExpr(_, _, _) = i {
595                                    let new_subtree = self.clone_subtree_at_index_and_push(left_index);
596                                    i_new_index = self.push_arena_at_root(&new_subtree);
597                                } else {
598                                    // Cons or LitVal type
599                                    i_new_index = self.clone_expr_at_and_push(left_index);
600                                }
601                                let new_left_index = self.push_as_expr(
602                                    &LpCompExpr(Multiplication, left_index, a_index)
603                                );
604                                self.overwrite_expr_at(
605                                    right_index,
606                                    LpCompExpr(Multiplication, i_new_index, b_index)
607                                );
608                                self.overwrite_expr_at(
609                                    handled_expr_index,
610                                    LpCompExpr(Addition, new_left_index, right_index)
611                                );
612                                lp_expr_stack.push(handled_expr_index);
613                            },
614                            // (a+b)*i = i*a+i*b
615                            (LpCompExpr(Addition, a_index, b_index), i) => {
616                                stop = false;
617                                let i_new_index: LpExprArenaIndex;
618                                if let LpCompExpr(_, _, _) = i {
619                                    let new_subtree = self.clone_subtree_at_index_and_push(right_index);
620                                    i_new_index = self.push_arena_at_root(&new_subtree);
621                                } else {
622                                    // Cons or LitVal type
623                                    i_new_index = self.clone_expr_at_and_push(right_index);
624                                }
625                                let new_right_index = self.push_as_expr(
626                                    &LpCompExpr(Multiplication, right_index, b_index)
627                                );
628                                self.overwrite_expr_at(
629                                    left_index,
630                                    LpCompExpr(Multiplication, i_new_index, a_index)
631                                );
632                                self.overwrite_expr_at(
633                                    handled_expr_index,
634                                    LpCompExpr(Addition, left_index, new_right_index)
635                                );
636                                lp_expr_stack.push(handled_expr_index);
637                            },
638
639                            // (a-b)*i = i*a-i*b
640                            (LpCompExpr(Subtraction, a_index, b_index), i) => {
641                                stop = false;
642                                let i_new_index: LpExprArenaIndex;
643                                if let LpCompExpr(_, _, _) = i {
644                                    let new_subtree = self.clone_subtree_at_index_and_push(right_index);
645                                    i_new_index = self.push_arena_at_root(&new_subtree);
646                                } else {
647                                    // Cons or LitVal type
648                                    i_new_index = self.clone_expr_at_and_push(right_index);
649                                }
650                                let new_right_index = self.push_as_expr(
651                                    &LpCompExpr(Multiplication, right_index, b_index)
652                                );
653                                self.overwrite_expr_at(
654                                    left_index,
655                                    LpCompExpr(Multiplication, i_new_index, a_index)
656                                );
657                                self.overwrite_expr_at(
658                                    handled_expr_index,
659                                    LpCompExpr(Subtraction, left_index, new_right_index)
660                                );
661                                lp_expr_stack.push(handled_expr_index);
662                            },
663                            // i*(a-b) = i*a-i*b
664                            (i, LpCompExpr(Subtraction, a_index, b_index)) => {
665                                stop = false;
666                                let i_new_index: LpExprArenaIndex;
667                                if let LpCompExpr(_, _, _) = i {
668                                    let new_subtree = self.clone_subtree_at_index_and_push(left_index);
669                                    i_new_index = self.push_arena_at_root(&new_subtree);
670                                } else {
671                                    // Cons or LitVal type
672                                    i_new_index = self.clone_expr_at_and_push(left_index);
673                                }
674                                let new_left_index = self.push_as_expr(
675                                    &LpCompExpr(Multiplication, left_index, a_index)
676                                );
677                                self.overwrite_expr_at(
678                                    right_index,
679                                    LpCompExpr(Multiplication, i_new_index, b_index)
680                                );
681                                self.overwrite_expr_at(
682                                    handled_expr_index,
683                                    LpCompExpr(Subtraction, new_left_index, right_index)
684                                );
685                                lp_expr_stack.push(handled_expr_index);
686                            },
687
688
689                            // COMMUTATIVITY WITH CONSTANTS
690                            // c1*(a*b)
691                            (LitVal(c1), LpCompExpr(Multiplication, a_index, b_index)) => {
692                                match (self.expr_clone_at(a_index), self.expr_clone_at(b_index)) {
693                                    // c1*(c2*b) = (c1*c2)*b
694                                    (LitVal(c2), _) => {
695                                        stop = false;
696                                        self.overwrite_expr_at(
697                                            left_index,
698                                            LitVal(c1 * c2),
699                                        );
700                                        self.overwrite_expr_at(
701                                            handled_expr_index,
702                                            LpCompExpr(
703                                                Multiplication,
704                                                left_index,
705                                                b_index
706                                            )
707                                        );
708                                        lp_expr_stack.push(handled_expr_index);
709                                    },
710                                    // c1*(a*c2) = (c1*c2)*a
711                                    (_, LitVal(c2)) => {
712                                        stop = false;
713                                        self.overwrite_expr_at(
714                                            left_index,
715                                            LitVal(c1 * c2),
716                                        );
717                                        self.overwrite_expr_at(
718                                            handled_expr_index,
719                                            LpCompExpr(
720                                                Multiplication,
721                                                left_index,
722                                                a_index
723                                            )
724                                        );
725                                        lp_expr_stack.push(handled_expr_index);
726                                    },
727                                    // c1*(a*b) = (c1*a)*b
728                                    (_, _) => {
729                                        stop = false;
730                                        let lit_new_index = self.push_as_expr(&LitVal(c1));
731                                        self.overwrite_expr_at(
732                                            left_index,
733                                            LpCompExpr(
734                                                Multiplication,
735                                                lit_new_index,
736                                                a_index
737                                            )
738                                        );
739                                        self.overwrite_expr_at(
740                                            handled_expr_index,
741                                            LpCompExpr(
742                                                Multiplication,
743                                                left_index,
744                                                b_index
745                                            )
746                                        );
747                                        lp_expr_stack.push(handled_expr_index);
748                                    }
749                                }
750                            },
751
752                            //TODO: (Pointless?)
753                            // expr1*(c*expr) = c*(expr1*expr2)
754
755                            // COMMUTATIVITY
756                            // x*(a*b) = (x*a)*b
757                            (_, LpCompExpr(Multiplication, a_index, b_index)) => {
758                                stop = false;
759                                let left_new_index = self.clone_expr_at_and_push(left_index);
760                                self.overwrite_expr_at(
761                                    left_index,
762                                    LpCompExpr(Multiplication, left_new_index, a_index),
763                                );
764                                self.overwrite_expr_at(
765                                    right_index,
766                                    self.expr_clone_at(b_index)
767                                );
768                                lp_expr_stack.push(handled_expr_index);
769                            },
770
771                            // Place literal first for *
772                            (_, LitVal(_)) => {
773                                stop = false;
774                                self.overwrite_expr_at(
775                                    handled_expr_index,
776                                    LpCompExpr(
777                                        Multiplication,
778                                        right_index,
779                                        left_index
780                                    )
781                                );
782                                lp_expr_stack.push(handled_expr_index);
783                            },
784
785                            // When literal is first and right side is not LpCompExpr (LpCompExpr case handled above), stop
786                            (LitVal(_c1), _) => { },
787                            // recurse deeper and come back for any complex expressions not handled above
788                            (LpCompExpr(_, _, _), _) => {
789                                lp_expr_stack.push(left_index);
790                            },
791                            (_, _) => { }
792                        }
793                    },
794                    LpCompExpr(Addition, left_index, right_index) => {
795                        match (self.expr_clone_at(left_index), self.expr_clone_at(right_index)) {
796                            // Trivial rule: 0 + x = x
797                            (LitVal(c), a)
798                            // Trivial rule: x + 0 = x
799                            | (a, LitVal(c)) if c == 0.0 => {
800                                stop = false;
801                                self.overwrite_expr_at(handled_expr_index, a.clone());
802                                lp_expr_stack.push(handled_expr_index);
803                            },
804
805                            // Simplify two literals
806                            (LitVal(c1), LitVal(c2)) => {
807                                stop = false;
808                                self.overwrite_expr_at(
809                                    handled_expr_index,
810                                    LitVal(c1 + c2)
811                                );
812                            },
813
814                            // Place literal at the end
815                            (LitVal(_c), _x) => {
816                                stop = false;
817                                self.overwrite_expr_at(
818                                    handled_expr_index,
819                                    LpCompExpr(Addition, right_index, left_index)
820                                );
821                                lp_expr_stack.push(right_index);
822                            },
823
824                            // ASSOCIATIVITY
825                            // a + (b+c) = (a+b)+c
826                            (a, LpCompExpr(Addition, b_index, c_index)) => {
827                                stop = false;
828                                let new_a_index = self.push_as_expr(&a.clone());
829                                self.overwrite_expr_at(
830                                    left_index,
831                                    LpCompExpr(Addition, new_a_index, b_index),
832                                );
833                                self.overwrite_expr_at(
834                                    right_index,
835                                    self.expr_clone_at(c_index)
836                                );
837                                lp_expr_stack.push(handled_expr_index);
838                            },
839
840                            // a + (b-c) = (a+b) - c
841                            (a, LpCompExpr(Subtraction, b_index, c_index)) => {
842                                stop = false;
843                                let new_a_index = self.push_as_expr(&a.clone());
844                                self.overwrite_expr_at(
845                                    left_index,
846                                    LpCompExpr(Addition, new_a_index, b_index),
847                                );
848                                self.overwrite_expr_at(
849                                    right_index,
850                                    self.expr_clone_at(c_index)
851                                );
852                                self.overwrite_expr_at(
853                                    handled_expr_index,
854                                    LpCompExpr(Subtraction, left_index, right_index)
855                                );
856                                lp_expr_stack.push(handled_expr_index);
857                            },
858
859                            // Accumulate consts +/-
860                            // (a+c1)+c2 = a+(c1+c2)
861                            (LpCompExpr(Addition, a_index, b_index), LitVal(c2)) => {
862                                match self.expr_clone_at(b_index) {
863                                    LitVal(c1) => {
864                                        stop = false;
865                                        self.overwrite_expr_at(
866                                            left_index,
867                                            self.expr_clone_at(a_index)
868                                        );
869                                        self.overwrite_expr_at(
870                                            right_index,
871                                            LitVal(c1 + c2)
872                                        );
873                                        lp_expr_stack.push(handled_expr_index);
874                                    },
875                                    _ => {
876                                        lp_expr_stack.push(left_index);
877                                    },
878                                }
879                            },
880                            (LpCompExpr(Subtraction, a_index, b_index), LitVal(c2)) => {
881                                match (self.expr_clone_at(a_index), self.expr_clone_at(b_index)) {
882                                    // (a-c1)+c2 = a+(c2-c1)
883                                    (_a, LitVal(c1)) => {
884                                        stop = false;
885                                        self.overwrite_expr_at(
886                                            right_index,
887                                            LitVal(c2 - c1)
888                                        );
889                                        self.overwrite_expr_at(
890                                            handled_expr_index,
891                                            LpCompExpr(Addition, a_index, right_index)
892                                        );
893                                        lp_expr_stack.push(a_index);
894                                    },
895                                    // (c1-b)+c2 = -b+(c1+c2)
896                                    (LitVal(c1), _b) => {
897                                        stop = false;
898                                        let lit_new_index = self.push_as_expr(&LitVal(-1.0));
899                                        self.overwrite_expr_at(
900                                            left_index,
901                                            LpCompExpr(
902                                                Multiplication,
903                                                lit_new_index,
904                                                b_index
905                                            )
906                                        );
907                                        self.overwrite_expr_at(
908                                            right_index,
909                                            LitVal(c1 + c2)
910                                        );
911                                        lp_expr_stack.push(handled_expr_index);
912                                    },
913                                    _ => {
914                                        lp_expr_stack.push(left_index);
915                                    },
916                                }
917                            },
918
919                            // Extract the const
920                            (LpCompExpr(Addition, a_index, b_index), _x) => {
921                                match (self.expr_clone_at(a_index), self.expr_clone_at(b_index)) {
922                                    // (a+c1)+x = (a+x)+c1
923                                    (_, LitVal(_c1)) => {
924                                        stop = false;
925                                        self.overwrite_expr_at(
926                                            left_index,
927                                            LpCompExpr(Addition, a_index, right_index)
928                                        );
929                                        self.overwrite_expr_at(
930                                            handled_expr_index,
931                                            LpCompExpr(Addition, left_index, b_index)
932                                        );
933                                        lp_expr_stack.push(left_index);
934                                    },
935                                    //// (c1+b)+x = (x+b)+c1
936                                    //(LitVal(_c1), _) => {
937                                    //    self.change_lp_expr(
938                                    //        left_index,
939                                    //        LpCompExpr(Addition, right_index, b_index)
940                                    //    );
941                                    //    self.change_lp_expr(
942                                    //        handled_expr_index,
943                                    //        LpCompExpr(Addition, left_index, a_index)
944                                    //    );
945                                    //    lp_expr_stack.push(left_index);
946                                    //},
947                                    _ => {
948                                        lp_expr_stack.push(right_index);
949                                        lp_expr_stack.push(left_index);
950                                    }
951                                }
952                            },
953                            (LpCompExpr(Subtraction, a_index, b_index), _x) => {
954                                match (self.expr_clone_at(a_index), self.expr_clone_at(b_index)) {
955                                    // (a-c1)+x = (a+x)-c1
956                                    (_a, LitVal(_c1)) => {
957                                        stop = false;
958                                        self.overwrite_expr_at(
959                                            left_index,
960                                            LpCompExpr(Addition, a_index, right_index)
961                                        );
962                                        self.overwrite_expr_at(
963                                            handled_expr_index,
964                                            LpCompExpr(Subtraction, left_index, b_index)
965                                        );
966                                        lp_expr_stack.push(left_index);
967                                    },
968                                    // (c1-b)+x = (x-b)+c1
969                                    (LitVal(_c1), _b) => {
970                                        stop = false;
971                                        self.overwrite_expr_at(
972                                            left_index,
973                                            LpCompExpr(Subtraction, right_index, b_index)
974                                        );
975                                        self.overwrite_expr_at(
976                                            handled_expr_index,
977                                            LpCompExpr(Addition, left_index, a_index)
978                                        );
979                                        lp_expr_stack.push(left_index);
980                                    },
981                                    (_a, _b) => {
982                                        lp_expr_stack.push(left_index);
983                                        lp_expr_stack.push(right_index);
984                                    }
985                                }
986                            },
987
988                            // Accumulate consts +/-
989                            // (expr+c1)+c2 = expr+(c1+c2) OK
990                            // (expr-c1)+c2 = expr+(c2-c1) OK
991                            // (c1-expr)+c2 = -expr+(c1+c2) OK
992
993                            // (expr-c1)-c2 = expr-(c1+c2) OK
994                            // (expr+c1)-c2 = expr+(c1-c2) OK
995                            // (c1-expr)-c2 = -expr+(c1-c2) OK
996
997                            // Extract the const
998                            // (expr1+c)+expr2 = (expr1+expr2)+c OK
999                            // (expr1-c)+expr2 = (expr1+expr2)-c OK
1000                            // (expr1+c)-expr2 = (expr1-expr2)+c OK
1001                            // (expr1-c)-expr2 = (expr1-expr2)-c OK
1002
1003                            (a, b) => {
1004                                // a + a = 2 * a
1005                                if a == b {
1006                                    stop = false;
1007                                    let new_lit_index = self.push_as_expr(&LitVal(2.0));
1008                                    self.overwrite_expr_at(
1009                                        handled_expr_index,
1010                                        LpCompExpr(
1011                                            Multiplication,
1012                                            new_lit_index,
1013                                            left_index
1014                                        )
1015                                    );
1016                                    lp_expr_stack.push(left_index);
1017                                } else {
1018                                    match (a, b) {
1019                                        (LpCompExpr(_, _, _), LpCompExpr(_, _, _)) => {
1020                                            lp_expr_stack.push(left_index);
1021                                            lp_expr_stack.push(right_index);
1022                                        },
1023                                        (LpCompExpr(_, _, _), _) => {
1024                                            lp_expr_stack.push(left_index);
1025                                        },
1026                                        (_, LpCompExpr(_, _, _)) => {
1027                                            lp_expr_stack.push(right_index);
1028                                        },
1029                                        (_, _) => { }
1030                                    }
1031                                }
1032                            }
1033                        }
1034                    },
1035                    LpCompExpr(Subtraction, left_index, right_index) => {
1036                        match (self.expr_clone_at(left_index), self.expr_clone_at(right_index)) {
1037                            // Trivial rule: x - 0 = x
1038                            (a, LitVal(c)) if c == 0.0 => {
1039                                stop = false;
1040                                self.overwrite_expr_at(
1041                                    handled_expr_index,
1042                                    a.clone()
1043                                );
1044                                lp_expr_stack.push(handled_expr_index);
1045                            },
1046
1047                            // a - (b + c) = (a-b)-c
1048                            (_, LpCompExpr(Addition, b_index, c_index)) => {
1049                                stop = false;
1050                                let a_new_index = self.clone_expr_at_and_push(left_index);
1051                                self.overwrite_expr_at(
1052                                    left_index,
1053                                    LpCompExpr(Subtraction, a_new_index, b_index)
1054                                );
1055                                self.overwrite_expr_at(
1056                                    handled_expr_index,
1057                                    LpCompExpr(Subtraction, left_index, c_index)
1058                                );
1059                                lp_expr_stack.push(handled_expr_index);
1060                            },
1061
1062                            // a - (b - c) = (a-b)+c
1063                            (_, LpCompExpr(Subtraction, b_index, c_index)) => {
1064                                stop = false;
1065                                let a_new_index = self.clone_expr_at_and_push(left_index);
1066                                self.overwrite_expr_at(
1067                                    left_index,
1068                                    LpCompExpr(Subtraction, a_new_index, b_index),
1069
1070                                );
1071                                self.overwrite_expr_at(
1072                                    handled_expr_index,
1073                                    LpCompExpr(Addition, left_index, c_index)
1074                                );
1075                                lp_expr_stack.push(handled_expr_index);
1076                            },
1077
1078                            // Place literal at the end
1079                            // c1 - b = -b + c1
1080                            (LitVal(_), _) => {
1081                                stop = false;
1082                                let lit_new_index = self.push_as_expr(&LitVal(-1.0));
1083                                let new_index = self.push_as_expr(
1084                                    &LpCompExpr(
1085                                        Multiplication,
1086                                        lit_new_index,
1087                                        right_index
1088                                    )
1089                                );
1090                                self.overwrite_expr_at(
1091                                    handled_expr_index,
1092                                    LpCompExpr(Addition, new_index, left_index)
1093                                );
1094                                lp_expr_stack.push(handled_expr_index);
1095                            },
1096
1097                            // Accumulate consts +/-
1098                            // (a-c1)-c2 = a-(c1+c2)
1099                            // (c1-b)-c2 = -b+(c1-c2)
1100                            (LpCompExpr(Subtraction, a_index, b_index), LitVal(c2)) => {
1101                                match (self.expr_clone_at(a_index), self.expr_clone_at(b_index)) {
1102                                    (a, LitVal(c1)) => {
1103                                        stop = false;
1104                                        self.overwrite_expr_at(
1105                                            left_index,
1106                                            a.clone()
1107                                        );
1108                                        self.overwrite_expr_at(
1109                                            right_index,
1110                                            LitVal(c1 + c2)
1111                                        );
1112                                        lp_expr_stack.push(handled_expr_index);
1113                                    },
1114                                    (LitVal(c1), _) => {
1115                                        stop = false;
1116                                        let lit_new_index = self.push_as_expr(&LitVal(-1.0));
1117                                        self.overwrite_expr_at(
1118                                            left_index,
1119                                            LpCompExpr(
1120                                                Multiplication,
1121                                                lit_new_index,
1122                                                b_index
1123                                            )
1124                                        );
1125                                        self.overwrite_expr_at(
1126                                            right_index,
1127                                            LitVal(c1 - c2)
1128                                        );
1129                                        self.overwrite_expr_at(
1130                                            handled_expr_index,
1131                                            LpCompExpr(
1132                                                Addition,
1133                                                left_index,
1134                                                right_index
1135                                            )
1136                                        );
1137                                        lp_expr_stack.push(handled_expr_index);
1138                                    },
1139                                    _ => {
1140                                        lp_expr_stack.push(left_index);
1141                                    },
1142                                }
1143                            },
1144
1145                            // (a+c1)-c2 = a+(c1-c2)
1146                            (LpCompExpr(Addition, a_index, c1_index), LitVal(c2)) => {
1147                                match self.expr_clone_at(c1_index) {
1148                                    LitVal(c1) => {
1149                                        stop = false;
1150                                        self.overwrite_expr_at(
1151                                            right_index,
1152                                            LitVal(c1 - c2)
1153                                        );
1154                                        self.overwrite_expr_at(
1155                                            handled_expr_index,
1156                                            LpCompExpr(Addition, a_index, right_index)
1157                                        );
1158                                        lp_expr_stack.push(handled_expr_index);
1159                                    },
1160                                    _ => {
1161                                        lp_expr_stack.push(left_index);
1162                                    }
1163                                }
1164                            },
1165
1166                            // Extract the const:
1167                            // (a+c1)-x = (a-x)+c1
1168                            (LpCompExpr(Addition, a_index, b_index), _x) => {
1169                                match self.expr_clone_at(b_index) {
1170                                    LitVal(_c1) => {
1171                                        stop = false;
1172                                        self.overwrite_expr_at(
1173                                            left_index,
1174                                            LpCompExpr(Subtraction, a_index, right_index),
1175                                        );
1176                                        self.overwrite_expr_at(
1177                                            handled_expr_index,
1178                                            LpCompExpr(Addition, left_index, b_index)
1179                                        );
1180                                        lp_expr_stack.push(handled_expr_index);
1181                                    },
1182                                    _ => {
1183                                        lp_expr_stack.push(left_index);
1184                                        lp_expr_stack.push(right_index);
1185                                    }
1186                                }
1187                            }
1188                            (LpCompExpr(Subtraction, a_index, b_index), _x) => {
1189                                match (self.expr_clone_at(a_index), self.expr_clone_at(b_index)) {
1190                                    // (a-c1)-x = (a-x)-c1
1191                                    (_a, LitVal(_c1)) => {
1192                                        stop = false;
1193                                        self.overwrite_expr_at(
1194                                            left_index,
1195                                            LpCompExpr(Subtraction, a_index, right_index)
1196                                        );
1197                                        self.overwrite_expr_at(
1198                                            handled_expr_index,
1199                                            LpCompExpr(Subtraction, left_index, b_index)
1200                                        );
1201                                        lp_expr_stack.push(left_index);
1202                                    },
1203                                    // (c1-b)-x = (-b-x)+c1
1204                                    (LitVal(_c1), _b) => {
1205                                        stop = false;
1206                                        let minus_one_new_index = self.push_as_expr(&LitVal(-1.0));
1207                                        let minus_b_new_index = self.push_as_expr(
1208                                            &LpCompExpr(Multiplication, minus_one_new_index, b_index)
1209                                        );
1210                                        self.overwrite_expr_at(
1211                                            left_index,
1212                                            LpCompExpr(Subtraction, minus_b_new_index, right_index)
1213                                        );
1214                                        self.overwrite_expr_at(
1215                                            handled_expr_index,
1216                                            LpCompExpr(Addition, left_index, a_index)
1217                                        );
1218                                        lp_expr_stack.push(left_index);
1219                                    },
1220                                    _ => {
1221                                        lp_expr_stack.push(right_index);
1222                                        lp_expr_stack.push(left_index);
1223                                    }
1224                                }
1225                            },
1226                            (a, b) => {
1227                                // a - a = 0
1228                                if a == b {
1229                                    stop = false;
1230                                    self.overwrite_expr_at(
1231                                        handled_expr_index,
1232                                        LitVal(0.0)
1233                                    );
1234                                } else {
1235                                    match (a, b) {
1236                                        // recurse deeper and come back for any complex expressions not handled above
1237                                        (LpCompExpr(_, _, _), LpCompExpr(_, _, _)) => {
1238                                            lp_expr_stack.push(left_index);
1239                                            lp_expr_stack.push(right_index);
1240                                        },
1241                                        (LpCompExpr(_, _, _), _) => {
1242                                            lp_expr_stack.push(left_index);
1243                                        },
1244                                        (_, LpCompExpr(_, _, _)) => {
1245                                            lp_expr_stack.push(right_index);
1246                                        },
1247                                        (_, _) => { }
1248                                    }
1249                                }
1250                            }
1251                        }
1252                    },
1253                    ConsBin(_)
1254                    | ConsInt(_)
1255                    | ConsCont(_)
1256                    | LitVal(_)
1257                    | LpExprNode::EmptyExpr => { }
1258                };
1259            }
1260        }
1261        self
1262    }
1263}
1264
1265
1266#[derive(Debug, Clone, PartialEq)]
1267pub enum Constraint {
1268    /* Not supported by solver format files (lp file or mps file) !
1269    Greater,
1270    Less,
1271    */
1272    GreaterOrEqual,
1273    LessOrEqual,
1274    Equal,
1275}
1276
1277impl ToTokens for Constraint {
1278    fn to_tokens(&self, stream: &mut TokenStream) {
1279        stream.extend(
1280        match self {
1281            Constraint::GreaterOrEqual => quote!(Constraint::GreaterOrEqual),
1282            Constraint::LessOrEqual => quote!(Constraint::LessOrEqual),
1283            Constraint::Equal => quote!(Constraint::Equal),
1284        });
1285    }
1286}
1287
1288#[derive(Debug, Clone, PartialEq)]
1289pub struct LpConstraint(pub LpExpression, pub Constraint, pub LpExpression);
1290
1291impl LpConstraint {
1292    pub(crate) fn generalize(&self) -> LpConstraint {
1293        // TODO: Optimize tailrec
1294        let &LpConstraint(ref lhs, ref op, ref rhs) = self;
1295        let mut new_lhs_expr = lhs.merge_cloned_arenas(rhs, Subtraction);
1296        let constant = new_lhs_expr.simplify().split_off_constant();
1297        let new_rhs_expr_arena: LpExpression = LitVal(-constant).into();
1298        LpConstraint(new_lhs_expr, (*op).clone(), new_rhs_expr_arena)
1299    }
1300
1301    pub(crate) fn var(&self, expr_index: LpExprArenaIndex, constraint_index: usize, lst: &mut HashMap<String, (usize, LpExprArenaIndex)>) {
1302        match self.0.expr_ref_at(expr_index) {
1303            ConsBin(LpBinary { ref name, .. })
1304            | ConsInt(LpInteger { ref name, .. })
1305            | ConsCont(LpContinuous { ref name, .. }) => {
1306                lst.insert(name.clone(), (constraint_index, expr_index) );
1307            },
1308            LpCompExpr(Multiplication, _, e) => {
1309                self.var(*e, constraint_index, lst);
1310            },
1311            LpCompExpr(Addition, e1, e2)
1312            | LpCompExpr(Subtraction, e1, e2) => {
1313                self.var(*e1, constraint_index, lst);
1314                self.var(*e2, constraint_index, lst);
1315            }
1316            _ => (),
1317        }
1318    }
1319}
1320
1321impl ToTokens for LpConstraint {
1322    fn to_tokens(&self, stream: &mut TokenStream) {
1323        let lhs = &self.0;
1324        let constraint = &self.1;
1325        let rhs = &self.2;
1326        stream.extend(quote!(
1327            LpConstraint(
1328                #lhs, #constraint, #rhs
1329            )
1330        ));
1331    }
1332}
1333
1334
1335/// make a complete expression or a constraint with a vector of expressions
1336///
1337/// # Examples
1338///
1339/// ```
1340/// use lp_modeler::dsl::*;
1341///
1342/// let mut problem = LpProblem::new("My Problem", LpObjective::Maximize);
1343/// let ref a = LpBinary::new("a");
1344/// let ref b = LpBinary::new("b");
1345/// let ref c = LpBinary::new("c");
1346///
1347/// let ref v = vec!(a, b, c);
1348/// problem += lp_sum(v).equal(10.0);
1349/// ```
1350///
1351pub fn lp_sum<T>(expr: &Vec<T>) -> LpExpression
1352    where T: Into<LpExpression> + Clone {
1353    let mut results: Vec<LpExpression> = expr.iter().map(|e| e.clone().into()).collect();
1354    let mut next = Vec::with_capacity(results.len() / 2);
1355    while results.len() > 1 {
1356        while results.len() >= 2 {
1357            let right = results.pop().expect("impossible because len>2");
1358            let left = results.pop().expect("impossible because len>2");
1359            next.push(left + right)
1360        }
1361        next.append(&mut results);
1362        next.reverse(); // Required only if we want to maintain the order of operations
1363        std::mem::swap(&mut results, &mut next)
1364    }
1365    results.into_iter().next().unwrap_or( LpExpression::literal(0.0) )
1366}
1367
1368pub fn sum<'a, T: 'a,U: 'a>(expr: &'a Vec<T>, f: impl Fn(&'a T) -> U) -> LpExpression where U: Into<LpExpression> + Clone {
1369    return lp_sum(&expr.iter().map(|t| f(t.into())).collect());
1370}
1371
1372pub trait SummableExp {
1373    fn sum(&self) -> LpExpression;
1374}
1375
1376/// make a complete expression or a constraint with a vector of expressions
1377///
1378/// # Examples
1379///
1380/// ```
1381/// use lp_modeler::dsl::*;
1382///
1383/// let mut problem = LpProblem::new("My Problem", LpObjective::Maximize);
1384/// let ref a = LpBinary::new("a");
1385/// let ref b = LpBinary::new("b");
1386/// let ref c = LpBinary::new("c");
1387///
1388/// problem += vec!(a,b,c).sum().equal(10.0);
1389/// ```
1390///
1391impl<T> SummableExp for Vec<T> where T: Into<LpExpression> + Clone {
1392    fn sum(&self) -> LpExpression {
1393       lp_sum(self)
1394    }
1395}
1396#[cfg(test)]
1397mod tests {
1398    // Note this useful idiom: importing names from outer (for mod tests) scope.
1399    use super::*;
1400
1401    #[test]
1402    fn expressions_creation() {
1403        let ref a = LpInteger::new("a").lower_bound(10.0).upper_bound(20.0);
1404        let ref b = LpInteger::new("b");
1405
1406        assert_eq!(
1407            a + b,
1408            LpExpression::build(
1409                2,
1410                vec![LpExprNode::ConsInt(a.clone()), LpExprNode::ConsInt(b.clone()), LpExprNode::LpCompExpr(LpExprOp::Addition, 0, 1)]
1411            )
1412        );
1413    }
1414
1415    #[test]
1416    fn simplifications() {
1417        let a = &LpInteger::new("a");
1418
1419        let expr1 = a - 2f32;
1420        let expr2 = 1f32 - a;
1421
1422        let c = (expr1.clone() + expr2.clone()).simplify().split_off_constant();
1423        assert_eq!(c, -1f32);
1424
1425        let c = (expr2.clone() + expr1.clone()).simplify().split_off_constant();
1426        assert_eq!(c, -1f32);
1427    }
1428
1429    #[test]
1430    fn simplify_deep_sum() {
1431        let count = 1000;
1432        let vars: Vec<LpExpression> = (0..count)
1433            .map(|i|
1434                &LpInteger::new(&format!("v{}", i)) * 2 + 1
1435            )
1436            .collect();
1437        let mut sum = lp_sum(&vars);
1438        assert_eq!(sum.simplify().split_off_constant(), count as f32);
1439    }
1440
1441    #[test]
1442    fn test_quotations() {
1443        let a = LpInteger { name: "a".to_string(), lower_bound: None, upper_bound: None };
1444        let quoted_a = quote!(#a);
1445        let quoted_a_str = "LpInteger { name : \"a\" . to_string () , lower_bound : None , upper_bound : None }";
1446        assert_eq!(quoted_a.to_string(), quoted_a_str);
1447
1448        let exp: LpExprNode = a.clone().into();
1449        let quoted_exp = quote!(#exp);
1450        let quoted_exp_str = "LpExprNode :: ConsInt (".to_owned() + quoted_a_str + ")";
1451        assert_eq!(quoted_exp.to_string(), quoted_exp_str);
1452
1453        let full_exp_arena = LpExpression::build (0, vec![LpExprNode:: LpCompExpr (LpExprOp :: Multiplication, 1, 2), LpExprNode:: LpCompExpr (LpExprOp :: Subtraction, 3, 4 ), LpExprNode:: LpCompExpr (LpExprOp :: Addition, 5, 6), LpExprNode:: LitVal (1f32), LpExprNode:: EmptyExpr, LpExprNode:: ConsCont (LpContinuous { name : "x".to_string() , lower_bound : None , upper_bound : None }), LpExprNode:: ConsInt (LpInteger { name : "y".to_string() , lower_bound : None , upper_bound : None }) ] );
1454
1455
1456        let full_exp_quoted = quote!(#full_exp_arena);
1457        let full_exp_str = "LpExpression { root : 0usize , arena : struct LpExprNode :: LpCompExpr (LpExprOp :: Multiplication , 1usize , 2usize) ; , struct LpExprNode :: LpCompExpr (LpExprOp :: Subtraction , 3usize , 4usize) ; , struct LpExprNode :: LpCompExpr (LpExprOp :: Addition , 5usize , 6usize) ; , struct LpExprNode :: LitVal (1f32) ; , struct LpExprNode :: EmptyExpr ; , struct LpExprNode :: ConsCont (LpContinuous { name : \"x\" . to_string () , lower_bound : None , upper_bound : None }) ; , struct LpExprNode :: ConsInt (LpInteger { name : \"y\" . to_string () , lower_bound : None , upper_bound : None }) ; }";
1458        assert_eq!(full_exp_quoted.to_string(), full_exp_str);
1459
1460        // a.equal(&b);
1461        let a_eq_b = LpConstraint(LpExpression::build(0, vec![LpExprNode:: LpCompExpr(LpExprOp :: Subtraction, 1, 2), LpExprNode::ConsInt (LpInteger { name : "a".to_string() , lower_bound : None , upper_bound : None }), LpExprNode::ConsInt (LpInteger { name : "b".to_string() , lower_bound : None , upper_bound : None }) ] ), Constraint::Equal, LitVal(0f32).into());
1462
1463        let quoted_a_eq_b = quote!(#a_eq_b);
1464        let a_eq_b_str = "LpConstraint (LpExpression { root : 0usize , arena : struct LpExprNode :: LpCompExpr (LpExprOp :: Subtraction , 1usize , 2usize) ; , struct LpExprNode :: ConsInt (LpInteger { name : \"a\" . to_string () , lower_bound : None , upper_bound : None }) ; , struct LpExprNode :: ConsInt (LpInteger { name : \"b\" . to_string () , lower_bound : None , upper_bound : None }) ; } , Constraint :: Equal , LpExpression { root : 0usize , arena : struct LpExprNode :: LitVal (0f32) ; })";
1465        assert_eq!(quoted_a_eq_b.to_string(), a_eq_b_str);
1466    }
1467}