1use std::{
2 iter,
3 ops::{self, Add, Mul, Neg, Sub},
4};
5
6use powdr_number::ExpressionConvertible;
7use schemars::JsonSchema;
8use serde::{Deserialize, Serialize};
9
10pub mod display;
11pub mod visitors;
12
13#[derive(
14 Debug,
15 PartialEq,
16 Eq,
17 PartialOrd,
18 Ord,
19 Clone,
20 Serialize,
21 Deserialize,
22 JsonSchema,
23 Hash,
24 derive_more::Display,
25)]
26pub enum AlgebraicExpression<T, R> {
27 #[serde(untagged)]
28 Reference(R),
29 #[serde(untagged)]
30 Number(T),
31 #[serde(untagged, serialize_with = "serialize_binary_operation")]
32 BinaryOperation(AlgebraicBinaryOperation<T, R>),
33 #[serde(untagged, serialize_with = "serialize_unary_operation")]
34 UnaryOperation(AlgebraicUnaryOperation<T, R>),
35}
36
37#[derive(
38 Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Serialize, Deserialize, JsonSchema, Hash,
39)]
40pub struct AlgebraicBinaryOperation<T, R> {
41 pub left: Box<AlgebraicExpression<T, R>>,
42 pub op: AlgebraicBinaryOperator,
43 pub right: Box<AlgebraicExpression<T, R>>,
44}
45
46#[derive(
47 Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Serialize, Deserialize, JsonSchema, Hash,
48)]
49pub enum AlgebraicBinaryOperator {
50 #[serde(rename = "+")]
51 Add,
52 #[serde(rename = "-")]
53 Sub,
54 #[serde(rename = "*")]
55 Mul,
56}
57
58#[derive(
59 Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Serialize, Deserialize, JsonSchema, Hash,
60)]
61pub struct AlgebraicUnaryOperation<T, R> {
62 pub op: AlgebraicUnaryOperator,
63 pub expr: Box<AlgebraicExpression<T, R>>,
64}
65
66#[derive(
67 Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Serialize, Deserialize, JsonSchema, Hash,
68)]
69pub enum AlgebraicUnaryOperator {
70 #[serde(rename = "-")]
71 Minus,
72}
73
74impl<T, R> AlgebraicExpression<T, R> {
75 fn children(&self) -> Box<dyn Iterator<Item = &AlgebraicExpression<T, R>> + '_> {
80 match self {
81 AlgebraicExpression::Reference(_) | AlgebraicExpression::Number(_) => {
82 Box::new(iter::empty())
83 }
84 AlgebraicExpression::BinaryOperation(AlgebraicBinaryOperation {
85 left, right, ..
86 }) => Box::new([left.as_ref(), right.as_ref()].into_iter()),
87 AlgebraicExpression::UnaryOperation(AlgebraicUnaryOperation { expr: e, .. }) => {
88 Box::new([e.as_ref()].into_iter())
89 }
90 }
91 }
92 fn children_mut(&mut self) -> Box<dyn Iterator<Item = &mut AlgebraicExpression<T, R>> + '_> {
97 match self {
98 AlgebraicExpression::Reference(_) | AlgebraicExpression::Number(_) => {
99 Box::new(iter::empty())
100 }
101 AlgebraicExpression::BinaryOperation(AlgebraicBinaryOperation {
102 left, right, ..
103 }) => Box::new([left.as_mut(), right.as_mut()].into_iter()),
104 AlgebraicExpression::UnaryOperation(AlgebraicUnaryOperation { expr: e, .. }) => {
105 Box::new([e.as_mut()].into_iter())
106 }
107 }
108 }
109
110 pub fn degree(&self) -> usize {
112 match self {
113 AlgebraicExpression::Reference(..) => 1,
114 AlgebraicExpression::BinaryOperation(AlgebraicBinaryOperation {
116 op: AlgebraicBinaryOperator::Mul,
117 left,
118 right,
119 }) => left.degree() + right.degree(),
120 _ => self.children().map(|e| e.degree()).max().unwrap_or(0),
122 }
123 }
124
125 pub fn new_binary(left: Self, op: AlgebraicBinaryOperator, right: Self) -> Self {
126 AlgebraicExpression::BinaryOperation(AlgebraicBinaryOperation {
127 left: Box::new(left),
128 op,
129 right: Box::new(right),
130 })
131 }
132
133 pub fn new_unary(op: AlgebraicUnaryOperator, expr: Self) -> Self {
134 AlgebraicExpression::UnaryOperation(AlgebraicUnaryOperation {
135 op,
136 expr: Box::new(expr),
137 })
138 }
139}
140
141impl<T, R> ops::Add for AlgebraicExpression<T, R> {
142 type Output = Self;
143
144 fn add(self, rhs: Self) -> Self::Output {
145 Self::new_binary(self, AlgebraicBinaryOperator::Add, rhs)
146 }
147}
148
149impl<T, R> ops::Sub for AlgebraicExpression<T, R> {
150 type Output = Self;
151
152 fn sub(self, rhs: Self) -> Self::Output {
153 Self::new_binary(self, AlgebraicBinaryOperator::Sub, rhs)
154 }
155}
156
157impl<T, R> ops::Neg for AlgebraicExpression<T, R> {
158 type Output = Self;
159
160 fn neg(self) -> Self::Output {
161 Self::new_unary(AlgebraicUnaryOperator::Minus, self)
162 }
163}
164
165impl<T, R> ops::Mul for AlgebraicExpression<T, R> {
166 type Output = Self;
167
168 fn mul(self, rhs: Self) -> Self::Output {
169 Self::new_binary(self, AlgebraicBinaryOperator::Mul, rhs)
170 }
171}
172
173impl<T, R> From<T> for AlgebraicExpression<T, R> {
174 fn from(value: T) -> Self {
175 AlgebraicExpression::Number(value)
176 }
177}
178
179impl<T, R> ExpressionConvertible<T, R> for AlgebraicExpression<T, R> {
180 fn to_expression<
181 E: Add<E, Output = E> + Sub<E, Output = E> + Mul<E, Output = E> + Neg<Output = E>,
182 >(
183 &self,
184 number_converter: &impl Fn(&T) -> E,
185 var_converter: &impl Fn(&R) -> E,
186 ) -> E {
187 match self {
188 AlgebraicExpression::Reference(r) => var_converter(r),
189 AlgebraicExpression::Number(n) => number_converter(n),
190 AlgebraicExpression::BinaryOperation(AlgebraicBinaryOperation { left, op, right }) => {
191 let left = left.to_expression(number_converter, var_converter);
192 let right = right.to_expression(number_converter, var_converter);
193
194 match op {
195 AlgebraicBinaryOperator::Add => left + right,
196 AlgebraicBinaryOperator::Sub => left - right,
197 AlgebraicBinaryOperator::Mul => left * right,
198 }
199 }
200 AlgebraicExpression::UnaryOperation(AlgebraicUnaryOperation { op, expr }) => match op {
201 AlgebraicUnaryOperator::Minus => {
202 -expr.to_expression(number_converter, var_converter)
203 }
204 },
205 }
206 }
207}
208
209fn serialize_unary_operation<S, T, R>(
210 un_op: &AlgebraicUnaryOperation<T, R>,
211 serializer: S,
212) -> Result<S::Ok, S::Error>
213where
214 S: serde::Serializer,
215 T: Serialize,
216 R: Serialize,
217{
218 (&un_op.op, un_op.expr.as_ref()).serialize(serializer)
219}
220
221fn serialize_binary_operation<S, T, R>(
222 bin_op: &AlgebraicBinaryOperation<T, R>,
223 serializer: S,
224) -> Result<S::Ok, S::Error>
225where
226 S: serde::Serializer,
227 T: Serialize,
228 R: Serialize,
229{
230 (bin_op.left.as_ref(), &bin_op.op, bin_op.right.as_ref()).serialize(serializer)
231}
232
233#[cfg(test)]
234mod tests {
235 use super::*;
236
237 #[test]
238 fn test_serde() {
239 let x: AlgebraicExpression<u32, &'static str> = AlgebraicExpression::from(5)
240 * AlgebraicExpression::Reference("x")
241 - AlgebraicExpression::from(3);
242 let serialized = serde_json::to_string(&x).unwrap();
243 assert_eq!(serialized, r#"[[5,"*","x"],"-",3]"#);
244 let deserialized = serde_json::from_str(&serialized).unwrap();
245 assert_eq!(x, deserialized);
246 }
247}