1use dashmap::DashMap;
2use num_bigint::BigInt;
3use num_rational::BigRational;
4use num_traits::One;
5use std::cell::RefCell;
6use std::collections::hash_map::DefaultHasher;
7use std::collections::HashMap;
8use std::hash::{Hash, Hasher};
9use std::sync::{Mutex, OnceLock, RwLock};
10
11use crate::number::{Number, Real};
12use crate::symbol::SymbolId;
13use crate::value::IndeterminateForm;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
18pub struct ExprId(u32);
19
20impl ExprId {
21 pub fn as_u32(self) -> u32 {
24 self.0
25 }
26
27 pub fn from_u32(u: u32) -> ExprId {
29 ExprId(u)
30 }
31}
32
33#[derive(Debug, Clone, PartialEq, Hash)]
36pub enum ExprData {
37 Symbol(SymbolId),
38 Integer(Box<BigInt>),
39 Rational(Box<BigRational>),
40 Real(Real),
41 Add(Box<[ExprId]>),
42 Mul(Box<[ExprId]>),
43 Pow { base: ExprId, exp: ExprId },
44 Apply { f: ExprId, args: Box<[ExprId]> },
45 Indeterminate(IndeterminateForm),
46}
47
48thread_local! {
50 static LOCAL_CACHE: RefCell<HashMap<u64, ExprId>> = RefCell::new(HashMap::new());
51}
52
53pub struct ExprPool {
56 global: DashMap<u64, ExprId>,
57 store: RwLock<Vec<ExprData>>,
58 alloc: Mutex<()>,
59}
60
61impl ExprPool {
62 pub fn new() -> ExprPool {
63 ExprPool {
64 global: DashMap::new(),
65 store: RwLock::new(Vec::new()),
66 alloc: Mutex::new(()),
67 }
68 }
69
70 pub fn global() -> &'static ExprPool {
72 static POOL: OnceLock<ExprPool> = OnceLock::new();
73 POOL.get_or_init(ExprPool::new)
74 }
75
76 fn hash_data(data: &ExprData) -> u64 {
77 let mut h = DefaultHasher::new();
78 data.hash(&mut h);
79 h.finish()
80 }
81
82 pub fn intern(&self, data: ExprData) -> ExprId {
85 let key = Self::hash_data(&data);
86 let cached = LOCAL_CACHE.with(|c| c.borrow().get(&key).copied());
87 if let Some(id) = cached {
88 return id;
89 }
90 if let Some(id) = self.global.get(&key) {
91 let id = *id;
92 LOCAL_CACHE.with(|c| c.borrow_mut().insert(key, id));
93 return id;
94 }
95 let _guard = self.alloc.lock().unwrap();
96 if let Some(id) = self.global.get(&key) {
97 let id = *id;
98 LOCAL_CACHE.with(|c| c.borrow_mut().insert(key, id));
99 return id;
100 }
101 let mut store = self.store.write().unwrap();
102 let id = ExprId(store.len() as u32);
103 store.push(data);
104 self.global.insert(key, id);
105 LOCAL_CACHE.with(|c| c.borrow_mut().insert(key, id));
106 id
107 }
108
109 pub fn get(&self, id: ExprId) -> Option<ExprData> {
110 self.store.read().unwrap().get(id.0 as usize).cloned()
111 }
112
113 pub fn symbol(&self, id: SymbolId) -> ExprId {
114 self.intern(ExprData::Symbol(id))
115 }
116
117 pub fn integer(&self, n: i64) -> ExprId {
118 self.intern(ExprData::Integer(Box::new(BigInt::from(n))))
119 }
120
121 pub fn real(&self, x: f64) -> ExprId {
122 self.intern(ExprData::Real(Real::F64(x)))
123 }
124
125 pub fn number(&self, n: &Number) -> ExprId {
126 match n {
127 Number::Integer(i) => self.intern(ExprData::Integer(Box::new(i.clone()))),
128 Number::Rational(r) => {
129 if *r.denom() == BigInt::one() {
130 self.intern(ExprData::Integer(Box::new(r.numer().clone())))
131 } else {
132 self.intern(ExprData::Rational(Box::new(r.clone())))
133 }
134 }
135 Number::Real(r) => self.intern(ExprData::Real(*r)),
136 Number::Complex { .. } => panic!("complex numbers cannot be interned as expression nodes yet"),
137 Number::I8(v) => self.intern(ExprData::Integer(Box::new(BigInt::from(*v)))),
139 Number::I16(v) => self.intern(ExprData::Integer(Box::new(BigInt::from(*v)))),
140 Number::I32(v) => self.intern(ExprData::Integer(Box::new(BigInt::from(*v)))),
141 Number::I64(v) => self.intern(ExprData::Integer(Box::new(BigInt::from(*v)))),
142 Number::I128(v) => self.intern(ExprData::Integer(Box::new(BigInt::from(*v)))),
143 Number::U8(v) => self.intern(ExprData::Integer(Box::new(BigInt::from(*v)))),
144 Number::U16(v) => self.intern(ExprData::Integer(Box::new(BigInt::from(*v)))),
145 Number::U32(v) => self.intern(ExprData::Integer(Box::new(BigInt::from(*v)))),
146 Number::U64(v) => self.intern(ExprData::Integer(Box::new(BigInt::from(*v)))),
147 Number::U128(v) => self.intern(ExprData::Integer(Box::new(BigInt::from(*v)))),
148 Number::Isize(v) => self.intern(ExprData::Integer(Box::new(BigInt::from(*v)))),
149 Number::Usize(v) => self.intern(ExprData::Integer(Box::new(BigInt::from(*v)))),
150 Number::BigFloat(f) => self.intern(ExprData::Real(Real::F64(*f))),
151 }
152 }
153
154 pub fn const_number(&self, id: ExprId) -> Option<Number> {
155 match self.get(id)? {
156 ExprData::Integer(i) => Some(Number::Integer(*i)),
157 ExprData::Rational(r) => Some(Number::Rational(*r)),
158 ExprData::Real(r) => Some(Number::Real(r)),
159 _ => None,
160 }
161 }
162
163 fn node_rank(&self, id: ExprId) -> u8 {
164 match self.get(id) {
165 Some(ExprData::Integer(_) | ExprData::Rational(_) | ExprData::Real(_)) => 0,
166 Some(ExprData::Symbol(_)) => 1,
167 _ => 2,
168 }
169 }
170
171 pub fn is_const_zero(&self, id: ExprId) -> bool {
172 self.const_number(id).is_some_and(|n| n.is_zero())
173 }
174
175 pub fn is_const_one(&self, id: ExprId) -> bool {
176 self.const_number(id).is_some_and(|n| n.is_one())
177 }
178
179 pub fn add(&self, items: &[ExprId]) -> ExprId {
181 let mut v = items.to_vec();
182 v.sort_by_key(|&id| (self.node_rank(id), id));
183 self.intern(ExprData::Add(v.into_boxed_slice()))
184 }
185
186 pub fn mul(&self, items: &[ExprId]) -> ExprId {
188 let mut v = items.to_vec();
189 v.sort_by_key(|&id| (self.node_rank(id), id));
190 self.intern(ExprData::Mul(v.into_boxed_slice()))
191 }
192
193 pub fn pow(&self, base: ExprId, exp: ExprId) -> ExprId {
194 self.intern(ExprData::Pow { base, exp })
195 }
196
197 pub fn apply(&self, f: ExprId, args: &[ExprId]) -> ExprId {
198 self.intern(ExprData::Apply { f, args: args.to_vec().into_boxed_slice() })
199 }
200
201 pub fn add_n(&self, items: &[ExprId]) -> ExprId {
204 let mut flat = Vec::new();
205 for &it in items {
206 if let Some(ExprData::Add(inner)) = self.get(it) {
207 flat.extend_from_slice(&inner);
208 } else {
209 flat.push(it);
210 }
211 }
212 let mut const_sum: Option<Number> = None;
213 let mut rest = Vec::new();
214 for &it in &flat {
215 if let Some(n) = self.const_number(it) {
216 const_sum = Some(match const_sum {
217 Some(acc) => acc + n,
218 None => n,
219 });
220 } else {
221 rest.push(it);
222 }
223 }
224 if let Some(n) = const_sum.filter(|n| !n.is_zero()) {
225 rest.push(self.number(&n));
226 }
227 if rest.is_empty() {
228 return self.integer(0);
229 }
230 if rest.len() == 1 {
231 return rest[0];
232 }
233 rest.sort_by_key(|&id| (self.node_rank(id), id));
234 self.intern(ExprData::Add(rest.into_boxed_slice()))
235 }
236
237 pub fn mul_n(&self, items: &[ExprId]) -> ExprId {
239 let mut flat = Vec::new();
240 for &it in items {
241 if let Some(ExprData::Mul(inner)) = self.get(it) {
242 flat.extend_from_slice(&inner);
243 } else {
244 flat.push(it);
245 }
246 }
247 let mut const_prod: Option<Number> = None;
248 let mut rest = Vec::new();
249 for &it in &flat {
250 if let Some(n) = self.const_number(it) {
251 if n.is_zero() {
252 return self.integer(0);
253 }
254 const_prod = Some(match const_prod {
255 Some(acc) => acc * n,
256 None => n,
257 });
258 } else {
259 rest.push(it);
260 }
261 }
262 if let Some(n) = const_prod.filter(|n| !n.is_one()) {
263 rest.push(self.number(&n));
264 }
265 if rest.is_empty() {
266 return self.integer(1);
267 }
268 if rest.len() == 1 {
269 return rest[0];
270 }
271 rest.sort_by_key(|&id| (self.node_rank(id), id));
272 self.intern(ExprData::Mul(rest.into_boxed_slice()))
273 }
274
275 pub fn add2(&self, a: ExprId, b: ExprId) -> ExprId {
276 self.add_n(&[a, b])
277 }
278
279 pub fn mul2(&self, a: ExprId, b: ExprId) -> ExprId {
280 self.mul_n(&[a, b])
281 }
282
283 pub fn pow2(&self, base: ExprId, exp: ExprId) -> ExprId {
285 if self.is_const_zero(exp) {
286 return self.integer(1);
287 }
288 if self.is_const_one(exp) {
289 return base;
290 }
291 if self.is_const_one(base) {
292 return self.integer(1);
293 }
294 if let (Some(b), Some(e)) = (self.const_number(base), self.const_number(exp))
295 && let Some(r) = b.pow(&e)
296 {
297 return self.number(&r);
298 }
299 self.pow(base, exp)
300 }
301
302 pub fn sub2(&self, a: ExprId, b: ExprId) -> ExprId {
303 self.add2(a, self.mul2(self.integer(-1), b))
304 }
305
306 pub fn div2(&self, a: ExprId, b: ExprId) -> ExprId {
307 self.mul2(a, self.pow2(b, self.integer(-1)))
308 }
309}
310
311impl Default for ExprPool {
312 fn default() -> Self {
313 Self::new()
314 }
315}