1
0
Fork 0
mirror of synced 2025-09-23 12:18:44 +00:00

Add iterative version of count_variables_add

This commit is contained in:
Dennis Kuhnert 2017-02-26 12:17:55 +01:00
parent 019d8104ca
commit 7080e382e1

View file

@ -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<T: Field>(expr: &Expression<T>) -> HashMap<String, T> {
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<T: Field>(expr: &Expression<T>) -> Vec<&Expression<T>> {
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<T: Field>(expr: &Expression<T>) -> Vec<&Expression<T>> {
}
}
/// 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<T: Field>(expr: &Expression<T>) -> HashMap<String, T> {
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<T: Field>(lhs: &Expression<T>, rhs: &Expression<T>) -> (Expression<T
let mut run = true;
while run {
run = false;
for mut i in 0..left.len() {
for i in 0..left.len() {
match *left[i] {
ref e @ NumberLiteral(_) |
ref e @ VariableReference(_) |
@ -202,7 +104,7 @@ fn swap_sub<T: Field>(lhs: &Expression<T>, rhs: &Expression<T>) -> (Expression<T
ref e => 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<T: Field>(lhs: &Expression<T>, rhs: &Expression<T>) -> (Expression<T
panic!("Unexpected");
}
/// 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<T: Field>(lhs: &Expression<T>, rhs: &Expression<T>) -> (Expression<T>, Expression<T>) {
// // 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`.
/// (<A,x>*<B,c> = <C,x>)
///
@ -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<T: Field>(expr: &Expression<T>) -> HashMap<String, T> {
// 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<T: Field>(lhs: &Expression<T>, rhs: &Expression<T>) -> (Expression<T>, Expression<T>) {
// // 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),
// }
// }