1use log::trace;
2use std::cmp::{Ordering, min, max};
3use std::collections::HashMap;
4use std::fmt;
5
6use super::{VariableName, VariableType};
7
8#[derive(Clone, Copy, PartialEq, Eq, Hash)]
10pub enum Degree {
11 Constant,
12 Linear,
13 Quadratic,
14 NonQuadratic,
15}
16
17impl PartialOrd<Degree> for Degree {
19 fn partial_cmp(&self, other: &Degree) -> Option<Ordering> {
20 Some(self.cmp(other))
21 }
22}
23
24impl Ord for Degree {
26 fn cmp(&self, other: &Degree) -> Ordering {
27 use Degree::*;
28 match (self, other) {
29 (Constant, Constant) => Ordering::Equal,
31 (Constant, Linear) | (Constant, Quadratic) | (Constant, NonQuadratic) => Ordering::Less,
32 (Linear, Linear) => Ordering::Equal,
34 (Linear, Quadratic) | (Linear, NonQuadratic) => Ordering::Less,
35 (Quadratic, Quadratic) => Ordering::Equal,
37 (Quadratic, NonQuadratic) => Ordering::Less,
38 (NonQuadratic, NonQuadratic) => Ordering::Equal,
40 _ => Ordering::Greater,
42 }
43 }
44}
45
46impl Degree {
47 pub fn add(&self, other: &Degree) -> Degree {
48 max(*self, *other)
49 }
50
51 pub fn infix_sub(&self, other: &Degree) -> Degree {
52 max(*self, *other)
53 }
54
55 pub fn mul(&self, other: &Degree) -> Degree {
56 use Degree::*;
57 match (self, other) {
58 (Constant, _) => *other,
59 (_, Constant) => *self,
60 (Linear, Linear) => Quadratic,
61 _ => NonQuadratic,
62 }
63 }
64
65 pub fn pow(&self, other: &Degree) -> Degree {
66 use Degree::*;
67 if (*self, *other) == (Constant, Constant) {
68 Constant
69 } else {
70 NonQuadratic
71 }
72 }
73
74 pub fn div(&self, other: &Degree) -> Degree {
75 use Degree::*;
76 if *other == Constant {
77 *self
78 } else {
79 NonQuadratic
80 }
81 }
82
83 pub fn int_div(&self, other: &Degree) -> Degree {
84 use Degree::*;
85 if (*self, *other) == (Constant, Constant) {
86 Constant
87 } else {
88 NonQuadratic
89 }
90 }
91
92 pub fn modulo(&self, other: &Degree) -> Degree {
93 use Degree::*;
94 if (*self, *other) == (Constant, Constant) {
95 Constant
96 } else {
97 NonQuadratic
98 }
99 }
100
101 pub fn shift_left(&self, other: &Degree) -> Degree {
102 use Degree::*;
103 if (*self, *other) == (Constant, Constant) {
104 Constant
105 } else {
106 NonQuadratic
107 }
108 }
109
110 pub fn shift_right(&self, other: &Degree) -> Degree {
111 use Degree::*;
112 if (*self, *other) == (Constant, Constant) {
113 Constant
114 } else {
115 NonQuadratic
116 }
117 }
118
119 pub fn lesser(&self, other: &Degree) -> Degree {
120 use Degree::*;
121 if (*self, *other) == (Constant, Constant) {
122 Constant
123 } else {
124 NonQuadratic
125 }
126 }
127
128 pub fn greater(&self, other: &Degree) -> Degree {
129 use Degree::*;
130 if (*self, *other) == (Constant, Constant) {
131 Constant
132 } else {
133 NonQuadratic
134 }
135 }
136
137 pub fn lesser_eq(&self, other: &Degree) -> Degree {
138 use Degree::*;
139 if (*self, *other) == (Constant, Constant) {
140 Constant
141 } else {
142 NonQuadratic
143 }
144 }
145
146 pub fn greater_eq(&self, other: &Degree) -> Degree {
147 use Degree::*;
148 if (*self, *other) == (Constant, Constant) {
149 Constant
150 } else {
151 NonQuadratic
152 }
153 }
154 pub fn equal(&self, other: &Degree) -> Degree {
155 use Degree::*;
156 if (*self, *other) == (Constant, Constant) {
157 Constant
158 } else {
159 NonQuadratic
160 }
161 }
162
163 pub fn not_equal(&self, other: &Degree) -> Degree {
164 use Degree::*;
165 if (*self, *other) == (Constant, Constant) {
166 Constant
167 } else {
168 NonQuadratic
169 }
170 }
171
172 pub fn bit_or(&self, other: &Degree) -> Degree {
173 use Degree::*;
174 if (*self, *other) == (Constant, Constant) {
175 Constant
176 } else {
177 NonQuadratic
178 }
179 }
180
181 pub fn bit_and(&self, other: &Degree) -> Degree {
182 use Degree::*;
183 if (*self, *other) == (Constant, Constant) {
184 Constant
185 } else {
186 NonQuadratic
187 }
188 }
189
190 pub fn bit_xor(&self, other: &Degree) -> Degree {
191 use Degree::*;
192 if (*self, *other) == (Constant, Constant) {
193 Constant
194 } else {
195 NonQuadratic
196 }
197 }
198
199 pub fn bool_or(&self, other: &Degree) -> Degree {
200 use Degree::*;
201 if (*self, *other) == (Constant, Constant) {
202 Constant
203 } else {
204 NonQuadratic
205 }
206 }
207
208 pub fn bool_and(&self, other: &Degree) -> Degree {
209 use Degree::*;
210 if (*self, *other) == (Constant, Constant) {
211 Constant
212 } else {
213 NonQuadratic
214 }
215 }
216
217 pub fn prefix_sub(&self) -> Degree {
218 *self
219 }
220
221 pub fn complement(&self) -> Degree {
222 use Degree::*;
223 Quadratic
224 }
225
226 pub fn bool_not(&self) -> Degree {
227 use Degree::*;
228 Quadratic
229 }
230}
231
232impl fmt::Debug for Degree {
233 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
234 use Degree::*;
235 match self {
236 Constant => write!(f, "constant"),
237 Linear => write!(f, "linear"),
238 Quadratic => write!(f, "quadratic"),
239 NonQuadratic => write!(f, "non-quadratic"),
240 }
241 }
242}
243
244#[derive(Clone, PartialEq, Eq, Hash)]
246pub struct DegreeRange(Degree, Degree);
247
248impl DegreeRange {
249 #[must_use]
250 pub fn new(start: Degree, end: Degree) -> DegreeRange {
251 DegreeRange(start, end)
252 }
253
254 #[must_use]
255 pub fn start(&self) -> Degree {
256 self.0
257 }
258
259 #[must_use]
260 pub fn end(&self) -> Degree {
261 self.1
262 }
263
264 #[must_use]
265 pub fn contains(&self, degree: Degree) -> bool {
266 self.start() <= degree && degree <= self.end()
267 }
268
269 #[must_use]
271 pub fn is_constant(&self) -> bool {
272 self.end() <= Degree::Constant
273 }
274
275 #[must_use]
277 pub fn is_linear(&self) -> bool {
278 self.end() <= Degree::Linear
279 }
280
281 #[must_use]
283 pub fn is_quadratic(&self) -> bool {
284 self.end() <= Degree::Quadratic
285 }
286
287 pub fn inf(&self, other: &DegreeRange) -> DegreeRange {
291 DegreeRange(min(self.start(), other.start()), max(self.end(), other.end()))
292 }
293
294 pub fn iter_inf<'a, T: IntoIterator<Item = &'a DegreeRange>>(ranges: T) -> DegreeRange {
301 let mut ranges = ranges.into_iter();
302 if let Some(range) = ranges.next() {
303 let mut result = range.clone();
304 for range in ranges {
305 result = result.inf(range);
306 }
307 result
308 } else {
309 panic!("iterator must not be empty")
310 }
311 }
312
313 pub fn iter_opt<'a, T: IntoIterator<Item = Option<&'a DegreeRange>>>(
317 ranges: T,
318 ) -> Option<DegreeRange> {
319 let ranges = ranges.into_iter().collect::<Option<Vec<_>>>();
320 match ranges {
321 Some(ranges) if !ranges.is_empty() => Some(Self::iter_inf(ranges)),
322 _ => None,
323 }
324 }
325
326 pub fn add(&self, other: &DegreeRange) -> DegreeRange {
327 DegreeRange::new(self.start().add(&other.start()), self.end().add(&other.end()))
328 }
329
330 pub fn infix_sub(&self, other: &DegreeRange) -> DegreeRange {
331 DegreeRange::new(self.start().infix_sub(&other.start()), self.end().infix_sub(&other.end()))
332 }
333
334 pub fn mul(&self, other: &DegreeRange) -> DegreeRange {
335 DegreeRange::new(self.start().mul(&other.start()), self.end().mul(&other.end()))
336 }
337
338 pub fn pow(&self, other: &DegreeRange) -> DegreeRange {
339 DegreeRange::new(self.start().pow(&other.start()), self.end().pow(&other.end()))
340 }
341
342 pub fn div(&self, other: &DegreeRange) -> DegreeRange {
343 DegreeRange::new(self.start().div(&other.start()), self.end().div(&other.end()))
344 }
345
346 pub fn int_div(&self, other: &DegreeRange) -> DegreeRange {
347 DegreeRange::new(self.start().int_div(&other.start()), self.end().int_div(&other.end()))
348 }
349
350 pub fn modulo(&self, other: &DegreeRange) -> DegreeRange {
351 DegreeRange::new(self.start().modulo(&other.start()), self.end().modulo(&other.end()))
352 }
353
354 pub fn shift_left(&self, other: &DegreeRange) -> DegreeRange {
355 DegreeRange::new(
356 self.start().shift_left(&other.start()),
357 self.end().shift_left(&other.end()),
358 )
359 }
360
361 pub fn shift_right(&self, other: &DegreeRange) -> DegreeRange {
362 DegreeRange::new(
363 self.start().shift_right(&other.start()),
364 self.end().shift_right(&other.end()),
365 )
366 }
367
368 pub fn lesser(&self, other: &DegreeRange) -> DegreeRange {
369 DegreeRange::new(self.start().lesser(&other.start()), self.end().lesser(&other.end()))
370 }
371
372 pub fn greater(&self, other: &DegreeRange) -> DegreeRange {
373 DegreeRange::new(self.start().greater(&other.start()), self.end().greater(&other.end()))
374 }
375
376 pub fn lesser_eq(&self, other: &DegreeRange) -> DegreeRange {
377 DegreeRange::new(self.start().lesser_eq(&other.start()), self.end().lesser_eq(&other.end()))
378 }
379
380 pub fn greater_eq(&self, other: &DegreeRange) -> DegreeRange {
381 DegreeRange::new(
382 self.start().greater_eq(&other.start()),
383 self.end().greater_eq(&other.end()),
384 )
385 }
386 pub fn equal(&self, other: &DegreeRange) -> DegreeRange {
387 DegreeRange::new(self.start().equal(&other.start()), self.end().equal(&other.end()))
388 }
389
390 pub fn not_equal(&self, other: &DegreeRange) -> DegreeRange {
391 DegreeRange::new(self.start().not_equal(&other.start()), self.end().not_equal(&other.end()))
392 }
393
394 pub fn bit_or(&self, other: &DegreeRange) -> DegreeRange {
395 DegreeRange::new(self.start().bit_or(&other.start()), self.end().bit_or(&other.end()))
396 }
397
398 pub fn bit_and(&self, other: &DegreeRange) -> DegreeRange {
399 DegreeRange::new(self.start().bit_and(&other.start()), self.end().bit_and(&other.end()))
400 }
401
402 pub fn bit_xor(&self, other: &DegreeRange) -> DegreeRange {
403 DegreeRange::new(self.start().bit_xor(&other.start()), self.end().bit_xor(&other.end()))
404 }
405
406 pub fn bool_or(&self, other: &DegreeRange) -> DegreeRange {
407 DegreeRange::new(self.start().bool_or(&other.start()), self.end().bool_or(&other.end()))
408 }
409
410 pub fn bool_and(&self, other: &DegreeRange) -> DegreeRange {
411 DegreeRange::new(self.start().bool_and(&other.start()), self.end().bool_and(&other.end()))
412 }
413
414 pub fn prefix_sub(&self) -> DegreeRange {
415 DegreeRange::new(self.start().prefix_sub(), self.end().prefix_sub())
416 }
417
418 pub fn complement(&self) -> DegreeRange {
419 DegreeRange::new(self.start().complement(), self.end().complement())
420 }
421
422 pub fn bool_not(&self) -> DegreeRange {
423 DegreeRange::new(self.start().bool_not(), self.end().bool_not())
424 }
425}
426
427impl From<Degree> for DegreeRange {
429 fn from(degree: Degree) -> DegreeRange {
430 DegreeRange(degree, degree)
431 }
432}
433
434impl fmt::Debug for DegreeRange {
435 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
436 write!(f, "[{:?}, {:?}]", self.start(), self.end())
437 }
438}
439
440#[derive(Default, Clone)]
443pub struct DegreeEnvironment {
444 degree_ranges: HashMap<VariableName, DegreeRange>,
448 var_types: HashMap<VariableName, VariableType>,
449}
450
451impl DegreeEnvironment {
452 pub fn new() -> DegreeEnvironment {
453 DegreeEnvironment::default()
454 }
455
456 pub fn set_degree(&mut self, var: &VariableName, range: &DegreeRange) -> bool {
460 if self.degree_ranges.insert(var.clone(), range.clone()).is_none() {
461 trace!("setting degree range of `{var:?}` to {range:?}");
462 true
463 } else {
464 false
465 }
466 }
467
468 pub fn set_type(&mut self, var: &VariableName, var_type: &VariableType) {
470 if self.var_types.insert(var.clone(), var_type.clone()).is_none() {
471 trace!("setting type of `{var:?}` to `{var_type}`");
472 }
473 }
474
475 #[must_use]
477 pub fn degree(&self, var: &VariableName) -> Option<&DegreeRange> {
478 self.degree_ranges.get(var)
479 }
480
481 #[must_use]
483 pub fn is_local(&self, var: &VariableName) -> bool {
484 matches!(self.var_types.get(var), Some(VariableType::Local))
485 }
486}
487
488pub trait DegreeMeta {
489 fn propagate_degrees(&mut self, env: &DegreeEnvironment) -> bool;
492
493 #[must_use]
495 fn degree(&self) -> Option<&DegreeRange>;
496}
497
498#[derive(Default, Clone)]
499pub struct DegreeKnowledge {
500 degree_range: Option<DegreeRange>,
502}
503
504impl DegreeKnowledge {
505 #[must_use]
506 pub fn new() -> DegreeKnowledge {
507 DegreeKnowledge::default()
508 }
509
510 pub fn set_degree(&mut self, range: &DegreeRange) -> bool {
511 let result = self.degree_range.is_none();
512 self.degree_range = Some(range.clone());
513 result
514 }
515
516 #[must_use]
517 pub fn degree(&self) -> Option<&DegreeRange> {
518 self.degree_range.as_ref()
519 }
520
521 #[must_use]
524 pub fn is_constant(&self) -> bool {
525 if let Some(range) = &self.degree_range {
526 range.is_constant()
527 } else {
528 false
529 }
530 }
531
532 #[must_use]
535 pub fn is_linear(&self) -> bool {
536 if let Some(range) = &self.degree_range {
537 range.is_linear()
538 } else {
539 false
540 }
541 }
542
543 #[must_use]
546 pub fn is_quadratic(&self) -> bool {
547 if let Some(range) = &self.degree_range {
548 range.is_quadratic()
549 } else {
550 false
551 }
552 }
553}
554
555#[cfg(test)]
556mod tests {
557 use super::{Degree, DegreeKnowledge};
558
559 #[test]
560 fn test_value_knowledge() {
561 let mut value = DegreeKnowledge::new();
562 assert!(value.degree().is_none());
563 assert!(!value.is_constant());
564 assert!(!value.is_linear());
565 assert!(!value.is_quadratic());
566
567 assert!(value.set_degree(&Degree::Constant.into()));
568 assert!(value.degree().is_some());
569 assert!(value.is_constant());
570 assert!(value.is_linear());
571 assert!(value.is_quadratic());
572
573 assert!(!value.set_degree(&Degree::Linear.into()));
574 assert!(value.degree().is_some());
575 assert!(!value.is_constant());
576 assert!(value.is_linear());
577 assert!(value.is_quadratic());
578
579 assert!(!value.set_degree(&Degree::Quadratic.into()));
580 assert!(value.degree().is_some());
581 assert!(!value.is_constant());
582 assert!(!value.is_linear());
583 assert!(value.is_quadratic());
584
585 assert!(!value.set_degree(&Degree::NonQuadratic.into()));
586 assert!(value.degree().is_some());
587 assert!(!value.is_constant());
588 assert!(!value.is_linear());
589 assert!(!value.is_quadratic());
590 }
591}