Skip to main content

scan_core/grammar/
float.rs

1use std::ops::{Add, Div, Mul, Neg};
2
3use get_size2::GetSize;
4use rand::{Rng, RngExt};
5
6use crate::{
7    Expression, Type, TypeError, Val,
8    grammar::{BooleanExpr, IntegerExpr, NaturalExpr},
9};
10
11/// Floating-point values.
12pub type Float = f64;
13
14/// Floating-point numerical expression.
15#[derive(Debug, Clone, GetSize)]
16pub enum FloatExpr<V>
17where
18    V: Clone,
19{
20    // -------------------
21    // General expressions
22    // -------------------
23    /// A constant value.
24    Const(Float),
25    /// A typed variable.
26    Var(V),
27    /// Conversion from Natural
28    Nat(NaturalExpr<V>),
29    /// Conversion from Integer
30    Int(IntegerExpr<V>),
31    // -------------
32    // Random values
33    // -------------
34    /// A random integer between a lower bound (included) and an upper bound (excluded).
35    Rand(Box<(FloatExpr<V>, FloatExpr<V>)>),
36    // --------------------
37    // Arithmetic operators
38    // --------------------
39    /// Opposite of a numerical expression.
40    Opposite(Box<FloatExpr<V>>),
41    /// Arithmetic n-ary sum.
42    Sum(Vec<FloatExpr<V>>),
43    /// Arithmetic n-ary multiplication.
44    Product(Vec<FloatExpr<V>>),
45    /// Div operation
46    Div(Box<(FloatExpr<V>, FloatExpr<V>)>),
47    // --------------------
48    // Order operators
49    // --------------------
50    /// Min of two values
51    Min(Box<(FloatExpr<V>, FloatExpr<V>)>),
52    /// Max of two values
53    Max(Box<(FloatExpr<V>, FloatExpr<V>)>),
54    // -----
55    // Flow
56    // -----
57    /// If-Then-Else construct, where If must be a boolean expression,
58    /// Then and Else must have the same type,
59    /// and this is also the type of the whole expression.
60    Ite(Box<(BooleanExpr<V>, FloatExpr<V>, FloatExpr<V>)>),
61}
62
63impl<V> FloatExpr<V>
64where
65    V: Copy,
66{
67    /// Returns `true` if the expression is constant, i.e., it contains no variables, and `false` otherwise.
68    pub fn is_constant(&self) -> bool {
69        match self {
70            FloatExpr::Const(_) => true,
71            FloatExpr::Var(_) | FloatExpr::Rand(_) => false,
72            FloatExpr::Nat(natural_expr) => natural_expr.is_constant(),
73            FloatExpr::Int(integer_expr) => integer_expr.is_constant(),
74
75            FloatExpr::Opposite(float_expr) => float_expr.is_constant(),
76            FloatExpr::Sum(float_exprs) | FloatExpr::Product(float_exprs) => {
77                float_exprs.iter().all(FloatExpr::is_constant)
78            }
79            FloatExpr::Div(args) | FloatExpr::Min(args) | FloatExpr::Max(args) => {
80                let (lhs, rhs) = args.as_ref();
81                lhs.is_constant() && rhs.is_constant()
82            }
83            FloatExpr::Ite(args) => {
84                let (ite, lhs, rhs) = args.as_ref();
85                ite.is_constant() && lhs.is_constant() && rhs.is_constant()
86            }
87        }
88    }
89
90    /// Returns the [`Float`] value computed from the expression,
91    /// given the variable evaluation.
92    /// It panics if the evaluation is not possible, including:
93    ///
94    /// - If a variable is not included in the evaluation;
95    /// - If a variable included in the evaluation is not of [`Float`] type;
96    /// - Division by 0;
97    /// - Overflow.
98    pub fn eval<R: Rng>(&self, vars: &dyn Fn(V) -> Val, mut rng: Option<&mut R>) -> Float {
99        match self {
100            FloatExpr::Const(float) => *float,
101            FloatExpr::Var(var) => {
102                if let Val::Float(float) = vars(*var) {
103                    float
104                } else {
105                    panic!("type mismatch: expected float variable")
106                }
107            }
108            // NOTE WARN: the u64 as f64 is lossy!
109            FloatExpr::Nat(natural_expr) => natural_expr.eval(vars, rng) as f64,
110            // NOTE WARN: the i64 as f64 is lossy!
111            FloatExpr::Int(integer_expr) => integer_expr.eval(vars, rng) as f64,
112            FloatExpr::Rand(bounds) => {
113                let (lower_bound_expr, upper_bound_expr) = bounds.as_ref();
114                let lower_bound = lower_bound_expr.eval(vars, rng.as_deref_mut());
115                let upper_bound = upper_bound_expr.eval(vars, rng.as_deref_mut());
116                rng.as_mut()
117                    .expect("rng")
118                    .random_range(lower_bound..upper_bound)
119            }
120            FloatExpr::Opposite(float_expr) => -float_expr.eval(vars, rng),
121            FloatExpr::Sum(float_exprs) => float_exprs
122                .iter()
123                .map(|expr| expr.eval(vars, rng.as_deref_mut()))
124                .sum(),
125            FloatExpr::Product(float_exprs) => float_exprs
126                .iter()
127                .map(|expr| expr.eval(vars, rng.as_deref_mut()))
128                .product(),
129            FloatExpr::Div(args) => {
130                let (lhs_expr, rhs_expr) = args.as_ref();
131                let lhs = lhs_expr.eval(vars, rng.as_deref_mut());
132                let rhs = rhs_expr.eval(vars, rng);
133                lhs / rhs
134            }
135            FloatExpr::Ite(args) => {
136                let (ite, lhs, rhs) = args.as_ref();
137                if ite.eval(vars, rng.as_deref_mut()) {
138                    lhs.eval(vars, rng)
139                } else {
140                    rhs.eval(vars, rng)
141                }
142            }
143            FloatExpr::Min(args) => {
144                let (lhs_expr, rhs_expr) = args.as_ref();
145                let lhs = lhs_expr.eval(vars, rng.as_deref_mut());
146                let rhs = rhs_expr.eval(vars, rng);
147                lhs.min(rhs)
148            }
149            FloatExpr::Max(args) => {
150                let (lhs_expr, rhs_expr) = args.as_ref();
151                let lhs = lhs_expr.eval(vars, rng.as_deref_mut());
152                let rhs = rhs_expr.eval(vars, rng);
153                lhs.max(rhs)
154            }
155        }
156    }
157
158    pub(crate) fn map<W: Clone>(self, map: &dyn Fn(V) -> W) -> FloatExpr<W> {
159        match self {
160            FloatExpr::Const(float) => FloatExpr::Const(float),
161            FloatExpr::Var(var) => FloatExpr::Var(map(var)),
162            FloatExpr::Nat(natural_expr) => FloatExpr::Nat(natural_expr.map(map)),
163            FloatExpr::Int(integer_expr) => FloatExpr::Int(integer_expr.map(map)),
164            FloatExpr::Rand(bounds) => {
165                let (lower_bound, upper_bound) = *bounds;
166                FloatExpr::Rand(Box::new((lower_bound.map(map), upper_bound.map(map))))
167            }
168            FloatExpr::Opposite(float_expr) => FloatExpr::Opposite(Box::new(float_expr.map(map))),
169            FloatExpr::Sum(float_exprs) => {
170                FloatExpr::Sum(float_exprs.into_iter().map(|expr| expr.map(map)).collect())
171            }
172            FloatExpr::Product(float_exprs) => {
173                FloatExpr::Product(float_exprs.into_iter().map(|expr| expr.map(map)).collect())
174            }
175            FloatExpr::Div(args) => {
176                let (lhs, rhs) = *args;
177                FloatExpr::Div(Box::new((lhs.map(map), rhs.map(map))))
178            }
179            FloatExpr::Ite(args) => {
180                let (r#if, then, r#else) = *args;
181                FloatExpr::Ite(Box::new((r#if.map(map), then.map(map), r#else.map(map))))
182            }
183            FloatExpr::Min(args) => {
184                let (lhs, rhs) = *args;
185                FloatExpr::Min(Box::new((lhs.map(map), rhs.map(map))))
186            }
187            FloatExpr::Max(args) => {
188                let (lhs, rhs) = *args;
189                FloatExpr::Max(Box::new((lhs.map(map), rhs.map(map))))
190            }
191        }
192    }
193
194    pub(crate) fn context(&self, vars: &dyn Fn(V) -> Option<Type>) -> Result<(), TypeError> {
195        match self {
196            FloatExpr::Const(_) => Ok(()),
197            FloatExpr::Var(v) => matches!(vars(*v), Some(Type::Float))
198                .then_some(())
199                .ok_or(TypeError::TypeMismatch),
200            FloatExpr::Nat(natural_expr) => natural_expr.context(vars),
201            FloatExpr::Int(integer_expr) => integer_expr.context(vars),
202            FloatExpr::Rand(exprs)
203            | FloatExpr::Div(exprs)
204            | FloatExpr::Min(exprs)
205            | FloatExpr::Max(exprs) => exprs.0.context(vars).and_then(|()| exprs.1.context(vars)),
206            FloatExpr::Opposite(integer_expr) => integer_expr.context(vars),
207            FloatExpr::Sum(integer_exprs) | FloatExpr::Product(integer_exprs) => {
208                integer_exprs.iter().try_for_each(|expr| expr.context(vars))
209            }
210            FloatExpr::Ite(exprs) => exprs
211                .0
212                .context(vars)
213                .and_then(|()| exprs.1.context(vars))
214                .and_then(|()| exprs.2.context(vars)),
215        }
216    }
217}
218
219impl<V> From<Float> for FloatExpr<V>
220where
221    V: Clone,
222{
223    fn from(value: Float) -> Self {
224        Self::Const(value)
225    }
226}
227
228impl<V> TryFrom<Expression<V>> for FloatExpr<V>
229where
230    V: Clone,
231{
232    type Error = TypeError;
233
234    fn try_from(value: Expression<V>) -> Result<Self, Self::Error> {
235        match value {
236            Expression::Boolean(_) => Err(TypeError::TypeMismatch),
237            Expression::Natural(natural_expr) => Ok(FloatExpr::Nat(natural_expr)),
238            Expression::Integer(integer_expr) => Ok(FloatExpr::Int(integer_expr)),
239            Expression::Float(float_expr) => Ok(float_expr),
240        }
241    }
242}
243
244impl<V> From<NaturalExpr<V>> for FloatExpr<V>
245where
246    V: Clone,
247{
248    fn from(value: NaturalExpr<V>) -> Self {
249        Self::Nat(value)
250    }
251}
252
253impl<V> From<IntegerExpr<V>> for FloatExpr<V>
254where
255    V: Clone,
256{
257    fn from(value: IntegerExpr<V>) -> Self {
258        if let IntegerExpr::Nat(nat_expr) = value {
259            Self::Nat(nat_expr)
260        } else {
261            Self::Int(value)
262        }
263    }
264}
265
266impl<V> Add for FloatExpr<V>
267where
268    V: Clone,
269{
270    type Output = Self;
271
272    fn add(mut self, mut rhs: Self) -> Self::Output {
273        if let FloatExpr::Sum(ref mut exprs) = self {
274            if let FloatExpr::Sum(rhs_exprs) = rhs {
275                exprs.extend(rhs_exprs);
276            } else {
277                exprs.push(rhs);
278            }
279            self
280        } else if let FloatExpr::Sum(ref mut rhs_exprs) = rhs {
281            rhs_exprs.push(self);
282            rhs
283        } else {
284            FloatExpr::Sum(vec![self, rhs])
285        }
286    }
287}
288
289impl<V> Mul for FloatExpr<V>
290where
291    V: Clone,
292{
293    type Output = Self;
294
295    fn mul(mut self, mut rhs: Self) -> Self::Output {
296        if let FloatExpr::Product(ref mut exprs) = self {
297            if let FloatExpr::Product(rhs_exprs) = rhs {
298                exprs.extend(rhs_exprs);
299            } else {
300                exprs.push(rhs);
301            }
302            self
303        } else if let FloatExpr::Product(ref mut rhs_exprs) = rhs {
304            rhs_exprs.push(self);
305            rhs
306        } else {
307            FloatExpr::Product(vec![self, rhs])
308        }
309    }
310}
311
312impl<V> Neg for FloatExpr<V>
313where
314    V: Clone,
315{
316    type Output = Self;
317
318    fn neg(self) -> Self::Output {
319        if let FloatExpr::Opposite(expr) = self {
320            *expr
321        } else {
322            FloatExpr::Opposite(Box::new(self))
323        }
324    }
325}
326
327impl<V> Div for FloatExpr<V>
328where
329    V: Clone,
330{
331    type Output = Self;
332
333    fn div(self, rhs: Self) -> Self::Output {
334        FloatExpr::Div(Box::new((self, rhs)))
335    }
336}