From 7080e382e19454f3cf1c18544ed902b1a9c202f7 Mon Sep 17 00:00:00 2001 From: Dennis Kuhnert Date: Sun, 26 Feb 2017 12:17:55 +0100 Subject: [PATCH] Add iterative version of count_variables_add --- src/r1cs.rs | 487 ++++++++++++++++++++++++++++------------------------ 1 file changed, 262 insertions(+), 225 deletions(-) diff --git a/src/r1cs.rs b/src/r1cs.rs index baef8da6..32ca6e01 100644 --- a/src/r1cs.rs +++ b/src/r1cs.rs @@ -9,139 +9,6 @@ use absy::*; use absy::Expression::*; use field::Field; -/// Returns a `HashMap` containing variables and the number of occurences -/// -/// # Arguments -/// -/// * `expr` - Expression only containing Numbers, Variables, Add and Mult -/// -/// # Example -/// -/// `7 * x + 4 * y + x` -> { x => 8, y = 4 } -fn count_variables_add(expr: &Expression) -> HashMap { - let mut count = HashMap::new(); - match expr.clone() { - NumberLiteral(x) => { count.insert("~one".to_string(), x); }, - VariableReference(var) => { count.insert(var, T::one()); }, - Mult(box NumberLiteral(x1), box NumberLiteral(x2)) => { count.insert("~one".to_string(), x1 * x2); }, - Mult(box NumberLiteral(x), box VariableReference(var)) | - Mult(box VariableReference(var), box NumberLiteral(x)) => { count.insert(var, x); }, - Add(box lhs, box rhs) => { - match (lhs, rhs) { - (NumberLiteral(x), NumberLiteral(y)) => { - let num = count.entry("~one".to_string()).or_insert(T::zero()); - *num = num.clone() + x + y; - }, - (VariableReference(v), NumberLiteral(x)) | - (NumberLiteral(x), VariableReference(v)) => { - { - let num = count.entry("~one".to_string()).or_insert(T::zero()); - *num = num.clone() + x; - } - let var = count.entry(v).or_insert(T::zero()); - *var = var.clone() + T::one(); - }, - (VariableReference(v1), VariableReference(v2)) => { - { - let var1 = count.entry(v1).or_insert(T::zero()); - *var1 = var1.clone() + T::one(); - } - let var2 = count.entry(v2).or_insert(T::zero()); - *var2 = var2.clone() + T::one(); - }, - (NumberLiteral(x), e @ Add(..)) | - (e @ Add(..), NumberLiteral(x)) => { - { - let num = count.entry("~one".to_string()).or_insert(T::zero()); - *num = num.clone() + x; - } - let vars = count_variables_add(&e); - for (key, value) in &vars { - let val = count.entry(key.to_string()).or_insert(T::zero()); - *val = val.clone() + value; - } - }, - (VariableReference(v), e @ Add(..)) | - (e @ Add(..), VariableReference(v)) => { - { - let var = count.entry(v).or_insert(T::zero()); - *var = var.clone() + T::one(); - } - let vars = count_variables_add(&e); - for (key, value) in &vars { - let val = count.entry(key.to_string()).or_insert(T::zero()); - *val = val.clone() + value; - } - }, - (NumberLiteral(x), Mult(box NumberLiteral(n), box VariableReference(v))) | - (NumberLiteral(x), Mult(box VariableReference(v), box NumberLiteral(n))) | - (Mult(box NumberLiteral(n), box VariableReference(v)), NumberLiteral(x)) | - (Mult(box VariableReference(v), box NumberLiteral(n)), NumberLiteral(x)) => { - { - let num = count.entry("~one".to_string()).or_insert(T::zero()); - *num = num.clone() + x; - } - let var = count.entry(v).or_insert(T::zero()); - *var = var.clone() + n; - }, - (VariableReference(v1), Mult(box NumberLiteral(n), box VariableReference(v2))) | - (VariableReference(v1), Mult(box VariableReference(v2), box NumberLiteral(n))) | - (Mult(box NumberLiteral(n), box VariableReference(v2)), VariableReference(v1)) | - (Mult(box VariableReference(v2), box NumberLiteral(n)), VariableReference(v1)) => { - { - let var = count.entry(v1).or_insert(T::zero()); - *var = var.clone() + T::one(); - } - let var = count.entry(v2).or_insert(T::zero()); - *var = var.clone() + n; - }, - (e @ Add(..), Mult(box NumberLiteral(n), box VariableReference(v))) | - (e @ Add(..), Mult(box VariableReference(v), box NumberLiteral(n))) | - (Mult(box NumberLiteral(n), box VariableReference(v)), e @ Add(..)) | - (Mult(box VariableReference(v), box NumberLiteral(n)), e @ Add(..)) => { - { - let var = count.entry(v).or_insert(T::zero()); - *var = var.clone() + n; - } - let vars = count_variables_add(&e); - for (key, value) in &vars { - let val = count.entry(key.to_string()).or_insert(T::zero()); - *val = val.clone() + value; - } - }, - (Mult(box NumberLiteral(n1), box VariableReference(v1)), Mult(box NumberLiteral(n2), box VariableReference(v2))) | - (Mult(box VariableReference(v1), box NumberLiteral(n1)), Mult(box NumberLiteral(n2), box VariableReference(v2))) | - (Mult(box NumberLiteral(n1), box VariableReference(v1)), Mult(box VariableReference(v2), box NumberLiteral(n2))) | - (Mult(box VariableReference(v1), box NumberLiteral(n1)), Mult(box VariableReference(v2), box NumberLiteral(n2))) => { - { - let var = count.entry(v1).or_insert(T::zero()); - *var = var.clone() + n1; - } - let var = count.entry(v2).or_insert(T::zero()); - *var = var.clone() + n2; - }, - (e1 @ Add(..), e2 @ Add(..)) => { - { - let vars = count_variables_add(&e1); - for (key, value) in &vars { - let val = count.entry(key.to_string()).or_insert(T::zero()); - *val = val.clone() + value; - } - } - let vars = count_variables_add(&e2); - for (key, value) in &vars { - let val = count.entry(key.to_string()).or_insert(T::zero()); - *val = val.clone() + value; - } - } - e @ _ => panic!("Error: unexpected Add({}, {})", e.0, e.1), - } - }, - e @ _ => panic!("Statement::Add/Mult[linear] expected, got: {}", e), - } - count -} - /// Returns a vector of summands of the given `Expression`. /// /// # Arguments @@ -161,9 +28,7 @@ fn get_summands(expr: &Expression) -> Vec<&Expression> { ref e @ NumberLiteral(_) | ref e @ VariableReference(_) | ref e @ Mult(..) | - ref e @ Sub(..) if e.is_linear() => { - add.push(e); - }, + ref e @ Sub(..) if e.is_linear() => add.push(e), Add(ref l, ref r) => { trace.push(l); trace.push(r); @@ -176,6 +41,43 @@ fn get_summands(expr: &Expression) -> Vec<&Expression> { } } +/// Returns a `HashMap` containing variables and the number of occurences +/// +/// # Arguments +/// +/// * `expr` - Expression only containing Numbers, Variables, Add and Mult +/// +/// # Example +/// +/// `7 * x + 4 * y + x` -> { x => 8, y = 4 } +fn count_variables_add(expr: &Expression) -> HashMap { + let summands = get_summands(expr); + let mut count = HashMap::new(); + for s in summands { + match *s { + NumberLiteral(ref x) => { + let num = count.entry("~one".to_string()).or_insert(T::zero()); + *num = num.clone() + x; + }, + VariableReference(ref v) => { + let num = count.entry(v.to_string()).or_insert(T::zero()); + *num = num.clone() + T::one(); + }, + Mult(box NumberLiteral(ref x1), box NumberLiteral(ref x2)) => { + let num = count.entry("~one".to_string()).or_insert(T::zero()); + *num = num.clone() + x1 + x2; + }, + Mult(box NumberLiteral(ref x), box VariableReference(ref v)) | + Mult(box VariableReference(ref v), box NumberLiteral(ref x)) => { + let num = count.entry(v.to_string()).or_insert(T::zero()); + *num = num.clone() + x; + }, + ref e => panic!("Not covered: {}", e), + } + } + count +} + /// Returns an equotation equivalent to `lhs == rhs` only using `Add` and `Mult` /// /// # Arguments @@ -188,7 +90,7 @@ fn swap_sub(lhs: &Expression, rhs: &Expression) -> (Expression(lhs: &Expression, rhs: &Expression) -> (Expression panic!("Unexpected: {}", e), } } - for mut i in 0..right.len() { + for i in 0..right.len() { match *right[i] { ref e @ NumberLiteral(_) | ref e @ VariableReference(_) | @@ -228,93 +130,6 @@ fn swap_sub(lhs: &Expression, rhs: &Expression) -> (Expression(lhs: &Expression, rhs: &Expression) -> (Expression, Expression) { -// // assert that Mult on lhs or rhs is linear! -// match (lhs.clone(), rhs.clone()) { -// // recursion end -// (v1 @ NumberLiteral(_), v2 @ NumberLiteral(_)) | -// (v1 @ VariableReference(_), v2 @ NumberLiteral(_)) | -// (v1 @ NumberLiteral(_), v2 @ VariableReference(_)) | -// (v1 @ VariableReference(_), v2 @ VariableReference(_)) | -// (v1 @ VariableReference(_), v2 @ Mult(..)) | -// (v1 @ Mult(..), v2 @ VariableReference(_)) | -// (v1 @ NumberLiteral(_), v2 @ Mult(..)) | -// (v1 @ Mult(..), v2 @ NumberLiteral(_)) | -// (v1 @ Mult(..), v2 @ Mult(..)) => { -// assert!(v1.is_linear()); -// assert!(v2.is_linear()); -// (v1, v2) -// }, -// // Num/Var/Mult = Add -// (v @ NumberLiteral(_), Add(left, right)) | -// (v @ VariableReference(_), Add(left, right)) | -// (v @ Mult(..), Add(left, right)) => { -// assert!(v.is_linear()); -// let (l1, r1) = swap_sub(&v, &left); -// let (l2, r2) = swap_sub(&l1, &right); -// (l2, Add(box r1, box r2)) -// }, -// // Add = Num/Var/Mult -// (Add(left, right), v @ NumberLiteral(_)) | -// (Add(left, right), v @ VariableReference(_)) | -// (Add(left, right), v @ Mult(..)) => { // v = left + right -// assert!(v.is_linear()); -// let (l1, r1) = swap_sub(&left, &v); -// let (l2, r2) = swap_sub(&right, &r1); -// (Add(box l1, box l2), r2) -// }, -// // Sub = Var/Num/Mult -// (Sub(box left, box right), v @ VariableReference(_)) | -// (Sub(box left, box right), v @ NumberLiteral(_)) | -// (Sub(box left, box right), v @ Mult(..)) => { -// assert!(v.is_linear()); -// let (l, r) = swap_sub(&left, &right); -// (l, Add(box v, box r)) -// }, -// // Var/Num/Mult = Sub -// (v @ VariableReference(_), Sub(box left, box right)) | -// (v @ NumberLiteral(_), Sub(box left, box right)) | -// (v @ Mult(..), Sub(box left, box right)) => { -// assert!(v.is_linear()); -// let (l, r) = swap_sub(&left, &right); -// (Add(box v, box r), l) -// }, -// // Add = Add -// (Add(box left1, box right1), Add(box left2, box right2)) => { -// let (l1, r1) = swap_sub(&left1, &left2); -// let (l2, r2) = swap_sub(&right1, &right2); -// (Add(box l1, box l2), Add(box r1, box r2)) -// }, -// // Sub = Add -// (Sub(box left_s, box right_s), Add(box left_a, box right_a)) => { -// let (l1, r1) = swap_sub(&left_s, &right_s); -// let (l2, r2) = swap_sub(&l1, &left_a); -// let (l3, r3) = swap_sub(&l2, &right_a); -// (l3, Add(box r1, box Add(box r2, box r3))) -// }, -// // Add = Sub -// (Add(box left_a, box right_a), Sub(box left_s, box right_s)) => { -// let (l1, r1) = swap_sub(&left_s, &right_s); -// let (l2, r2) = swap_sub(&l1, &left_a); -// let (l3, r3) = swap_sub(&l2, &right_a); -// (Add(box r1, box Add(box r2, box r3)), l3) -// }, -// // Sub = Sub -// (Sub(box l1, box r1), Sub(l2, r2)) => { -// let (lhs1, rhs1) = swap_sub(&l1, &r1); -// let (lhs2, rhs2) = swap_sub(&l2, &r2); -// (Add(box lhs1, box rhs2), Add(box lhs2, box rhs1)) -// }, -// e @ _ => panic!("Input not covered: {} = {}", e.0, e.1), -// } -// } - /// Calculates one R1CS row representation for `linear_expr` = `expr`. /// (* = ) /// @@ -647,3 +462,225 @@ mod tests { } } } + +// old recursive implementations + +// /// Returns a `HashMap` containing variables and the number of occurences +// /// +// /// # Arguments +// /// +// /// * `expr` - Expression only containing Numbers, Variables, Add and Mult +// /// +// /// # Example +// /// +// /// `7 * x + 4 * y + x` -> { x => 8, y = 4 } +// fn count_variables_add(expr: &Expression) -> HashMap { +// let mut count = HashMap::new(); +// match expr.clone() { +// NumberLiteral(x) => { count.insert("~one".to_string(), x); }, +// VariableReference(var) => { count.insert(var, T::one()); }, +// Mult(box NumberLiteral(x1), box NumberLiteral(x2)) => { count.insert("~one".to_string(), x1 * x2); }, +// Mult(box NumberLiteral(x), box VariableReference(var)) | +// Mult(box VariableReference(var), box NumberLiteral(x)) => { count.insert(var, x); }, +// Add(box lhs, box rhs) => { +// match (lhs, rhs) { +// (NumberLiteral(x), NumberLiteral(y)) => { +// let num = count.entry("~one".to_string()).or_insert(T::zero()); +// *num = num.clone() + x + y; +// }, +// (VariableReference(v), NumberLiteral(x)) | +// (NumberLiteral(x), VariableReference(v)) => { +// { +// let num = count.entry("~one".to_string()).or_insert(T::zero()); +// *num = num.clone() + x; +// } +// let var = count.entry(v).or_insert(T::zero()); +// *var = var.clone() + T::one(); +// }, +// (VariableReference(v1), VariableReference(v2)) => { +// { +// let var1 = count.entry(v1).or_insert(T::zero()); +// *var1 = var1.clone() + T::one(); +// } +// let var2 = count.entry(v2).or_insert(T::zero()); +// *var2 = var2.clone() + T::one(); +// }, +// (NumberLiteral(x), e @ Add(..)) | +// (e @ Add(..), NumberLiteral(x)) => { +// { +// let num = count.entry("~one".to_string()).or_insert(T::zero()); +// *num = num.clone() + x; +// } +// let vars = count_variables_add(&e); +// for (key, value) in &vars { +// let val = count.entry(key.to_string()).or_insert(T::zero()); +// *val = val.clone() + value; +// } +// }, +// (VariableReference(v), e @ Add(..)) | +// (e @ Add(..), VariableReference(v)) => { +// { +// let var = count.entry(v).or_insert(T::zero()); +// *var = var.clone() + T::one(); +// } +// let vars = count_variables_add(&e); +// for (key, value) in &vars { +// let val = count.entry(key.to_string()).or_insert(T::zero()); +// *val = val.clone() + value; +// } +// }, +// (NumberLiteral(x), Mult(box NumberLiteral(n), box VariableReference(v))) | +// (NumberLiteral(x), Mult(box VariableReference(v), box NumberLiteral(n))) | +// (Mult(box NumberLiteral(n), box VariableReference(v)), NumberLiteral(x)) | +// (Mult(box VariableReference(v), box NumberLiteral(n)), NumberLiteral(x)) => { +// { +// let num = count.entry("~one".to_string()).or_insert(T::zero()); +// *num = num.clone() + x; +// } +// let var = count.entry(v).or_insert(T::zero()); +// *var = var.clone() + n; +// }, +// (VariableReference(v1), Mult(box NumberLiteral(n), box VariableReference(v2))) | +// (VariableReference(v1), Mult(box VariableReference(v2), box NumberLiteral(n))) | +// (Mult(box NumberLiteral(n), box VariableReference(v2)), VariableReference(v1)) | +// (Mult(box VariableReference(v2), box NumberLiteral(n)), VariableReference(v1)) => { +// { +// let var = count.entry(v1).or_insert(T::zero()); +// *var = var.clone() + T::one(); +// } +// let var = count.entry(v2).or_insert(T::zero()); +// *var = var.clone() + n; +// }, +// (e @ Add(..), Mult(box NumberLiteral(n), box VariableReference(v))) | +// (e @ Add(..), Mult(box VariableReference(v), box NumberLiteral(n))) | +// (Mult(box NumberLiteral(n), box VariableReference(v)), e @ Add(..)) | +// (Mult(box VariableReference(v), box NumberLiteral(n)), e @ Add(..)) => { +// { +// let var = count.entry(v).or_insert(T::zero()); +// *var = var.clone() + n; +// } +// let vars = count_variables_add(&e); +// for (key, value) in &vars { +// let val = count.entry(key.to_string()).or_insert(T::zero()); +// *val = val.clone() + value; +// } +// }, +// (Mult(box NumberLiteral(n1), box VariableReference(v1)), Mult(box NumberLiteral(n2), box VariableReference(v2))) | +// (Mult(box VariableReference(v1), box NumberLiteral(n1)), Mult(box NumberLiteral(n2), box VariableReference(v2))) | +// (Mult(box NumberLiteral(n1), box VariableReference(v1)), Mult(box VariableReference(v2), box NumberLiteral(n2))) | +// (Mult(box VariableReference(v1), box NumberLiteral(n1)), Mult(box VariableReference(v2), box NumberLiteral(n2))) => { +// { +// let var = count.entry(v1).or_insert(T::zero()); +// *var = var.clone() + n1; +// } +// let var = count.entry(v2).or_insert(T::zero()); +// *var = var.clone() + n2; +// }, +// (e1 @ Add(..), e2 @ Add(..)) => { +// { +// let vars = count_variables_add(&e1); +// for (key, value) in &vars { +// let val = count.entry(key.to_string()).or_insert(T::zero()); +// *val = val.clone() + value; +// } +// } +// let vars = count_variables_add(&e2); +// for (key, value) in &vars { +// let val = count.entry(key.to_string()).or_insert(T::zero()); +// *val = val.clone() + value; +// } +// } +// e @ _ => panic!("Error: unexpected Add({}, {})", e.0, e.1), +// } +// }, +// e @ _ => panic!("Statement::Add/Mult[linear] expected, got: {}", e), +// } +// count +// } + +// /// Returns an equotation equivalent to `lhs == rhs` only using `Add` and `Mult` +// /// +// /// # Arguments +// /// +// /// * `lhs` - Leht hand side of the equotation +// /// * `rhs` - Right hand side of the equotation +// fn swap_sub_recursive(lhs: &Expression, rhs: &Expression) -> (Expression, Expression) { +// // assert that Mult on lhs or rhs is linear! +// match (lhs.clone(), rhs.clone()) { +// // recursion end +// (v1 @ NumberLiteral(_), v2 @ NumberLiteral(_)) | +// (v1 @ VariableReference(_), v2 @ NumberLiteral(_)) | +// (v1 @ NumberLiteral(_), v2 @ VariableReference(_)) | +// (v1 @ VariableReference(_), v2 @ VariableReference(_)) | +// (v1 @ VariableReference(_), v2 @ Mult(..)) | +// (v1 @ Mult(..), v2 @ VariableReference(_)) | +// (v1 @ NumberLiteral(_), v2 @ Mult(..)) | +// (v1 @ Mult(..), v2 @ NumberLiteral(_)) | +// (v1 @ Mult(..), v2 @ Mult(..)) => { +// assert!(v1.is_linear()); +// assert!(v2.is_linear()); +// (v1, v2) +// }, +// // Num/Var/Mult = Add +// (v @ NumberLiteral(_), Add(left, right)) | +// (v @ VariableReference(_), Add(left, right)) | +// (v @ Mult(..), Add(left, right)) => { +// assert!(v.is_linear()); +// let (l1, r1) = swap_sub(&v, &left); +// let (l2, r2) = swap_sub(&l1, &right); +// (l2, Add(box r1, box r2)) +// }, +// // Add = Num/Var/Mult +// (Add(left, right), v @ NumberLiteral(_)) | +// (Add(left, right), v @ VariableReference(_)) | +// (Add(left, right), v @ Mult(..)) => { // v = left + right +// assert!(v.is_linear()); +// let (l1, r1) = swap_sub(&left, &v); +// let (l2, r2) = swap_sub(&right, &r1); +// (Add(box l1, box l2), r2) +// }, +// // Sub = Var/Num/Mult +// (Sub(box left, box right), v @ VariableReference(_)) | +// (Sub(box left, box right), v @ NumberLiteral(_)) | +// (Sub(box left, box right), v @ Mult(..)) => { +// assert!(v.is_linear()); +// let (l, r) = swap_sub(&left, &right); +// (l, Add(box v, box r)) +// }, +// // Var/Num/Mult = Sub +// (v @ VariableReference(_), Sub(box left, box right)) | +// (v @ NumberLiteral(_), Sub(box left, box right)) | +// (v @ Mult(..), Sub(box left, box right)) => { +// assert!(v.is_linear()); +// let (l, r) = swap_sub(&left, &right); +// (Add(box v, box r), l) +// }, +// // Add = Add +// (Add(box left1, box right1), Add(box left2, box right2)) => { +// let (l1, r1) = swap_sub(&left1, &left2); +// let (l2, r2) = swap_sub(&right1, &right2); +// (Add(box l1, box l2), Add(box r1, box r2)) +// }, +// // Sub = Add +// (Sub(box left_s, box right_s), Add(box left_a, box right_a)) => { +// let (l1, r1) = swap_sub(&left_s, &right_s); +// let (l2, r2) = swap_sub(&l1, &left_a); +// let (l3, r3) = swap_sub(&l2, &right_a); +// (l3, Add(box r1, box Add(box r2, box r3))) +// }, +// // Add = Sub +// (Add(box left_a, box right_a), Sub(box left_s, box right_s)) => { +// let (l1, r1) = swap_sub(&left_s, &right_s); +// let (l2, r2) = swap_sub(&l1, &left_a); +// let (l3, r3) = swap_sub(&l2, &right_a); +// (Add(box r1, box Add(box r2, box r3)), l3) +// }, +// // Sub = Sub +// (Sub(box l1, box r1), Sub(l2, r2)) => { +// let (lhs1, rhs1) = swap_sub(&l1, &r1); +// let (lhs2, rhs2) = swap_sub(&l2, &r2); +// (Add(box lhs1, box rhs2), Add(box lhs2, box rhs1)) +// }, +// e @ _ => panic!("Input not covered: {} = {}", e.0, e.1), +// } +// }