1use std::ops::{Add, Div, Mul, Neg, Sub};
2
3use crate::arena::{Children, ExprId, ExprNode};
4use crate::handle::Expr;
5use crate::linear::{add_into, add_n, div_into, mul_into, neg_into, sub_into};
6
7impl<'a> Add for Expr<'a> {
12 type Output = Self;
13 fn add(self, rhs: Self) -> Self {
14 self.assert_same_arena(rhs);
15 let id = self.arena.with_mut(|arena| add_into(arena, self.id, rhs.id));
16 Self::new(id, self.arena)
17 }
18}
19
20impl<'a> Sub for Expr<'a> {
21 type Output = Self;
22 fn sub(self, rhs: Self) -> Self {
23 self.assert_same_arena(rhs);
24 let id = self.arena.with_mut(|arena| sub_into(arena, self.id, rhs.id));
25 Self::new(id, self.arena)
26 }
27}
28
29impl<'a> Mul for Expr<'a> {
30 type Output = Self;
31 fn mul(self, rhs: Self) -> Self {
32 self.assert_same_arena(rhs);
33 let id = self.arena.with_mut(|arena| mul_into(arena, self.id, rhs.id));
34 Self::new(id, self.arena)
35 }
36}
37
38impl<'a> Div for Expr<'a> {
39 type Output = Self;
40 fn div(self, rhs: Self) -> Self {
41 self.assert_same_arena(rhs);
42 let id = self.arena.with_mut(|arena| div_into(arena, self.id, rhs.id));
43 Self::new(id, self.arena)
44 }
45}
46
47impl<'a> Neg for Expr<'a> {
48 type Output = Self;
49 fn neg(self) -> Self {
50 let id = self.arena.with_mut(|arena| neg_into(arena, self.id));
51 Self::new(id, self.arena)
52 }
53}
54
55macro_rules! impl_scalar_ops {
61 ($scalar:ty, $to_f64:expr) => {
62 impl<'a> Add<$scalar> for Expr<'a> {
63 type Output = Self;
64 fn add(self, rhs: $scalar) -> Self {
65 let id = self.arena.with_mut(|arena| {
66 let rhs_id = arena.constant($to_f64(rhs));
67 add_into(arena, self.id, rhs_id)
68 });
69 Self::new(id, self.arena)
70 }
71 }
72
73 impl<'a> Add<Expr<'a>> for $scalar {
74 type Output = Expr<'a>;
75 fn add(self, rhs: Expr<'a>) -> Expr<'a> {
76 rhs + self
77 }
78 }
79
80 impl<'a> Sub<$scalar> for Expr<'a> {
81 type Output = Self;
82 fn sub(self, rhs: $scalar) -> Self {
83 let id = self.arena.with_mut(|arena| {
84 let rhs_id = arena.constant($to_f64(rhs));
85 sub_into(arena, self.id, rhs_id)
86 });
87 Self::new(id, self.arena)
88 }
89 }
90
91 impl<'a> Sub<Expr<'a>> for $scalar {
92 type Output = Expr<'a>;
93 fn sub(self, rhs: Expr<'a>) -> Expr<'a> {
94 let id = rhs.arena.with_mut(|arena| {
95 let lhs_id = arena.constant($to_f64(self));
96 sub_into(arena, lhs_id, rhs.id)
97 });
98 Expr::new(id, rhs.arena)
99 }
100 }
101
102 impl<'a> Mul<$scalar> for Expr<'a> {
103 type Output = Self;
104 fn mul(self, rhs: $scalar) -> Self {
105 let id = self.arena.with_mut(|arena| {
106 let rhs_id = arena.constant($to_f64(rhs));
107 mul_into(arena, self.id, rhs_id)
108 });
109 Self::new(id, self.arena)
110 }
111 }
112
113 impl<'a> Mul<Expr<'a>> for $scalar {
114 type Output = Expr<'a>;
115 fn mul(self, rhs: Expr<'a>) -> Expr<'a> {
116 rhs * self
117 }
118 }
119
120 impl<'a> Div<$scalar> for Expr<'a> {
121 type Output = Self;
122 fn div(self, rhs: $scalar) -> Self {
123 let id = self.arena.with_mut(|arena| {
124 let rhs_id = arena.constant($to_f64(rhs));
125 div_into(arena, self.id, rhs_id)
126 });
127 Self::new(id, self.arena)
128 }
129 }
130
131 impl<'a> Div<Expr<'a>> for $scalar {
132 type Output = Expr<'a>;
133 fn div(self, rhs: Expr<'a>) -> Expr<'a> {
134 let id = rhs.arena.with_mut(|arena| {
135 let lhs_id = arena.constant($to_f64(self));
136 div_into(arena, lhs_id, rhs.id)
137 });
138 Expr::new(id, rhs.arena)
139 }
140 }
141 };
142}
143
144impl_scalar_ops!(f64, core::convert::identity);
145impl_scalar_ops!(i32, f64::from);
146
147fn sum_children(first: ExprId, rest: impl Iterator<Item = ExprId>) -> Children {
153 let capacity = rest.size_hint().0.saturating_add(1);
154 let mut children = Children::new();
155 if capacity > children.inline_size() {
156 let mut ids = Vec::with_capacity(capacity);
158 ids.push(first);
159 ids.extend(rest);
160 Children::from_vec(ids)
161 } else {
162 children.push(first);
163 children.extend(rest);
164 children
165 }
166}
167
168impl<'a> std::iter::Sum for Expr<'a> {
169 fn sum<I: Iterator<Item = Self>>(mut iter: I) -> Self {
170 let first = iter.next().expect("Expr::sum on empty iterator");
171 let ids = sum_children(
172 first.id,
173 iter.map(|expr| {
174 first.assert_same_arena(expr);
175 expr.id
176 }),
177 );
178 let id = first.arena.with_mut(|arena| add_n(arena, ids));
179 Self::new(id, first.arena)
180 }
181}
182
183impl<'a> Expr<'a> {
184 #[doc(hidden)]
188 pub fn __sum_terms(mut iter: impl Iterator<Item = Self>) -> Option<Self> {
189 let first = iter.next()?;
190 let mut same_arena = true;
191 let ids = sum_children(
192 first.id,
193 iter.map(|expr| {
194 same_arena &= std::ptr::eq(first.arena, expr.arena);
195 expr.id
196 }),
197 );
198 assert!(same_arena, "expressions belong to different arenas");
199 let id = first.arena.with_mut(|arena| add_n(arena, ids));
200 Some(Self::new(id, first.arena))
201 }
202
203 #[doc(hidden)]
206 pub fn __sum_terms_in(
207 arena: &'a crate::ExprArenaCell,
208 mut iter: impl Iterator<Item = Self>,
209 ) -> Self {
210 let Some(first) = iter.next() else {
211 return Self::constant(arena, 0.0);
212 };
213 let mut same_arena = std::ptr::eq(arena, first.arena);
214 let ids = sum_children(
215 first.id,
216 iter.map(|expr| {
217 same_arena &= std::ptr::eq(arena, expr.arena);
218 expr.id
219 }),
220 );
221 assert!(same_arena, "sum! terms belong to a different model");
222 let id = arena.with_mut(|arena| add_n(arena, ids));
223 Self::new(id, arena)
224 }
225
226 fn extrema_terms(mut iter: impl Iterator<Item = Self>, is_min: bool) -> Option<Self> {
227 let first = iter.next()?;
228 let mut same_arena = true;
229 let mut ids = Children::new();
230 let mut append = |expr: Self| {
231 same_arena &= std::ptr::eq(first.arena, expr.arena);
232 expr.arena.with_ref(|arena| match arena.get(expr.id) {
233 ExprNode::Min(children) if is_min => ids.extend_from_slice(children),
234 ExprNode::Max(children) if !is_min => ids.extend_from_slice(children),
235 _ => ids.push(expr.id),
236 });
237 };
238 append(first);
239 for expr in iter {
240 append(expr);
241 }
242 assert!(same_arena, "expressions belong to different arenas");
243 if ids.len() == 1 {
244 return Some(Self::new(ids[0], first.arena));
245 }
246 let id = first.arena.with_mut(|arena| {
247 arena.push(if is_min { ExprNode::Min(ids) } else { ExprNode::Max(ids) })
248 });
249 Some(Self::new(id, first.arena))
250 }
251
252 #[doc(hidden)]
254 pub fn __min_terms(iter: impl Iterator<Item = Self>) -> Option<Self> {
255 Self::extrema_terms(iter, true)
256 }
257
258 #[doc(hidden)]
260 pub fn __max_terms(iter: impl Iterator<Item = Self>) -> Option<Self> {
261 Self::extrema_terms(iter, false)
262 }
263}
264
265impl<'a, 'b> std::iter::Sum<&'b Expr<'a>> for Expr<'a> {
266 fn sum<I: Iterator<Item = &'b Expr<'a>>>(iter: I) -> Self {
267 iter.copied().sum()
268 }
269}
270
271pub fn dot<'a>(exprs: &[Expr<'a>], coeffs: &[f64]) -> Expr<'a> {
280 assert_eq!(
281 exprs.len(),
282 coeffs.len(),
283 "dot: length mismatch (exprs.len() = {}, coeffs.len() = {})",
284 exprs.len(),
285 coeffs.len(),
286 );
287 exprs.iter().zip(coeffs).map(|(e, c)| *c * *e).sum()
288}