1use crate::utils::IndexMap;
7use ark_std::boxed::Box;
8use ark_std::collections::BTreeMap;
9use core::cell::{Ref, RefCell, RefMut};
10
11use super::{
12 constraint_system::ConstraintSystem,
13 instance_outliner::InstanceOutliner,
14 predicate::{
15 polynomial_constraint::{R1CS_PREDICATE_LABEL, SR1CS_PREDICATE_LABEL},
16 Predicate, PredicateConstraintSystem,
17 },
18 Label, LinearCombination, Matrix, OptimizationGoal, SynthesisError, SynthesisMode, Variable,
19};
20use ark_ff::Field;
21use ark_std::{rc::Rc, string::String, vec::Vec};
22
23#[derive(Debug, Clone)]
26pub enum ConstraintSystemRef<F: Field> {
27 None,
31 CS(Rc<RefCell<ConstraintSystem<F>>>),
34}
35
36impl<F: Field> PartialEq for ConstraintSystemRef<F> {
37 fn eq(&self, other: &Self) -> bool {
38 match (self, other) {
39 (Self::None, Self::None) => true,
40 (..) => false,
41 }
42 }
43}
44
45impl<F: Field> Eq for ConstraintSystemRef<F> {}
46
47impl<F: Field> ConstraintSystemRef<F> {
48 #[inline]
50 pub fn new(inner: ConstraintSystem<F>) -> Self {
51 Self::CS(Rc::new(RefCell::new(inner)))
52 }
53
54 pub fn get_all_predicates_num_constraints(&self) -> IndexMap<Label, usize> {
56 self.inner().map_or_else(IndexMap::default, |cs| {
57 cs.borrow().get_all_predicates_num_constraints()
58 })
59 }
60
61 pub fn get_predicates_num_constraints(&self, predicate_label: &str) -> Option<usize> {
63 self.inner()
64 .and_then(|cs| cs.borrow().get_predicate_num_constraints(predicate_label))
65 }
66
67 pub fn get_all_predicate_arities(&self) -> IndexMap<Label, usize> {
69 self.inner().map_or_else(IndexMap::default, |cs| {
70 cs.borrow().get_all_predicate_arities()
71 })
72 }
73
74 pub fn get_predicate_arity(&self, predicate_label: &str) -> Option<usize> {
76 self.inner()
77 .and_then(|cs| cs.borrow().get_predicate_arity(predicate_label))
78 }
79
80 pub fn get_all_predicate_types(&self) -> BTreeMap<Label, Predicate<F>> {
82 self.inner()
83 .map_or(BTreeMap::new(), |cs| cs.borrow().get_all_predicate_types())
84 }
85
86 pub fn get_predicate_type(&self, predicate_label: &str) -> Option<Predicate<F>> {
88 self.inner()
89 .and_then(|cs| cs.borrow().get_predicate_type(predicate_label))
90 }
91
92 pub fn num_constraints(&self) -> usize {
95 self.inner().map_or(0, |cs| cs.borrow().num_constraints())
96 }
97
98 #[inline]
100 pub fn num_instance_variables(&self) -> usize {
101 self.inner()
102 .map_or(0, |cs| cs.borrow().num_instance_variables())
103 }
104
105 #[inline]
107 pub fn instance_assignment(&self) -> crate::gr1cs::Result<Vec<F>> {
108 self.inner()
109 .ok_or(SynthesisError::AssignmentMissing)
110 .and_then(|cs| cs.borrow().instance_assignment().map(|v| v.to_vec()))
111 }
112
113 #[inline]
115 pub fn witness_assignment(&self) -> crate::gr1cs::Result<Vec<F>> {
116 self.inner()
117 .ok_or(SynthesisError::AssignmentMissing)
118 .and_then(|cs| cs.borrow().witness_assignment().map(|v| v.to_vec()))
119 }
120
121 #[inline]
123 pub fn num_variables(&self) -> usize {
124 self.inner().map_or(0, |cs| cs.borrow().num_variables())
125 }
126
127 #[inline]
128 pub fn num_predicates(&self) -> usize {
130 self.inner().map_or(0, |cs| cs.borrow().num_predicates())
131 }
132
133 #[inline]
135 pub fn num_witness_variables(&self) -> usize {
136 self.inner()
137 .map_or(0, |cs| cs.borrow().num_witness_variables())
138 }
139
140 #[inline]
144 pub fn enforce_constraint(
145 &self,
146 predicate_label: &str,
147 lc_vec: impl IntoIterator<
148 Item = Box<dyn FnOnce() -> LinearCombination<F>>,
149 IntoIter: ExactSizeIterator,
150 >,
151 ) -> crate::gr1cs::Result<()> {
152 self.inner()
153 .ok_or(SynthesisError::MissingCS)
154 .and_then(|cs| cs.borrow_mut().enforce_constraint(predicate_label, lc_vec))
155 }
156
157 #[inline]
159 pub fn enforce_constraint_arity_2(
160 &self,
161 predicate_label: &str,
162 a: impl FnOnce() -> LinearCombination<F>,
163 b: impl FnOnce() -> LinearCombination<F>,
164 ) -> crate::gr1cs::Result<()> {
165 self.inner()
166 .ok_or(SynthesisError::MissingCS)
167 .and_then(|cs| {
168 cs.borrow_mut()
169 .enforce_constraint_arity_2(predicate_label, a, b)
170 })
171 }
172
173 #[inline]
175 pub fn enforce_constraint_arity_3(
176 &self,
177 predicate_label: &str,
178 a: impl FnOnce() -> LinearCombination<F>,
179 b: impl FnOnce() -> LinearCombination<F>,
180 c: impl FnOnce() -> LinearCombination<F>,
181 ) -> crate::gr1cs::Result<()> {
182 self.inner()
183 .ok_or(SynthesisError::MissingCS)
184 .and_then(|cs| {
185 cs.borrow_mut()
186 .enforce_constraint_arity_3(predicate_label, a, b, c)
187 })
188 }
189
190 #[inline]
192 pub fn enforce_constraint_arity_4(
193 &self,
194 predicate_label: &str,
195 a: impl FnOnce() -> LinearCombination<F>,
196 b: impl FnOnce() -> LinearCombination<F>,
197 c: impl FnOnce() -> LinearCombination<F>,
198 d: impl FnOnce() -> LinearCombination<F>,
199 ) -> crate::gr1cs::Result<()> {
200 self.inner()
201 .ok_or(SynthesisError::MissingCS)
202 .and_then(|cs| {
203 cs.borrow_mut()
204 .enforce_constraint_arity_4(predicate_label, a, b, c, d)
205 })
206 }
207
208 #[inline]
210 pub fn enforce_constraint_arity_5(
211 &self,
212 predicate_label: &str,
213 a: impl FnOnce() -> LinearCombination<F>,
214 b: impl FnOnce() -> LinearCombination<F>,
215 c: impl FnOnce() -> LinearCombination<F>,
216 d: impl FnOnce() -> LinearCombination<F>,
217 e: impl FnOnce() -> LinearCombination<F>,
218 ) -> crate::gr1cs::Result<()> {
219 self.inner()
220 .ok_or(SynthesisError::MissingCS)
221 .and_then(|cs| {
222 cs.borrow_mut()
223 .enforce_constraint_arity_5(predicate_label, a, b, c, d, e)
224 })
225 }
226
227 #[inline]
235 pub fn enforce_r1cs_constraint(
236 &self,
237 a: impl FnOnce() -> LinearCombination<F>,
238 b: impl FnOnce() -> LinearCombination<F>,
239 c: impl FnOnce() -> LinearCombination<F>,
240 ) -> crate::gr1cs::Result<()> {
241 if !self.should_construct_matrices() {
242 return Ok(());
243 }
244 if !self.has_predicate(R1CS_PREDICATE_LABEL) {
245 return Err(SynthesisError::PredicateNotFound);
246 }
247 self.inner()
248 .ok_or(SynthesisError::MissingCS)
249 .and_then(|cs| cs.borrow_mut().enforce_r1cs_constraint(a, b, c))
250 }
251
252 #[inline]
258 pub fn enforce_sr1cs_constraint(
259 &self,
260 a: impl FnOnce() -> LinearCombination<F>,
261 b: impl FnOnce() -> LinearCombination<F>,
262 ) -> crate::gr1cs::Result<()> {
263 if !self.should_construct_matrices() {
264 return Ok(());
265 }
266 if !self.has_predicate(SR1CS_PREDICATE_LABEL) {
267 return Err(SynthesisError::PredicateNotFound);
268 }
269 self.inner()
270 .ok_or(SynthesisError::MissingCS)
271 .and_then(|cs| cs.borrow_mut().enforce_sr1cs_constraint(a, b))
272 }
273
274 #[inline]
276 pub fn new_lc(
277 &self,
278 lc: impl FnOnce() -> LinearCombination<F>,
279 ) -> crate::gr1cs::Result<Variable> {
280 match self.inner() {
281 Some(cs) => cs.borrow_mut().new_lc(lc),
282 None => Err(SynthesisError::MissingCS),
283 }
284 }
285
286 pub fn set_mode(&self, mode: SynthesisMode) {
289 self.inner().map_or((), |cs| cs.borrow_mut().set_mode(mode))
290 }
291
292 #[inline]
297 pub fn is_in_setup_mode(&self) -> bool {
298 self.inner()
299 .is_some_and(|cs| cs.borrow().is_in_setup_mode())
300 }
301
302 #[inline]
305 pub fn optimization_goal(&self) -> OptimizationGoal {
306 self.inner().map_or(OptimizationGoal::Constraints, |cs| {
307 cs.borrow().optimization_goal()
308 })
309 }
310
311 #[inline]
314 pub fn set_optimization_goal(&self, goal: OptimizationGoal) {
315 self.inner()
316 .map_or((), |cs| cs.borrow_mut().set_optimization_goal(goal))
317 }
318
319 #[inline]
323 pub fn should_outline_instances(&self) -> bool {
324 self.inner()
325 .is_some_and(|cs| cs.borrow().should_outline_instances())
326 }
327
328 #[inline]
331 pub fn set_instance_outliner(&self, outliner: InstanceOutliner<F>) {
332 self.inner()
333 .map_or((), |cs| cs.borrow_mut().set_instance_outliner(outliner))
334 }
335
336 #[inline]
338 pub fn should_construct_matrices(&self) -> bool {
339 self.inner()
340 .is_some_and(|cs| cs.borrow().should_construct_matrices())
341 }
342
343 #[inline]
345 pub fn new_input_variable<Func>(&self, f: Func) -> crate::utils::Result<Variable>
346 where
347 Func: FnOnce() -> crate::utils::Result<F>,
348 {
349 self.inner()
350 .ok_or(SynthesisError::MissingCS)
351 .and_then(|cs| {
352 if self.is_in_setup_mode() {
353 cs.borrow_mut().new_input_variable(f)
354 } else {
355 let value = f();
358 cs.borrow_mut().new_input_variable(|| value)
359 }
360 })
361 }
362
363 #[inline]
365 pub fn new_witness_variable<Func>(&self, f: Func) -> crate::utils::Result<Variable>
366 where
367 Func: FnOnce() -> crate::utils::Result<F>,
368 {
369 let a = self
370 .inner()
371 .ok_or(SynthesisError::MissingCS)
372 .and_then(|cs| {
373 if self.is_in_setup_mode() {
374 cs.borrow_mut().new_witness_variable(f)
375 } else {
376 let value = f();
379 cs.borrow_mut().new_witness_variable(|| value)
380 }
381 });
382 a
383 }
384
385 pub fn register_predicate(
387 &self,
388 label: &str,
389 predicate: PredicateConstraintSystem<F>,
390 ) -> crate::utils::Result<()> {
391 self.inner()
392 .ok_or(SynthesisError::MissingCS)
393 .and_then(|cs| cs.borrow_mut().register_predicate(label, predicate))
394 }
395
396 pub fn remove_predicate(&self, label: &str) {
398 self.inner()
399 .map_or((), |cs| cs.borrow_mut().remove_predicate(label))
400 }
401
402 pub fn has_predicate(&self, predicate_label: &str) -> bool {
404 self.inner()
405 .is_some_and(|cs| cs.borrow().has_predicate(predicate_label))
406 }
407
408 pub fn assigned_value(&self, v: Variable) -> Option<F> {
410 self.inner().and_then(|cs| cs.borrow().assigned_value(v))
411 }
412
413 pub fn is_satisfied(&self) -> crate::utils::Result<bool> {
417 self.inner()
418 .ok_or(SynthesisError::MissingCS)
419 .and_then(|cs| cs.borrow().is_satisfied())
420 }
421
422 pub fn which_is_unsatisfied(&self) -> crate::utils::Result<Option<String>> {
428 self.inner()
429 .ok_or(SynthesisError::MissingCS)
430 .and_then(|cs| cs.borrow().which_is_unsatisfied())
431 }
432
433 pub fn finalize(&self) {
436 if let Some(cs) = self.inner() {
437 cs.borrow_mut().finalize();
438 }
439 }
440
441 pub fn inline_all_lcs(&self) {
450 if let Some(cs) = self.inner() {
451 cs.borrow_mut().inline_all_lcs();
452 }
453 }
454
455 #[must_use]
457 pub fn or(self, other: Self) -> Self {
458 match self {
459 ConstraintSystemRef::None => other,
460 ConstraintSystemRef::CS(_) => self,
461 }
462 }
463
464 pub fn is_none(&self) -> bool {
466 matches!(self, ConstraintSystemRef::None)
467 }
468
469 pub(crate) fn inner(&self) -> Option<&Rc<RefCell<ConstraintSystem<F>>>> {
470 match self {
471 Self::CS(a) => Some(a),
472 Self::None => None,
473 }
474 }
475
476 pub fn into_inner(self) -> Option<ConstraintSystem<F>> {
480 match self {
481 Self::CS(a) => Rc::try_unwrap(a).ok().map(|s| s.into_inner()),
482 Self::None => None,
483 }
484 }
485
486 #[inline]
489 pub fn to_matrices(&self) -> crate::gr1cs::Result<BTreeMap<Label, Vec<Matrix<F>>>> {
490 self.inner()
491 .ok_or(SynthesisError::MissingCS)
492 .and_then(|cs| cs.borrow().to_matrices())
493 }
494
495 pub fn get_lc(&self, var: Variable) -> Option<LinearCombination<F>> {
499 self.inner().map(|cs| cs.borrow().get_lc(var))
500 }
501
502 pub fn make_row(&self, lc: LinearCombination<F>) -> crate::utils::Result<Vec<(F, usize)>> {
504 self.inner()
505 .ok_or(SynthesisError::MissingCS)
506 .map(|cs| cs.borrow().make_row(lc))
507 }
508
509 #[inline]
514 pub fn borrow(&self) -> Option<Ref<'_, ConstraintSystem<F>>> {
515 self.inner().map(|cs| cs.borrow())
516 }
517
518 #[inline]
523 pub fn borrow_mut(&self) -> Option<RefMut<'_, ConstraintSystem<F>>> {
524 self.inner().map(|cs| cs.borrow_mut())
525 }
526
527 pub fn constraint_names(&self) -> Option<Vec<String>> {
529 #[cfg(feature = "std")]
530 {
531 self.inner().and_then(|cs| {
532 cs.borrow()
533 .predicate_traces
534 .iter()
535 .flat_map(|(key, values)| values.iter().map(move |v| (key.clone(), v)))
536 .map(|(label, trace)| {
537 let mut constraint_path = String::new();
538 let mut prev_module_path = "";
539 let mut prefixes = ark_std::collections::BTreeSet::new();
540 for step in trace.as_ref()?.path() {
541 let module_path = if prev_module_path == step.module_path {
542 prefixes.insert(step.module_path.to_string());
543 String::new()
544 } else {
545 let mut parts = step
546 .module_path
547 .split("::")
548 .filter(|&part| part != "r1cs_std" && part != "constraints");
549 let mut path_so_far = String::new();
550 for part in parts.by_ref() {
551 if path_so_far.is_empty() {
552 path_so_far += part;
553 } else {
554 path_so_far += &["::", part].join("");
555 }
556 if prefixes.contains(&path_so_far) {
557 continue;
558 } else {
559 prefixes.insert(path_so_far.clone());
560 break;
561 }
562 }
563 parts.collect::<Vec<_>>().join("::") + "::"
564 };
565 prev_module_path = step.module_path;
566 constraint_path += &["/", &module_path, step.name].join("");
567 }
568 Some(constraint_path + " (predicate:" + &label + ")")
569 })
570 .collect::<Option<Vec<_>>>()
571 })
572 }
573 #[cfg(not(feature = "std"))]
574 {
575 None
576 }
577 }
578}