lp_modeler/dsl/
operations.rs

1use std::ops::{Add, Mul, Neg, Sub, AddAssign, SubAssign, MulAssign};
2use dsl::LpExprNode::*;
3use dsl::{Constraint, LpBinary, LpConstraint, LpContinuous, LpExprNode, LpInteger, LpExpression};
4use dsl::LpExprOp::{Addition, Subtraction, Multiplication};
5
6/// Operations trait for any type implementing Into<LpExpression> trait
7pub trait LpOperations<T> where T: Into<LpExpression> {
8    /// Less or equal binary syntax for LpExpression
9    fn le(&self, lhs_expr: T) -> LpConstraint;
10    /// Greater or equal binary syntax for LpExpression
11    fn ge(&self, lhs_expr: T) -> LpConstraint;
12    /// Equality binary syntax for LpExpression
13    fn equal(&self, lhs_expr: T) -> LpConstraint;
14}
15
16/// Macro implementing binary operations for Into<LpExpression> or &Into<LpExpression>
17macro_rules! operations_for_expr {
18    ($trait_name: ident, $f_name: ident, $expr_type: ident) => {
19        impl<T> $trait_name<T> for LpExpression
20        where
21            T: Into<LpExpression> + Clone,
22        {
23            type Output = LpExpression;
24            fn $f_name(self, not_yet_lp_expr_arena: T) -> LpExpression {
25                let new_lp_expr_arena = self.clone();
26                new_lp_expr_arena.merge_cloned_arenas(&not_yet_lp_expr_arena.into(), $expr_type)
27            }
28        }
29        impl<'a, T> $trait_name<T> for &'a LpExpression
30        where
31            T: Into<LpExpression> + Clone,
32        {
33            type Output = LpExpression;
34            fn $f_name(self, not_yet_lp_expr_arena: T) -> LpExpression {
35                let new_lp_expr_arena = (*self).clone();
36                new_lp_expr_arena.merge_cloned_arenas(&not_yet_lp_expr_arena.into(), $expr_type)
37            }
38        }
39    };
40}
41
42operations_for_expr!(Add, add, Addition);
43operations_for_expr!(Sub, sub, Subtraction);
44operations_for_expr!(Mul, mul, Multiplication);
45
46macro_rules! assign_operations_for_expr {
47    ($trait_name: ident, $f_name: ident, $expr_type: ident) => {
48        impl<T> $trait_name<T> for LpExpression
49        where
50            T: Into<LpExpression> + Clone,
51        {
52            fn $f_name(&mut self, rhs: T) {
53                *self = self.merge_cloned_arenas(&rhs.into(), $expr_type)
54            }
55        }
56    };
57}
58
59assign_operations_for_expr!(AddAssign, add_assign, Addition);
60assign_operations_for_expr!(SubAssign, sub_assign, Subtraction);
61assign_operations_for_expr!(MulAssign, mul_assign, Multiplication);
62
63/// Macro implementing a binary operation with a LpVars and a Into<Expression>
64macro_rules! lpvars_operation_for_intoexpr {
65    ($trait_name: ident, $f_name: ident, $lp_type: ident, $expr_type: ident) => {
66        impl<T> $trait_name<T> for $lp_type
67        where
68            T: Into<LpExpression> + Clone,
69        {
70            type Output = LpExpression;
71            fn $f_name(self, not_yet_lp_expr_arena: T) -> LpExpression {
72                let new_lp_expr_arena: LpExpression = self.clone().into();
73                new_lp_expr_arena.merge_cloned_arenas(&not_yet_lp_expr_arena.into(), $expr_type)
74            }
75        }
76        impl<'a, T> $trait_name<T> for &'a $lp_type
77        where
78            T: Into<LpExpression> + Clone,
79        {
80            type Output = LpExpression;
81            fn $f_name(self, not_yet_lp_expr_arena: T) -> LpExpression {
82                let new_lp_expr_arena: LpExpression = (*self).clone().into();
83                new_lp_expr_arena.merge_cloned_arenas(&not_yet_lp_expr_arena.into(), $expr_type)
84            }
85        }
86    };
87}
88
89lpvars_operation_for_intoexpr!(Mul, mul, LpBinary, Multiplication);
90lpvars_operation_for_intoexpr!(Add, add, LpBinary, Addition);
91lpvars_operation_for_intoexpr!(Sub, sub, LpBinary, Subtraction);
92lpvars_operation_for_intoexpr!(Mul, mul, LpInteger, Multiplication);
93lpvars_operation_for_intoexpr!(Add, add, LpInteger, Addition);
94lpvars_operation_for_intoexpr!(Sub, sub, LpInteger, Subtraction);
95lpvars_operation_for_intoexpr!(Mul, mul, LpContinuous, Multiplication);
96lpvars_operation_for_intoexpr!(Add, add, LpContinuous, Addition);
97lpvars_operation_for_intoexpr!(Sub, sub, LpContinuous, Subtraction);
98
99/// Macro implementing binary operations for a numeric type
100macro_rules! numeric_operation_for_expr {
101    ($num_type: ty, $trait_name: ident, $f_name: ident, $type_expr: ident) => {
102        impl $trait_name<LpExpression> for $num_type {
103            type Output = LpExpression;
104            fn $f_name(self, lp_expr_arena: LpExpression) -> LpExpression {
105                let new_lp_expr_arena: LpExpression = (self as f32).into();
106                new_lp_expr_arena.merge_cloned_arenas(&lp_expr_arena.clone(), $type_expr)
107            }
108        }
109        impl<'a> $trait_name<&'a LpExpression> for $num_type {
110            type Output = LpExpression;
111            fn $f_name(self, lp_expr_arena: &'a LpExpression) -> LpExpression {
112                let new_lp_expr_arena: LpExpression = (self as f32).into();
113                new_lp_expr_arena.merge_cloned_arenas(lp_expr_arena, $type_expr)
114            }
115        }
116    };
117}
118/// Macro implementing add, mul and sub for a specific numeric type
119macro_rules! numeric_all_ops_for_expr {
120    ($num_type: ty) => {
121        numeric_operation_for_expr!($num_type, Add, add, Addition);
122        numeric_operation_for_expr!($num_type, Mul, mul, Multiplication);
123        numeric_operation_for_expr!($num_type, Sub, sub, Subtraction);
124    };
125}
126numeric_all_ops_for_expr!(f32);
127numeric_all_ops_for_expr!(i32);
128
129/// &LpExpression to LpExpression
130impl<'a> Into<LpExpression> for &'a LpExpression {
131    fn into(self) -> LpExpression {
132        (*self).clone()
133    }
134}
135
136/// Implementing LpOperations trait for any Into<LpExpression>
137impl<T: Into<LpExpression> + Clone, U> LpOperations<T> for U where U: Into<LpExpression> + Clone {
138    fn le(&self, lhs_expr: T) -> LpConstraint {
139        LpConstraint(
140            self.clone().into(),
141            Constraint::LessOrEqual,
142            lhs_expr.clone().into(),
143        )
144        .generalize()
145    }
146    fn ge(&self, lhs_expr: T) -> LpConstraint {
147        LpConstraint(
148            self.clone().into(),
149            Constraint::GreaterOrEqual,
150            lhs_expr.clone().into(),
151        )
152        .generalize()
153    }
154    fn equal(&self, lhs_expr: T) -> LpConstraint {
155        LpConstraint(
156            self.clone().into(),
157            Constraint::Equal,
158            lhs_expr.clone().into(),
159        )
160        .generalize()
161    }
162}
163
164impl<'a> Neg for &'a LpExprNode {
165    type Output = LpExpression;
166    fn neg(self) -> LpExpression {
167        let new_lp_expr_arena: LpExpression = LitVal(-1.0).into();
168        new_lp_expr_arena.merge_cloned_arenas(&self.clone().into(), Multiplication)
169    }
170}
171
172macro_rules! neg_operation_for_lpvars {
173    ($lp_var_type: ty) => {
174        impl<'a> Neg for &'a $lp_var_type {
175            type Output = LpExpression;
176            fn neg(self) -> LpExpression {
177                let new_lp_expr_arena: LpExpression = LitVal(-1.0).into();
178                new_lp_expr_arena.merge_cloned_arenas(&self.clone().into(), Multiplication)
179            }
180        }
181    };
182}
183neg_operation_for_lpvars!(LpInteger);
184neg_operation_for_lpvars!(LpContinuous);
185neg_operation_for_lpvars!(LpBinary);
186
187/// Macro implementing binary operations for a numeric type
188macro_rules! numeric_operation_for_lpvars {
189    ($num_type_left: ty, $trait_name: ident, $f_name: ident, $type_expr: ident, $lp_type_right: ty) => {
190        impl $trait_name<$lp_type_right> for $num_type_left {
191            type Output = LpExpression;
192            fn $f_name(self, var: $lp_type_right) -> LpExpression {
193                let new_lp_expr_arena: LpExpression = (self as f32).clone().into();
194                let new_right: LpExpression = var.clone().into();
195                new_lp_expr_arena.merge_cloned_arenas(&new_right, $type_expr)
196            }
197        }
198        impl<'a> $trait_name<&'a $lp_type_right> for $num_type_left {
199            type Output = LpExpression;
200            fn $f_name(self, var: &'a $lp_type_right) -> LpExpression {
201                let new_lp_expr_arena: LpExpression = (self as f32).into();
202                let new_right: LpExpression = (*var).clone().into();
203                new_lp_expr_arena.merge_cloned_arenas(&new_right, $type_expr)
204            }
205        }
206    };
207}
208
209/// Macro implementing add, mul and sub for a specific numeric type
210macro_rules! numeric_all_ops_for_lpvars {
211    ($num_type: ty) => {
212        numeric_operation_for_lpvars!($num_type, Add, add, Addition, LpInteger);
213        numeric_operation_for_lpvars!($num_type, Add, add, Addition, LpBinary);
214        numeric_operation_for_lpvars!($num_type, Add, add, Addition, LpContinuous);
215        numeric_operation_for_lpvars!($num_type, Mul, mul, Multiplication, LpInteger);
216        numeric_operation_for_lpvars!($num_type, Mul, mul, Multiplication, LpBinary);
217        numeric_operation_for_lpvars!($num_type, Mul, mul, Multiplication, LpContinuous);
218        numeric_operation_for_lpvars!($num_type, Sub, sub, Subtraction, LpInteger);
219        numeric_operation_for_lpvars!($num_type, Sub, sub, Subtraction, LpBinary);
220        numeric_operation_for_lpvars!($num_type, Sub, sub, Subtraction, LpContinuous);
221    };
222}
223numeric_all_ops_for_lpvars!(i32);
224numeric_all_ops_for_lpvars!(f32);