arcis_compiler/
types.rs

1use crate::{
2    core::{
3        circuits::boolean::utils::shift_right,
4        expressions::{circuit::ArithmeticCircuitId, field_expr::FieldExpr},
5        global_value::{field_array::FieldArray, value::FieldValue},
6    },
7    traits::*,
8    utils::{field::BaseField, number::Number, used_field::UsedField},
9};
10use ff::Field;
11use std::ops::{Add, Div, Mul, Sub};
12
13pub type ArcisField = BaseField;
14pub type ArcisValue = FieldValue<ArcisField>;
15pub type ArcisArray<const N: usize> = FieldArray<N, ArcisField>;
16
17#[derive(Debug, Clone, Copy)]
18pub struct ArcisFloatValue(pub ArcisValue);
19
20impl ArcisFloatValue {
21    pub const MINUS_PLSB: usize = DOUBLE_PRECISION_MANTISSA;
22    pub fn max_bounds() -> (ArcisField, ArcisField) {
23        (
24            -ArcisField::power_of_two(127),
25            ArcisField::power_of_two(127) - ArcisField::ONE,
26        )
27    }
28    pub fn number_to_f64(a: Number) -> f64 {
29        f64::from(a) / 2.0f64.powi(52)
30    }
31    pub fn number_with_precision_to_f64(a: Number, precision: usize) -> f64 {
32        f64::from(a) / 2.0f64.powi(precision as i32)
33    }
34    pub fn i128_to_f64(a: i128) -> f64 {
35        Self::number_to_f64(a.into())
36    }
37    pub fn i128_to_f32(a: i128) -> f32 {
38        Self::i128_to_f64(a) as f32
39    }
40    pub fn f64_to_i128(a: f64) -> i128 {
41        let value = a.clamp(-(2f64.powi(75)), 2f64.powi(75));
42        (value * 2f64.powi(DOUBLE_PRECISION_MANTISSA as i32)) as i128
43    }
44    pub fn f32_to_i128(a: f32) -> i128 {
45        let value = a.clamp(-(2f32.powi(75)), 2f32.powi(75));
46        (value * 2f32.powi(DOUBLE_PRECISION_MANTISSA as i32)) as i128
47    }
48    pub fn f64_to_number(a: f64) -> Number {
49        let value = a.clamp(-(2f64.powi(75)), 2f64.powi(75));
50        Number::from(value * 2f64.powi(DOUBLE_PRECISION_MANTISSA as i32))
51    }
52    pub fn f32_to_number(a: f32) -> Number {
53        let value = a.clamp(-(2f32.powi(75)), 2f32.powi(75));
54        Number::from(value * 2f32.powi(DOUBLE_PRECISION_MANTISSA as i32))
55    }
56}
57
58impl From<ArcisValue> for ArcisFloatValue {
59    fn from(value: ArcisValue) -> Self {
60        Self(value)
61    }
62}
63
64impl From<ArcisFloatValue> for ArcisValue {
65    fn from(a: ArcisFloatValue) -> ArcisValue {
66        a.0
67    }
68}
69
70impl TryFrom<f64> for ArcisFloatValue {
71    type Error = &'static str;
72
73    fn try_from(value: f64) -> Result<Self, &'static str> {
74        if value < -(2f64.powi(75)) || value >= 2f64.powi(75) {
75            Err("Arcis only supports inputs in the range [-2**75, 2**75)")
76        } else {
77            Ok(ArcisFloatValue(FieldValue::new(FieldExpr::Val(
78                ArcisFloatValue::f64_to_number(value).into(),
79            ))))
80        }
81    }
82}
83
84macro_rules! impl_float_comparison_op {
85    ($op:ident, $opfn:ident) => {
86        impl $op<Self> for ArcisFloatValue {
87            type Output = ArcisValue;
88
89            fn $opfn(self, other: Self) -> Self::Output {
90                ArcisValue::from(self.0.$opfn(other.0))
91            }
92        }
93
94        impl $op<f64> for ArcisFloatValue {
95            type Output = ArcisValue;
96
97            fn $opfn(self, other: f64) -> Self::Output {
98                ArcisValue::from(self.0.$opfn(ArcisFloatValue::try_from(other).unwrap().0))
99            }
100        }
101    };
102}
103
104impl_float_comparison_op!(Equal, eq);
105impl_float_comparison_op!(GreaterThan, gt);
106impl_float_comparison_op!(GreaterEqual, ge);
107
108macro_rules! impl_float_arithmetic_op {
109    ($op:ident, $opfn:ident) => {
110        impl $op<ArcisFloatValue> for ArcisFloatValue {
111            type Output = Self;
112
113            fn $opfn(self, other: Self) -> Self {
114                Self(self.0.$opfn(other.0))
115            }
116        }
117
118        impl $op<f64> for ArcisFloatValue {
119            type Output = ArcisFloatValue;
120
121            fn $opfn(self, other: f64) -> Self::Output {
122                Self(self.0.$opfn(ArcisFloatValue::try_from(other).unwrap().0))
123            }
124        }
125    };
126}
127
128impl_float_arithmetic_op!(Add, add);
129impl_float_arithmetic_op!(Sub, sub);
130
131pub(crate) const DOUBLE_PRECISION_MANTISSA: usize = 52;
132
133impl Mul for ArcisFloatValue {
134    type Output = Self;
135
136    fn mul(self, rhs: Self) -> Self::Output {
137        let prod = self.0 * rhs.0;
138        Self(shift_right(prod, DOUBLE_PRECISION_MANTISSA, true))
139    }
140}
141impl Div for ArcisFloatValue {
142    type Output = Self;
143
144    fn div(self, rhs: ArcisFloatValue) -> Self::Output {
145        Self(ArithmeticCircuitId::Div.apply(vec![self.0, rhs.0])[0])
146    }
147}