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
6pub trait LpOperations<T> where T: Into<LpExpression> {
8 fn le(&self, lhs_expr: T) -> LpConstraint;
10 fn ge(&self, lhs_expr: T) -> LpConstraint;
12 fn equal(&self, lhs_expr: T) -> LpConstraint;
14}
15
16macro_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(¬_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(¬_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
63macro_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(¬_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(¬_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
99macro_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}
118macro_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
129impl<'a> Into<LpExpression> for &'a LpExpression {
131 fn into(self) -> LpExpression {
132 (*self).clone()
133 }
134}
135
136impl<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
187macro_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
209macro_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);