From 29d969f6f257a107b912fa895e219aececee4240 Mon Sep 17 00:00:00 2001
From: Aaron Councilman <aaronjc4@illinois.edu>
Date: Wed, 25 Sep 2024 15:28:15 -0500
Subject: [PATCH] Fixes to dynamic constant generation from Juno

---
 juno_frontend/src/dynconst.rs | 72 ++++++++++++++++++-----------------
 1 file changed, 38 insertions(+), 34 deletions(-)

diff --git a/juno_frontend/src/dynconst.rs b/juno_frontend/src/dynconst.rs
index 72a9d0ff..ba726299 100644
--- a/juno_frontend/src/dynconst.rs
+++ b/juno_frontend/src/dynconst.rs
@@ -256,16 +256,29 @@ impl DynConst {
                                                   .collect::<Vec<_>>();
         non_zero_coeff.sort_by(|(d1, _), (d2, _)| d1.cmp(d2));
 
-        non_zero_coeff.iter().map(|(d, c)| self.build_mono(builder, d, c))
-                             .collect::<Vec<_>>().into_iter()
-                             .reduce(|x, y| builder.create_dynamic_constant_add(x, y))
-                             // If there are no terms, this dynamic constant is 0
-                             .unwrap_or_else(|| builder.create_dynamic_constant_constant(0))
+        let (pos, neg) : (Vec<_>, Vec<_>) = 
+            non_zero_coeff.iter()
+                          .map(|(d, c)| self.build_mono(builder, d, c))
+                          .partition(|(_, neg)| ! *neg);
+
+        let pos_sum = pos.into_iter().map(|(t, _)| t)
+                         .reduce(|x, y| builder.create_dynamic_constant_add(x, y))
+                         .unwrap_or_else(|| builder.create_dynamic_constant_constant(0));
+
+        let neg_sum = neg.into_iter().map(|(t, _)| t)
+                         .reduce(|x, y| builder.create_dynamic_constant_add(x, y));
+
+        match neg_sum {
+            None => pos_sum,
+            Some(neg) => builder.create_dynamic_constant_sub(pos_sum, neg)
+        }
     }
 
     // Build's a monomial, with a given list of powers (term) and coefficients
+    // Returns the dynamic constant id of the positive value and a boolean
+    // indicating whether the value should actually be negative
     fn build_mono(&self, builder : &mut Builder, term : &Vec<i64>,
-                  coeff : &Ratio<i64>) -> DynamicConstantID {
+                  coeff : &Ratio<i64>) -> (DynamicConstantID, bool) {
         let term_id = term.iter().enumerate()
                           .filter(|(_, p)| **p != 0)
                           .map(|(v, p)| self.build_power(builder, v, *p))
@@ -279,20 +292,30 @@ impl DynConst {
                     panic!("Dynamic constant is a non-integer constant")
                 } else {
                     let val : i64 = coeff.to_integer();
-                    if val < 0 {
-                        panic!("Dynamic constant is a negative constant")
-                    } else {
-                        builder.create_dynamic_constant_constant(val as usize)
-                    }
+                    (builder.create_dynamic_constant_constant(val.abs() as usize),
+                     val < 0)
                 }
             },
             Some(term) => {
-                if coeff.is_one() { term }
+                if coeff.is_one() { (term, false) }
                 else {
-                    let numer : i64 = *coeff.numer();
+                    let numer : i64 = coeff.numer().abs();
                     let denom : i64 = *coeff.denom(); // > 0
-                    let coeff_id = self.build_coeff(builder, numer, denom);
-                    builder.create_dynamic_constant_mul(coeff_id, term)
+                
+                    let with_numer =
+                        if numer == 1 { term }
+                        else { 
+                            let numer_id = builder.create_dynamic_constant_constant(numer as usize);
+                            builder.create_dynamic_constant_mul(numer_id, term)
+                        };
+                    let with_denom =
+                        if denom == 1 { with_numer }
+                        else {
+                            let denom_id = builder.create_dynamic_constant_constant(denom as usize);
+                            builder.create_dynamic_constant_div(with_numer, denom_id)
+                        };
+
+                    (with_denom, numer < 0)
                 }
             },
         }
@@ -316,23 +339,4 @@ impl DynConst {
             builder.create_dynamic_constant_div(one_id, power_id)
         }
     }
-
-    // Build's a dynamic constant that is a certain rational number (n / d)
-    fn build_coeff(&self, builder : &mut Builder, n : i64, d : i64) -> DynamicConstantID {
-        assert!(n != 0); assert!(d > 0);
-
-        let n_abs_term = builder.create_dynamic_constant_constant(n.abs() as usize);
-        let n_term = 
-            if n > 0 { n_abs_term } 
-            else {
-                let zero_term = builder.create_dynamic_constant_constant(0);
-                builder.create_dynamic_constant_sub(zero_term, n_abs_term)
-            };
-
-        if d == 1 { n_term }
-        else {
-            let d_term = builder.create_dynamic_constant_constant(d as usize);
-            builder.create_dynamic_constant_div(n_term, d_term)
-        }
-    }
 }
-- 
GitLab