1use std::collections::BTreeMap;
2use std::sync::{Arc, Mutex};
3
4use qudit_core::RealScalar;
5use serde::{Deserialize, Serialize};
6
7use crate::TensorExpression;
8use crate::analysis::simplify_expressions_iter;
9use crate::codegen::CompilableUnit;
10use crate::expressions::{ExpressionBody, NamedExpression};
11use crate::index::{IndexSize, TensorIndex};
12use crate::{
13 ComplexExpression, DifferentiationLevel, Expression, GRADIENT, GenerationShape, HESSIAN,
14 Module, ModuleBuilder, WriteFunc,
15};
16
17pub type ExpressionId = u64;
18
19#[derive(Serialize, Deserialize)]
20pub struct CachedExpressionBody {
21 original: ExpressionBody,
22 func: Option<Vec<Expression>>,
23 grad: Option<Vec<Expression>>,
24 hess: Option<Vec<Expression>>,
25}
26
27impl CachedExpressionBody {
28 pub fn new(original: impl Into<ExpressionBody>) -> CachedExpressionBody {
29 let original = original.into();
30 CachedExpressionBody {
31 original,
32 func: None,
33 grad: None,
34 hess: None,
35 }
36 }
37
38 pub fn num_elements(&self) -> usize {
39 self.original.num_elements()
40 }
41
42 pub fn prepare(&mut self, variables: &[String], diff_level: DifferentiationLevel) -> bool {
44 let mut has_changed = false;
45
46 if self.func.is_none() {
47 self.func = Some(simplify_expressions_iter(
48 self.original.iter().flat_map(|c| [&c.real, &c.imag]),
49 ));
50
51 has_changed = true;
52 }
53
54 if diff_level >= GRADIENT && self.grad.is_none() {
55 let mut grad_exprs = vec![];
56 for variable in variables {
57 for expr in self.original.iter() {
58 let grad_expr = expr.differentiate(variable);
59 grad_exprs.push(grad_expr);
60 }
61 }
62
63 self.grad = Some(simplify_expressions_iter(
64 self.original
65 .iter()
66 .chain(grad_exprs.iter())
67 .flat_map(|c| [&c.real, &c.imag]),
68 ));
69
70 has_changed = true;
71 }
72
73 if diff_level >= HESSIAN && self.hess.is_some() {
74 let mut grad_exprs = vec![];
75 for variable in variables {
76 for expr in self.original.iter() {
77 let grad_expr = expr.differentiate(variable);
78 grad_exprs.push(grad_expr);
79 }
80 }
81
82 let mut hess_exprs = vec![];
83 for variable in variables {
84 for expr in grad_exprs.iter() {
85 let hess_expr = expr.differentiate(variable);
86 hess_exprs.push(hess_expr);
87 }
88 }
89
90 self.hess = Some(simplify_expressions_iter(
91 self.original
92 .iter()
93 .chain(grad_exprs.iter())
94 .chain(hess_exprs.iter())
95 .flat_map(|c| [&c.real, &c.imag]),
96 ));
97
98 has_changed = true;
99 }
100
101 has_changed
102 }
103}
104
105impl<B: Into<ExpressionBody>> From<B> for CachedExpressionBody {
106 fn from(value: B) -> Self {
107 CachedExpressionBody::new(value)
108 }
109}
110
111#[derive(Serialize, Deserialize)]
112pub struct CachedTensorExpression {
113 name: String,
114 variables: Vec<String>,
115 indices: Vec<TensorIndex>,
116 expressions: CachedExpressionBody,
117 id_lookup: BTreeMap<ExpressionId, (Vec<usize>, GenerationShape)>,
118 base_id: ExpressionId,
119}
120
121impl CachedTensorExpression {
122 pub fn new<E: Into<TensorExpression>>(expr: E, base_id: ExpressionId) -> Self {
123 let expr = expr.into();
124 let mut id_lookup = BTreeMap::new();
125 id_lookup.insert(base_id, ((0..expr.rank()).collect(), expr.indices().into()));
126 let (name, variables, body, indices) = expr.destruct();
127 CachedTensorExpression {
128 name,
129 variables,
130 indices,
131 expressions: body.into(),
132 id_lookup,
133 base_id,
134 }
135 }
136
137 pub fn indices(&self) -> &[TensorIndex] {
139 &self.indices
140 }
141
142 pub fn rank(&self) -> usize {
144 self.indices.len()
145 }
146
147 pub fn num_params(&self) -> usize {
148 self.variables.len()
149 }
150
151 pub fn dimensions(&self) -> Vec<IndexSize> {
153 self.indices.iter().map(|idx| idx.index_size()).collect()
154 }
155
156 pub fn tensor_strides(&self) -> Vec<usize> {
158 let mut strides = Vec::with_capacity(self.indices.len());
159 let mut current_stride = 1;
160 for &index in self.indices.iter().rev() {
161 strides.push(current_stride);
162 current_stride *= index.index_size();
163 }
164 strides.reverse();
165 strides
166 }
167
168 pub fn elements(&self) -> &[ComplexExpression] {
169 &self.expressions.original
170 }
171
172 pub fn prepare(&mut self, diff_level: DifferentiationLevel) -> bool {
174 self.expressions.prepare(&self.variables, diff_level)
175 }
176
177 fn add_to_builder<'a, R: RealScalar>(
178 &'a self,
179 mut builder: ModuleBuilder<'a, R>,
180 ) -> ModuleBuilder<'a, R> {
181 if let Some(func) = &self.expressions.func {
182 let unit = CompilableUnit::new(
184 &(format!("expr_{}_{}", self.base_id, "1")),
185 func.as_ref(),
186 self.variables.clone(),
187 self.expressions.original.len() * 2,
188 );
189
190 builder = builder.add_unit(unit);
191 }
192
193 if let Some(grad) = &self.expressions.grad {
194 let unit = CompilableUnit::new(
196 &(format!("expr_{}_{}", self.base_id, "2")),
197 grad.as_ref(),
198 self.variables.clone(),
199 self.expressions.original.len() * 2,
200 );
201
202 builder = builder.add_unit(unit);
203 }
204
205 if self.expressions.hess.is_some() {
206 let unit = CompilableUnit::new(
208 &(format!("expr_{}_{}", self.base_id, "3")),
209 self.expressions.grad.as_ref().unwrap(),
210 self.variables.clone(),
211 self.expressions.original.len() * 2,
212 );
213
214 builder = builder.add_unit(unit);
215 }
216
217 builder
218 }
219
220 pub fn num_elements(&self) -> usize {
221 self.expressions.num_elements()
222 }
223
224 pub fn form_expression(&self) -> TensorExpression {
225 let named = NamedExpression::new(
226 self.name.clone(),
227 self.variables.clone(),
228 self.expressions.original.clone(),
229 );
230 TensorExpression::from_raw(self.indices.clone(), named)
231 }
232
233 pub fn form_modified_indices(
234 &self,
235 modifiers: &(Vec<usize>, GenerationShape),
236 ) -> Vec<TensorIndex> {
237 let perm_index_sizes: Vec<usize> = modifiers
238 .0
239 .iter()
240 .map(|p| self.indices[*p].index_size())
241 .collect();
242 let redirection = modifiers.1.calculate_directions(&perm_index_sizes);
243 perm_index_sizes
244 .iter()
245 .zip(redirection.iter())
246 .enumerate()
247 .map(|(id, (s, d))| TensorIndex::new(*d, id, *s))
248 .collect()
249 }
250
251 pub fn form_modified_expression(
252 &self,
253 modifiers: &(Vec<usize>, GenerationShape),
254 ) -> TensorExpression {
255 let perm_index_sizes: Vec<usize> = modifiers
256 .0
257 .iter()
258 .map(|p| self.indices[*p].index_size())
259 .collect();
260 let redirection = modifiers.1.calculate_directions(&perm_index_sizes);
261 let mut expression = self.form_expression();
262 let new_indices = perm_index_sizes
263 .iter()
264 .zip(redirection.iter())
265 .enumerate()
266 .map(|(id, (s, d))| TensorIndex::new(*d, id, *s))
267 .collect();
268 expression.permute(&modifiers.0, redirection);
269 expression.reindex(new_indices);
270 expression
271 }
272}
273
274#[derive(Default, Serialize, Deserialize)]
275pub struct ExpressionCache {
276 expressions: BTreeMap<ExpressionId, CachedTensorExpression>,
277 id_lookup: BTreeMap<ExpressionId, ExpressionId>, name_lookup: BTreeMap<String, Vec<ExpressionId>>, #[serde(skip)]
280 module32: Option<Module<f32>>,
281 #[serde(skip)]
282 module64: Option<Module<f64>>,
283 id_counter: ExpressionId,
284}
285
286impl ExpressionCache {
287 pub fn new() -> Self {
288 Self {
289 expressions: BTreeMap::new(),
290 id_lookup: BTreeMap::new(),
291 name_lookup: BTreeMap::new(),
292 module32: None,
293 module64: None,
294 id_counter: 0,
295 }
296 }
297
298 pub fn new_shared() -> Arc<Mutex<Self>> {
299 Arc::new(Self::new().into())
300 }
301
302 pub fn get(&self, expr_id: ExpressionId) -> Option<TensorExpression> {
303 let base_id = self
305 .id_lookup
306 .get(&expr_id)
307 .unwrap_or_else(|| panic!("Failed to {expr_id} in cache."));
308 let cexpr = self
309 .expressions
310 .get(base_id)
311 .unwrap_or_else(|| panic!("Failed to {expr_id} in cache."));
312 let modifiers = cexpr
313 .id_lookup
314 .get(&expr_id)
315 .unwrap_or_else(|| panic!("Failed to {expr_id} in cache."));
316 Some(cexpr.form_modified_expression(modifiers))
317 }
318
319 pub fn lookup(&self, expr: impl AsRef<NamedExpression>) -> Option<ExpressionId> {
320 let expr = expr.as_ref();
321 if let Some(ids) = self.name_lookup.get(expr.name()) {
322 for id in ids {
323 let cexpr = self
324 .expressions
325 .get(id)
326 .expect("Expected since just looked up id.");
327 if expr == &cexpr.expressions.original {
328 return Some(*id);
329 }
330 }
331 }
332 None
333 }
334
335 pub fn contains(&self, expr: impl AsRef<NamedExpression>) -> bool {
336 self.lookup(expr).is_some()
337 }
338
339 fn get_new_id(&mut self) -> ExpressionId {
340 let new_id = self.id_counter;
341 self.id_counter += 1;
342 new_id
343 }
344
345 fn uncompile(&mut self) {
346 self.module32 = None;
347 self.module64 = None;
348 }
349
350 pub fn remove(&mut self, expr_id: ExpressionId) {
351 let mut modified_flag = false;
352 if let Some(base_id) = self.id_lookup.get(&expr_id) {
353 if *base_id == expr_id {
358 modified_flag = true;
359 let cexpr = self.expressions.remove(base_id).unwrap();
360 self.id_lookup.remove(&expr_id);
361 let name_vec = self.name_lookup.get_mut(&cexpr.name).unwrap();
362 name_vec.swap_remove(name_vec.iter().position(|x| *x == expr_id).unwrap());
363 }
364 }
365
366 if modified_flag {
367 self.uncompile();
368 }
369 }
370
371 pub fn insert(&mut self, expr: impl Into<TensorExpression>) -> ExpressionId {
372 let expr: TensorExpression = expr.into();
373 if let Some(id) = self.lookup(&expr) {
374 return id;
375 }
376
377 self.uncompile();
378
379 let id = self.get_new_id();
380 self.name_lookup.insert(expr.name().to_owned(), vec![id]);
381 self.expressions
382 .insert(id, CachedTensorExpression::new(expr, id));
383 self.id_lookup.insert(id, id);
384 id
385 }
386
387 pub fn indices(&self, expr_id: ExpressionId) -> Vec<TensorIndex> {
388 let base_id = self
389 .id_lookup
390 .get(&expr_id)
391 .unwrap_or_else(|| panic!("Failed to {expr_id} in cache."));
392 let cexpr = self
393 .expressions
394 .get(base_id)
395 .unwrap_or_else(|| panic!("Failed to {expr_id} in cache."));
396 let modifiers = cexpr
397 .id_lookup
398 .get(&expr_id)
399 .unwrap_or_else(|| panic!("Failed to {expr_id} in cache."));
400 cexpr.form_modified_indices(modifiers)
401 }
402
403 pub fn num_elements(&self, expr_id: ExpressionId) -> usize {
404 let base_id = self
405 .id_lookup
406 .get(&expr_id)
407 .unwrap_or_else(|| panic!("Failed to {expr_id} in cache."));
408 let cexpr = self
409 .expressions
410 .get(base_id)
411 .unwrap_or_else(|| panic!("Failed to {expr_id} in cache."));
412 cexpr.num_elements()
413 }
414
415 pub fn generation_shape(&self, expr_id: ExpressionId) -> GenerationShape {
416 let base_id = self
417 .id_lookup
418 .get(&expr_id)
419 .unwrap_or_else(|| panic!("Failed to {expr_id} in cache."));
420 let cexpr = self
421 .expressions
422 .get(base_id)
423 .unwrap_or_else(|| panic!("Failed to {expr_id} in cache."));
424 let modifiers = cexpr
425 .id_lookup
426 .get(&expr_id)
427 .unwrap_or_else(|| panic!("Failed to {expr_id} in cache."));
428 modifiers.1
429 }
430
431 pub fn base_name(&self, expr_id: ExpressionId) -> String {
432 let base_id = self
433 .id_lookup
434 .get(&expr_id)
435 .unwrap_or_else(|| panic!("Failed to {expr_id} in cache."));
436 let cexpr = self
437 .expressions
438 .get(base_id)
439 .unwrap_or_else(|| panic!("Failed to {expr_id} in cache."));
440
441 cexpr.name.clone()
442 }
443
444 pub fn name(&self, expr_id: ExpressionId) -> String {
445 let base_id = self
446 .id_lookup
447 .get(&expr_id)
448 .unwrap_or_else(|| panic!("Failed to {expr_id} in cache."));
449 let cexpr = self
450 .expressions
451 .get(base_id)
452 .unwrap_or_else(|| panic!("Failed to {expr_id} in cache."));
453 let modifiers = cexpr
454 .id_lookup
455 .get(&expr_id)
456 .unwrap_or_else(|| panic!("Failed to {expr_id} in cache."));
457
458 let base_name = cexpr.name.clone();
459 let permutation = modifiers
460 .0
461 .iter()
462 .map(|&i| i.to_string())
463 .collect::<Vec<String>>()
464 .join("_");
465 let shape = modifiers
466 .1
467 .to_vec()
468 .iter()
469 .map(|&i| i.to_string())
470 .collect::<Vec<String>>()
471 .join("_");
472 format!("{base_name}_perm{permutation}_shape{shape}")
473 }
474
475 pub fn num_params(&self, expr_id: ExpressionId) -> usize {
476 let base_id = self
477 .id_lookup
478 .get(&expr_id)
479 .unwrap_or_else(|| panic!("Failed to {expr_id} in cache."));
480 let cexpr = self
481 .expressions
482 .get(base_id)
483 .unwrap_or_else(|| panic!("Failed to {expr_id} in cache."));
484 cexpr.num_params()
485 }
486
487 pub fn trace(&mut self, expr_id: ExpressionId, pairs: Vec<(usize, usize)>) -> ExpressionId {
488 let old_name = self.name(expr_id);
490 let traced = pairs
491 .iter()
492 .map(|(x, y)| format!("{x}_{y}"))
493 .collect::<Vec<String>>()
494 .join("_");
495 let traced_name = format!("traced{traced}_{old_name}");
496
497 let base_id = self
498 .id_lookup
499 .get(&expr_id)
500 .unwrap_or_else(|| panic!("Failed to {expr_id} in cache."));
501 let cexpr = self
502 .expressions
503 .get(base_id)
504 .unwrap_or_else(|| panic!("Failed to {expr_id} in cache."));
505 let modifiers = cexpr
506 .id_lookup
507 .get(&expr_id)
508 .unwrap_or_else(|| panic!("Failed to {expr_id} in cache."));
509
510 let old_expr: TensorExpression = cexpr.form_modified_expression(modifiers);
511
512 let mut traced_expr = old_expr.partial_trace(&pairs);
513 traced_expr.set_name(traced_name.clone());
514
515 if let Some(ids) = self.name_lookup.get(&traced_name) {
516 for id in ids {
517 let cexpr_other = self
518 .expressions
519 .get(id)
520 .unwrap_or_else(|| panic!("Failed to {id} in cache."));
521
522 if traced_expr.elements() == cexpr_other.elements() {
523 return *id;
524 }
525 }
526 }
527
528 self.uncompile();
529 self.insert(traced_expr)
530 }
531
532 pub fn permute_reshape(
533 &mut self,
534 expr_id: ExpressionId,
535 perm: Vec<usize>,
536 reshape: GenerationShape,
537 ) -> ExpressionId {
538 let base_id = *self
539 .id_lookup
540 .get(&expr_id)
541 .unwrap_or_else(|| panic!("Failed to {expr_id} in cache."));
542 let cexpr = self
543 .expressions
544 .get(&base_id)
545 .unwrap_or_else(|| panic!("Failed to {expr_id} in cache."));
546 let modifiers = cexpr
547 .id_lookup
548 .get(&expr_id)
549 .unwrap_or_else(|| panic!("Failed to {expr_id} in cache."));
550
551 let composed_perm: Vec<usize> = perm.iter().map(|&idx| modifiers.0[idx]).collect(); let new_val = (composed_perm, reshape);
555 for (id, val) in cexpr.id_lookup.iter() {
556 if *val == new_val {
557 return *id;
558 }
559 }
560
561 let new_id = self.get_new_id();
562 let cexpr = self
563 .expressions
564 .get_mut(&base_id)
565 .unwrap_or_else(|| panic!("Failed to {expr_id} in cache."));
566 cexpr.id_lookup.insert(new_id, new_val);
567 self.id_lookup.insert(new_id, base_id);
568 new_id
569 }
570
571 fn _get_module_mut<R: RealScalar>(&mut self) -> &mut Option<Module<R>> {
572 if std::any::TypeId::of::<R>() == std::any::TypeId::of::<f32>() {
573 unsafe { std::mem::transmute(&mut self.module32) }
575 } else if std::any::TypeId::of::<R>() == std::any::TypeId::of::<f64>() {
576 unsafe { std::mem::transmute(&mut self.module64) }
578 } else {
579 unreachable!()
580 }
581 }
582
583 fn _get_module<R: RealScalar>(&self) -> &Option<Module<R>> {
584 if std::any::TypeId::of::<R>() == std::any::TypeId::of::<f32>() {
585 unsafe { std::mem::transmute(&self.module32) }
587 } else if std::any::TypeId::of::<R>() == std::any::TypeId::of::<f64>() {
588 unsafe { std::mem::transmute(&self.module64) }
590 } else {
591 unreachable!()
592 }
593 }
594
595 pub fn is_compiled<R: RealScalar>(&self) -> bool {
596 self._get_module::<R>().is_some()
597 }
598
599 pub fn prepare(&mut self, diff_level: DifferentiationLevel) {
601 let mut should_uncompile = false;
602 for cexpr in self.expressions.values_mut() {
603 if cexpr.prepare(diff_level) {
604 should_uncompile = true;
605 }
606 }
607
608 if should_uncompile {
609 self.uncompile();
610 }
611 }
612
613 pub fn compile<R: RealScalar>(&mut self) {
614 let mut module_builder: ModuleBuilder<R> = ModuleBuilder::new("cache");
615 for cexpr in self.expressions.values_mut() {
617 module_builder = cexpr.add_to_builder(module_builder);
618 }
619 *self._get_module_mut() = Some(module_builder.build());
620 }
621
622 pub fn get_fn<R: RealScalar>(
627 &mut self,
628 expr_id: ExpressionId,
629 diff_level: DifferentiationLevel,
630 ) -> WriteFunc<R> {
631 if !self.is_compiled::<R>() {
632 self.compile::<R>();
633 }
634
635 let module = self
636 ._get_module()
637 .as_ref()
638 .expect("Module should exist due to previous compilation.");
639
640 let base_id = self
641 .id_lookup
642 .get(&expr_id)
643 .expect("Unexpected expression id.");
644
645 module
647 .get_function(&format!("expr_{}_{}", base_id, diff_level))
648 .expect("Error retrieving compiled expression.")
649 }
650
651 pub fn get_output_map<R: RealScalar>(
652 &self,
653 expr_id: ExpressionId,
654 row_stride: u64,
655 col_stride: u64,
656 mat_stride: u64,
657 ) -> Vec<u64> {
658 let base_id = self
659 .id_lookup
660 .get(&expr_id)
661 .unwrap_or_else(|| panic!("Failed to {expr_id} in cache."));
662 let cexpr = self
663 .expressions
664 .get(base_id)
665 .unwrap_or_else(|| panic!("Failed to {expr_id} in cache."));
666 let modifiers = cexpr
667 .id_lookup
668 .get(&expr_id)
669 .unwrap_or_else(|| panic!("Failed to {expr_id} in cache."));
670
671 let (perm, shape) = modifiers;
672
673 let original_strides = cexpr.tensor_strides();
676 let original_dimensions = cexpr.dimensions();
677
678 let new_strides = {
679 let mut strides = Vec::with_capacity(cexpr.rank());
680 let mut current_stride = 1;
681 for perm_index in perm.iter().map(|p| cexpr.indices()[*p]).rev() {
682 strides.push(current_stride);
683 current_stride *= perm_index.index_size();
684 }
685 strides.reverse();
686 strides
687 };
688
689 let mut complex_elem_perm = Vec::with_capacity(cexpr.num_elements());
690 for i in 0..cexpr.num_elements() {
691 let mut original_coordinate: Vec<usize> = Vec::with_capacity(cexpr.rank());
692 let mut temp_i = i;
693 for d_idx in 0..cexpr.rank() {
694 original_coordinate
695 .push((temp_i / original_strides[d_idx]) % original_dimensions[d_idx]);
696 temp_i %= original_strides[d_idx]; }
698
699 let mut permuted_coordinate: Vec<usize> = vec![0; cexpr.rank()];
703 for j in 0..cexpr.rank() {
704 permuted_coordinate[j] = original_coordinate[perm[j]];
705 }
706
707 let mut new_linear_idx = 0;
709 for d_idx in 0..cexpr.rank() {
710 new_linear_idx += permuted_coordinate[d_idx] * new_strides[d_idx];
711 }
712 complex_elem_perm.push(new_linear_idx);
713 }
714
715 let ncols = shape.ncols() as u64;
716 let nrows = shape.nrows() as u64;
717
718 let num_real_elements = cexpr.num_elements() * 2;
719 let mut map = Vec::with_capacity(num_real_elements);
720
721 for real_idx in 0..(num_real_elements as u64) {
722 let complex_idx = real_idx / 2;
723 let complex_perm_idx = complex_elem_perm[complex_idx as usize] as u64;
724 let imag_offset = real_idx % 2;
725 let mat_idx = complex_perm_idx / (nrows * ncols);
726 let row_idx = (complex_perm_idx % (nrows * ncols)) / ncols;
727 let col_idx = complex_perm_idx % ncols;
728 map.push(
729 2 * (mat_idx * mat_stride + row_idx * row_stride + col_idx * col_stride)
730 + imag_offset,
731 )
732 }
733
734 map
735 }
736}