Skip to main content

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