conjure_core/representations/
matrix_to_atom.rs
1use std::collections::BTreeMap;
2
3use itertools::{izip, Itertools};
4
5use super::prelude::*;
6use crate::{ast::matrix, into_matrix};
7
8register_represention!(MatrixToAtom, "matrix_to_atom");
9
10#[derive(Clone, Debug)]
11pub struct MatrixToAtom {
12 src_var: Name,
13
14 indices: Vec<Vec<Literal>>,
16
17 elem_domain: Domain,
19
20 index_domains: Vec<Domain>,
22}
23
24impl MatrixToAtom {
25 fn names(&self) -> impl Iterator<Item = Name> + '_ {
27 self.indices.iter().map(|x| self.indices_to_name(x))
28 }
29
30 fn indices_to_name(&self, indices: &[Literal]) -> Name {
32 Name::RepresentedName(
33 Box::new(self.src_var.clone()),
34 self.repr_name().to_string(),
35 indices.iter().join("_"),
36 )
37 }
38
39 #[allow(dead_code)]
41 fn name_to_indices(&self, name: &Name) -> Vec<Literal> {
42 let Name::RepresentedName(src_var, rule_string, suffix) = name else {
43 bug!("representation name should be Name::RepresentationOf");
44 };
45
46 assert_eq!(
47 src_var.as_ref(),
48 self.variable_name(),
49 "name should have the same source var as self"
50 );
51 assert_eq!(
52 rule_string,
53 self.repr_name(),
54 "name should have the same repr_name as self"
55 );
56
57 let indices = suffix.split("_").collect_vec();
60 assert_eq!(
61 indices.len(),
62 self.indices[0].len(),
63 "name should have same number of indices as self"
64 );
65
66 let parsed_indices = indices
67 .into_iter()
68 .map(|x| match x {
69 "true" => Literal::Bool(true),
70 "false" => Literal::Bool(false),
71 x if x.parse::<i32>().is_ok() => {
72 let i: i32 = x
73 .parse()
74 .expect("already checked whether this parses into an int");
75 Literal::Int(i)
76 }
77
78 x => bug!("{x} should be a string that can parse into a valid Literal"),
79 })
80 .collect_vec();
81
82 assert!(
83 self.indices.contains(&parsed_indices),
84 "indices parsed from the representation name should be valid indices for this variable"
85 );
86
87 parsed_indices
88 }
89}
90
91impl Representation for MatrixToAtom {
92 fn init(name: &Name, symtab: &SymbolTable) -> Option<Self> {
93 let domain = symtab.resolve_domain(name)?;
94
95 if !domain
96 .is_finite()
97 .expect("domain was resolved earlier, so should be ground here")
98 {
99 return None;
100 }
101
102 let Domain::DomainMatrix(elem_domain, index_domains) = domain else {
103 return None;
104 };
105
106 let indices = matrix::enumerate_indices(index_domains.clone()).collect_vec();
107
108 Some(MatrixToAtom {
109 src_var: name.clone(),
110 indices,
111 elem_domain: *elem_domain,
112 index_domains,
113 })
114 }
115
116 fn variable_name(&self) -> &Name {
117 &self.src_var
118 }
119
120 fn value_down(&self, value: Literal) -> Result<BTreeMap<Name, Literal>, ApplicationError> {
121 let Literal::AbstractLiteral(matrix) = value else {
122 return Err(RuleNotApplicable);
123 };
124
125 let AbstractLiteral::Matrix(_, ref index_domain) = matrix else {
126 return Err(RuleNotApplicable);
127 };
128
129 if index_domain != &self.index_domains[0] {
130 return Err(RuleNotApplicable);
131 }
132
133 Ok(izip!(self.names(), matrix::flatten(matrix)).collect())
134 }
135
136 fn value_up(&self, values: &BTreeMap<Name, Literal>) -> Result<Literal, ApplicationError> {
137 let n_dims = self.index_domains.len();
140 fn inner(
141 current_index: Vec<Literal>,
142 current_dim: usize,
143 self1: &MatrixToAtom,
144 values: &BTreeMap<Name, Literal>,
145 n_dims: usize,
146 ) -> Literal {
147 if current_dim < n_dims {
148 Literal::AbstractLiteral(into_matrix![self1.index_domains[current_dim]
149 .values()
150 .unwrap()
151 .into_iter()
152 .map(|i| {
153 let mut current_index_1 = current_index.clone();
154 current_index_1.push(i);
155 inner(current_index_1, current_dim + 1, self1, values, n_dims)
156 })
157 .collect_vec()])
158 } else {
159 values
160 .get(&self1.indices_to_name(¤t_index))
161 .unwrap()
162 .clone()
163 }
164 }
165
166 Ok(inner(vec![], 0, self, values, n_dims))
167 }
168
169 fn expression_down(
170 &self,
171 _: &SymbolTable,
172 ) -> Result<BTreeMap<Name, Expression>, ApplicationError> {
173 Ok(self
174 .names()
175 .map(|name| {
176 (
177 name.clone(),
178 Expression::Atomic(Metadata::new(), Atom::Reference(name)),
179 )
180 })
181 .collect())
182 }
183
184 fn declaration_down(&self) -> Result<Vec<Declaration>, ApplicationError> {
185 Ok(self
186 .names()
187 .map(|name| Declaration::new_var(name, self.elem_domain.clone()))
188 .collect_vec())
189 }
190
191 fn repr_name(&self) -> &str {
192 "matrix_to_atom"
193 }
194
195 fn box_clone(&self) -> Box<dyn Representation> {
196 Box::new(self.clone()) as _
197 }
198}