1use crate::{errors::SynthesisError, ConstraintSystem, Index, LinearCombination, OptionalVec, Variable};
16use snarkvm_fields::Field;
17
18use cfg_if::cfg_if;
19use fxhash::{FxBuildHasher, FxHashMap};
20use indexmap::{map::Entry, IndexMap, IndexSet};
21use itertools::Itertools;
22
23pub type Fr = snarkvm_curves::bls12_377::Fr;
25
26#[derive(Debug, Clone)]
27enum NamedObject {
28 Constraint(usize),
29 Var(Variable),
30 Namespace(Namespace),
32}
33
34#[derive(Debug, Clone, Default)]
35struct Namespace {
36 children: Vec<NamedObject>,
37 idx: NamespaceIndex,
38}
39
40impl Namespace {
41 fn push(&mut self, child: NamedObject) {
42 self.children.push(child);
43 }
44}
45
46type InternedField = usize;
47type InternedPathSegment = usize;
48type NamespaceIndex = usize;
49
50#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
51pub struct InternedPath {
52 parent_namespace: NamespaceIndex,
53 last_segment: InternedPathSegment,
54}
55
56#[derive(PartialEq, Eq, Hash)]
57pub struct TestConstraint {
58 interned_path: InternedPath,
59 a: Vec<(Variable, InternedField)>,
60 b: Vec<(Variable, InternedField)>,
61 c: Vec<(Variable, InternedField)>,
62}
63
64#[derive(Default, Debug)]
65pub struct CurrentNamespace {
66 segments: Vec<InternedPathSegment>,
67 indices: Vec<NamespaceIndex>,
68}
69
70impl CurrentNamespace {
71 fn idx(&self) -> usize {
72 self.indices.last().copied().unwrap_or(0)
73 }
74
75 fn pop(&mut self) {
76 assert!(self.segments.pop().is_some());
77 assert!(self.indices.pop().is_some());
78 }
79}
80
81pub struct TestConstraintSystem<F: Field> {
83 interned_full_paths: FxHashMap<Vec<InternedPathSegment>, InternedPath>,
85 interned_path_segments: IndexSet<String, FxBuildHasher>,
87 interned_fields: IndexSet<F, FxBuildHasher>,
89 named_objects: IndexMap<InternedPath, NamedObject, FxBuildHasher>,
92 current_namespace: CurrentNamespace,
95 constraints: OptionalVec<TestConstraint>,
97 public_variables: OptionalVec<InternedField>,
99 private_variables: OptionalVec<InternedField>,
101}
102
103impl<F: Field> Default for TestConstraintSystem<F> {
104 fn default() -> Self {
105 let mut interned_path_segments = IndexSet::with_hasher(FxBuildHasher::default());
106 let path_segment = "ONE".to_owned();
107 let interned_path_segment = interned_path_segments.insert_full(path_segment).0;
108 let interned_path = InternedPath { parent_namespace: 0, last_segment: interned_path_segment };
109
110 cfg_if! {
111 if #[cfg(debug_assertions)] {
112 let mut interned_full_paths = FxHashMap::default();
113 interned_full_paths.insert(vec![interned_path_segment], interned_path);
114 } else {
115 let interned_full_paths = FxHashMap::default();
116 }
117 }
118
119 let mut named_objects = IndexMap::with_hasher(FxBuildHasher::default());
120 named_objects.insert_full(interned_path, NamedObject::Var(TestConstraintSystem::<F>::one()));
121
122 let mut interned_fields = IndexSet::with_hasher(FxBuildHasher::default());
123 let interned_field = interned_fields.insert_full(F::one()).0;
124
125 let mut inputs: OptionalVec<InternedField> = Default::default();
126 inputs.insert(interned_field);
127
128 let constraints = OptionalVec::default();
129
130 TestConstraintSystem {
131 interned_full_paths,
132 interned_fields,
133 interned_path_segments,
134 named_objects,
135 current_namespace: Default::default(),
136 constraints,
137 public_variables: inputs,
138 private_variables: Default::default(),
139 }
140 }
141}
142
143impl<F: Field> TestConstraintSystem<F> {
144 pub fn new() -> Self {
145 Self::default()
146 }
147
148 pub fn diff(&self, other: &Self) {
150 for (i, (self_c, other_c)) in self.constraints.iter().zip(other.constraints.iter()).enumerate() {
151 let self_interned_path = self_c.interned_path;
152 let other_interned_path = other_c.interned_path;
153 if self_c.a != other_c.a {
154 println!("A row {i} is different:");
155 println!("self: {}", self.unintern_path(self_interned_path));
156 println!("other: {}", other.unintern_path(other_interned_path));
157 break;
158 }
159
160 if self_c.b != other_c.b {
161 println!("B row {i} is different:");
162 println!("self: {}", self.unintern_path(self_interned_path));
163 println!("other: {}", other.unintern_path(other_interned_path));
164 break;
165 }
166
167 if self_c.c != other_c.c {
168 println!("C row {i} is different:");
169 println!("self: {}", self.unintern_path(self_interned_path));
170 println!("other: {}", other.unintern_path(other_interned_path));
171 break;
172 }
173 }
174 }
175
176 #[inline]
177 fn intern_path(&self, path: &str) -> InternedPath {
178 let mut vec = vec![];
179
180 for segment in path.split('/') {
181 vec.push(self.interned_path_segments.get_index_of(segment).unwrap());
182 }
183
184 *self.interned_full_paths.get(&vec).unwrap()
185 }
186
187 fn unintern_path(&self, interned_path: InternedPath) -> String {
188 let last_segment = self.interned_path_segments.get_index(interned_path.last_segment).unwrap();
189 let mut reversed_uninterned_segments = vec![last_segment];
190
191 let mut parent_ns = interned_path.parent_namespace;
192 while parent_ns != 0 {
193 let interned_parent_ns = self.named_objects.get_index(parent_ns).unwrap().0;
194 let parent_segment = self.interned_path_segments.get_index(interned_parent_ns.last_segment).unwrap();
195 reversed_uninterned_segments.push(parent_segment);
196 parent_ns = interned_parent_ns.parent_namespace;
197 }
198
199 let segments = reversed_uninterned_segments.into_iter().map(|s| s.as_str()).rev();
200 Itertools::intersperse(segments, "/").collect()
201 }
202
203 pub fn print_named_objects(&self) {
204 for TestConstraint { interned_path, .. } in self.constraints.iter() {
205 println!("{}", self.unintern_path(*interned_path));
206 }
207 }
208
209 fn eval_lc(&self, terms: &[(Variable, InternedField)]) -> F {
210 let mut acc = F::zero();
211
212 for &(var, interned_coeff) in terms {
213 let interned_tmp = match var.get_unchecked() {
214 Index::Public(index) => self.public_variables[index],
215 Index::Private(index) => self.private_variables[index],
216 };
217 let mut tmp = *self.interned_fields.get_index(interned_tmp).unwrap();
218 let coeff = self.interned_fields.get_index(interned_coeff).unwrap();
219
220 tmp.mul_assign(coeff);
221 acc.add_assign(tmp);
222 }
223
224 acc
225 }
226
227 pub fn which_is_unsatisfied(&self) -> Option<String> {
228 for TestConstraint { interned_path, a, b, c } in self.constraints.iter() {
229 let mut a = self.eval_lc(a.as_ref());
230 let b = self.eval_lc(b.as_ref());
231 let c = self.eval_lc(c.as_ref());
232
233 a.mul_assign(&b);
234
235 if a != c {
236 return Some(self.unintern_path(*interned_path));
237 }
238 }
239
240 None
241 }
242
243 #[inline]
244 pub fn is_satisfied(&self) -> bool {
245 self.which_is_unsatisfied().is_none()
246 }
247
248 #[inline]
249 pub fn num_non_zero(&self) -> (usize, usize, usize) {
250 let mut non_zero_a = 0;
251 let mut non_zero_b = 0;
252 let mut non_zero_c = 0;
253 for TestConstraint { a, b, c, .. } in self.constraints.iter() {
254 non_zero_a += a.len();
255 non_zero_b += b.len();
256 non_zero_c += c.len();
257 }
258 (non_zero_a, non_zero_b, non_zero_c)
259 }
260
261 #[inline]
262 pub fn num_constraints(&self) -> usize {
263 self.constraints.len()
264 }
265
266 #[inline]
267 pub fn get_constraint_path(&self, i: usize) -> String {
268 self.unintern_path(self.constraints.iter().nth(i).unwrap().interned_path)
269 }
270
271 pub fn set(&mut self, path: &str, to: F) {
272 let interned_path = self.intern_path(path);
273 let interned_field = self.interned_fields.insert_full(to).0;
274
275 match self.named_objects.get(&interned_path) {
276 Some(NamedObject::Var(v)) => match v.get_unchecked() {
277 Index::Public(index) => self.public_variables[index] = interned_field,
278 Index::Private(index) => self.private_variables[index] = interned_field,
279 },
280 Some(e) => panic!("tried to set path `{path}` to value, but `{e:?}` already exists there."),
281 _ => panic!("no variable exists at path: {path}"),
282 }
283 }
284
285 pub fn get(&mut self, path: &str) -> F {
286 let interned_path = self.intern_path(path);
287
288 let interned_field = match self.named_objects.get(&interned_path) {
289 Some(NamedObject::Var(v)) => match v.get_unchecked() {
290 Index::Public(index) => self.public_variables[index],
291 Index::Private(index) => self.private_variables[index],
292 },
293 Some(e) => panic!("tried to get value of path `{path}`, but `{e:?}` exists there (not a variable)"),
294 _ => panic!("no variable exists at path: {path}"),
295 };
296
297 *self.interned_fields.get_index(interned_field).unwrap()
298 }
299
300 #[inline]
301 fn set_named_obj(&mut self, interned_path: InternedPath, to: NamedObject) -> NamespaceIndex {
302 match self.named_objects.entry(interned_path) {
303 Entry::Vacant(e) => {
304 let ns_idx = e.index();
305 e.insert(to);
306 ns_idx
307 }
308 Entry::Occupied(e) => {
309 let interned_segments = e.remove_entry().0;
310 panic!("tried to create object at existing path: {}", self.unintern_path(interned_segments));
311 }
312 }
313 }
314
315 #[inline]
316 fn compute_path(&mut self, new_segment: &str) -> InternedPath {
317 let (interned_segment, new) = if let Some(index) = self.interned_path_segments.get_index_of(new_segment) {
318 (index, false)
319 } else {
320 self.interned_path_segments.insert_full(new_segment.to_owned())
321 };
322
323 assert!(!new || !new_segment.contains('/'), "'/' is not allowed in names");
325
326 let interned_path =
327 InternedPath { parent_namespace: self.current_namespace.idx(), last_segment: interned_segment };
328
329 cfg_if! {
330 if #[cfg(debug_assertions)] {
331 let mut full_path = self.current_namespace.segments.clone();
332 full_path.push(interned_segment);
333 self.interned_full_paths.insert(full_path, interned_path);
334 }
335 }
336
337 interned_path
338 }
339
340 #[cfg(not(debug_assertions))]
341 fn purge_namespace(&mut self, namespace: Namespace) {
342 for child_obj in namespace.children {
343 match child_obj {
344 NamedObject::Var(var) => match var.get_unchecked() {
345 Index::Private(idx) => {
346 self.private_variables.remove(idx);
347 }
348 Index::Public(idx) => {
349 self.public_variables.remove(idx);
350 }
351 },
352 NamedObject::Constraint(idx) => {
353 self.constraints.remove(idx);
354 }
355 NamedObject::Namespace(children) => {
356 self.purge_namespace(children);
357 }
358 }
359 self.named_objects.swap_remove_index(namespace.idx);
360 }
361 }
362
363 #[inline]
364 fn register_object_in_namespace(&mut self, named_obj: NamedObject) {
365 if let NamedObject::Namespace(ref mut ns) =
366 self.named_objects.get_index_mut(self.current_namespace.idx()).unwrap().1
367 {
368 ns.push(named_obj);
369 }
370 }
371}
372
373impl<F: Field> ConstraintSystem<F> for TestConstraintSystem<F> {
374 type Root = Self;
375
376 fn alloc<Fn, A, AR>(&mut self, annotation: A, f: Fn) -> Result<Variable, SynthesisError>
377 where
378 Fn: FnOnce() -> Result<F, SynthesisError>,
379 A: FnOnce() -> AR,
380 AR: AsRef<str>,
381 {
382 let interned_path = self.compute_path(annotation().as_ref());
383 let interned_field = self.interned_fields.insert_full(f()?).0;
384 let index = self.private_variables.insert(interned_field);
385 let var = Variable::new_unchecked(Index::Private(index));
386 let named_obj = NamedObject::Var(var);
387 self.register_object_in_namespace(named_obj.clone());
388 self.set_named_obj(interned_path, named_obj);
389
390 Ok(var)
391 }
392
393 fn alloc_input<Fn, A, AR>(&mut self, annotation: A, f: Fn) -> Result<Variable, SynthesisError>
394 where
395 Fn: FnOnce() -> Result<F, SynthesisError>,
396 A: FnOnce() -> AR,
397 AR: AsRef<str>,
398 {
399 let interned_path = self.compute_path(annotation().as_ref());
400 let interned_field = self.interned_fields.insert_full(f()?).0;
401 let index = self.public_variables.insert(interned_field);
402 let var = Variable::new_unchecked(Index::Public(index));
403 let named_obj = NamedObject::Var(var);
404 self.register_object_in_namespace(named_obj.clone());
405 self.set_named_obj(interned_path, named_obj);
406
407 Ok(var)
408 }
409
410 fn enforce<A, AR, LA, LB, LC>(&mut self, annotation: A, a: LA, b: LB, c: LC)
411 where
412 A: FnOnce() -> AR,
413 AR: AsRef<str>,
414 LA: FnOnce(LinearCombination<F>) -> LinearCombination<F>,
415 LB: FnOnce(LinearCombination<F>) -> LinearCombination<F>,
416 LC: FnOnce(LinearCombination<F>) -> LinearCombination<F>,
417 {
418 let interned_path = self.compute_path(annotation().as_ref());
419 let index = self.constraints.next_idx();
420 let named_obj = NamedObject::Constraint(index);
421 self.register_object_in_namespace(named_obj.clone());
422 self.set_named_obj(interned_path, named_obj);
423
424 let mut intern_fields = |uninterned: Vec<(Variable, F)>| -> Vec<(Variable, InternedField)> {
425 uninterned
426 .into_iter()
427 .map(|(var, field)| {
428 let interned_field = self.interned_fields.insert_full(field).0;
429 (var, interned_field)
430 })
431 .collect()
432 };
433
434 let a = intern_fields(a(LinearCombination::zero()).0);
435 let b = intern_fields(b(LinearCombination::zero()).0);
436 let c = intern_fields(c(LinearCombination::zero()).0);
437
438 self.constraints.insert(TestConstraint { interned_path, a, b, c });
439 }
440
441 fn push_namespace<NR: AsRef<str>, N: FnOnce() -> NR>(&mut self, name_fn: N) {
442 let name = name_fn();
443 let interned_path = self.compute_path(name.as_ref());
444 let new_segment = interned_path.last_segment;
445 let named_obj = NamedObject::Namespace(Default::default());
446 self.register_object_in_namespace(named_obj.clone());
447 let namespace_idx = self.set_named_obj(interned_path, named_obj);
448 if let NamedObject::Namespace(ref mut ns) = self.named_objects[namespace_idx] {
449 ns.idx = namespace_idx;
450 };
451
452 self.current_namespace.segments.push(new_segment);
453 self.current_namespace.indices.push(namespace_idx);
454 }
455
456 #[cfg(not(debug_assertions))]
457 fn pop_namespace(&mut self) {
458 let namespace = if let NamedObject::Namespace(no) =
459 self.named_objects.swap_remove_index(self.current_namespace.idx()).unwrap().1
460 {
461 no
462 } else {
463 unreachable!()
464 };
465
466 self.purge_namespace(namespace);
468
469 self.current_namespace.pop();
471 }
472
473 #[cfg(debug_assertions)]
474 fn pop_namespace(&mut self) {
475 self.current_namespace.pop();
479 }
480
481 #[inline]
482 fn get_root(&mut self) -> &mut Self::Root {
483 self
484 }
485
486 #[inline]
487 fn num_constraints(&self) -> usize {
488 self.num_constraints()
489 }
490
491 #[inline]
492 fn num_public_variables(&self) -> usize {
493 self.public_variables.len()
494 }
495
496 #[inline]
497 fn num_private_variables(&self) -> usize {
498 self.private_variables.len()
499 }
500
501 #[inline]
502 fn is_in_setup_mode(&self) -> bool {
503 false
504 }
505}