1
0
Fork 0
mirror of synced 2025-09-24 04:40:05 +00:00

Add Sub to R1CS; Add Dockerfile

Change CURVE to ALT_BN128
Remove 'Expression::' with import
This commit is contained in:
Dennis Kuhnert 2017-02-01 17:24:44 +01:00
parent 6bcf021124
commit f31e109413
10 changed files with 175 additions and 141 deletions

1
.dockerignore Normal file
View file

@ -0,0 +1 @@
target

30
Dockerfile Normal file
View file

@ -0,0 +1,30 @@
FROM ubuntu:14.04
MAINTAINER Dennis Kuhnert <dennis.kuhnert@campus.tu-berlin.de>
WORKDIR /root
RUN apt-get update && \
apt-get install -y \
wget unzip curl \
build-essential git libgmp3-dev libprocps3-dev libgtest-dev python-markdown libboost-all-dev libssl-dev
RUN wget https://github.com/scipr-lab/libsnark/archive/master.zip \
&& mv master.zip libsnark.zip \
&& unzip libsnark.zip \
&& cd libsnark-master \
&& ./prepare-depends.sh
RUN curl https://sh.rustup.rs -sSf | \
sh -s -- --default-toolchain nightly -y
ENV PATH=/root/.cargo/bin:$PATH
RUN cd libsnark-master \
&& make install lib PREFIX=/usr/local \
NO_PROCPS=1 NO_GTEST=1 NO_DOCS=1 CURVE=ALT_BN128 FEATUREFLAGS="-DBINARY_OUTPUT=1 -DMONTGOMERY_OUTPUT=1 -DNO_PT_COMPRESSION=1"
COPY . /root/VerifiableStatementCompiler
RUN cd VerifiableStatementCompiler \
&& cargo build

View file

@ -2,4 +2,4 @@
libsnark has to be installed to: `lib/libsnark`
set `LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/lib/libsnark/lib`
`export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib`

View file

@ -1,14 +1,13 @@
extern crate gcc;
fn main() {
println!("cargo:rustc-link-search=lib/libsnark/lib");
println!("cargo:rustc-link-search=/usr/local/lib");
gcc::Config::new()
.cpp(true)
.include("lib/libsnark/include")
.include("lib/libsnark/include/libsnark")
.include("/usr/local/include")
.include("/usr/local/include/libsnark")
.flag("-std=c++11")
// .define("CURVE", Some("ALT_BN128"))
.define("CURVE_BN128", None)
.define("CURVE_ALT_BN128", None)
.file("lib/wraplibsnark.cpp")
.compile("libwraplibsnark.a");
}

View file

@ -3,10 +3,8 @@
// comment
def qeval(x):
// comment in function
// comment
y = x**3
//b = x**5
//z = x + 3 - y + 7
//a = z * y + 3 * y
b = x**5
return y + x + y
// comment after function
// comment

View file

@ -1,6 +1,7 @@
// only using sub, no need to flatten
def qeval(a):
b = a - 5
b = a + 100
c = b + a + b
d = b - a - 3 - a
return d + c
e = d + 3 - a
return d + c + e

View file

@ -15,20 +15,20 @@ bool _run_libsnark(const int* A, const int* B, const int* C, const int* witness,
cout << endl << "run_libsnark" << endl;
for (int row = 0; row < constraints; row++) {
cout << "row " << row << endl;
// cout << "row " << row << endl;
linear_combination<Fr<default_r1cs_ppzksnark_pp> > lin_comb_A, lin_comb_B, lin_comb_C;
for (int idx = 0; idx < variables; idx++) {
// using (constraints + 2) because of the representation of Rust's Vec<_>
if (A[row * (constraints + 2) + idx] != 0) {
cout << "A(" << idx << ", " << A[row * (constraints + 2) + idx] << ")" << endl;
// cout << "A(" << idx << ", " << A[row * (constraints + 2) + idx] << ")" << endl;
lin_comb_A.add_term(idx, A[row * (constraints + 2) + idx]);
}
if (B[row * (constraints + 2) + idx] != 0) {
cout << "B(" << idx << ", " << B[row * (constraints + 2) + idx] << ")" << endl;
// cout << "B(" << idx << ", " << B[row * (constraints + 2) + idx] << ")" << endl;
lin_comb_B.add_term(idx, B[row * (constraints + 2) + idx]);
}
if (C[row * (constraints + 2) + idx] != 0) {
cout << "C(" << idx << ", " << C[row * (constraints + 2) + idx] << ")" << endl;
// cout << "C(" << idx << ", " << C[row * (constraints + 2) + idx] << ")" << endl;
lin_comb_C.add_term(idx, C[row * (constraints + 2) + idx]);
}
}

View file

@ -120,10 +120,10 @@ impl fmt::Display for Expression {
match *self {
Expression::NumberLiteral(ref i) => write!(f, "{}", i),
Expression::VariableReference(ref var) => write!(f, "{}", var),
Expression::Add(ref lhs, ref rhs) => write!(f, "{} + {}", lhs, rhs),
Expression::Sub(ref lhs, ref rhs) => write!(f, "{} - {}", lhs, rhs),
Expression::Mult(ref lhs, ref rhs) => write!(f, "{} * {}", lhs, rhs),
Expression::Div(ref lhs, ref rhs) => write!(f, "{} / {}", lhs, rhs),
Expression::Add(ref lhs, ref rhs) => write!(f, "({} + {})", lhs, rhs),
Expression::Sub(ref lhs, ref rhs) => write!(f, "({} - {})", lhs, rhs),
Expression::Mult(ref lhs, ref rhs) => write!(f, "({} * {})", lhs, rhs),
Expression::Div(ref lhs, ref rhs) => write!(f, "({} / {})", lhs, rhs),
Expression::Pow(ref lhs, ref rhs) => write!(f, "{}**{}", lhs, rhs),
Expression::IfElse(ref condition, ref consequent, ref alternative) => write!(f, "{} ? {} : {}", condition, consequent, alternative),
}

View file

@ -5,6 +5,7 @@ use std::io::prelude::*;
use std::fs::File;
use self::regex::Regex;
use ast::*;
use ast::Expression::*;
fn parse_expression_rhs(text: String) -> Expression {
let op_regex = Regex::new(r"^((?P<lhs>[[:alnum:]]+)(?P<op>(\*\*|[\+\-\*/]))(?P<rhs>.+)|(?P<var>[[:alpha:]][[:alnum:]]*)|(?P<num>\d+))$").unwrap();
@ -15,30 +16,30 @@ fn parse_expression_rhs(text: String) -> Expression {
match op_regex.captures(&line) {
Some(x) => {
if let Some(var) = x.name("var") {
Expression::VariableReference(var.as_str().to_string())
VariableReference(var.as_str().to_string())
} else if let Some(num) = x.name("num") {
Expression::NumberLiteral(num.as_str().parse::<i32>().unwrap())
NumberLiteral(num.as_str().parse::<i32>().unwrap())
} else {
let lhs = if variable_regex.is_match(&x["lhs"]) {
Box::new(Expression::VariableReference(x["lhs"].to_string()))
box VariableReference(x["lhs"].to_string())
} else if number_regex.is_match(&x["lhs"]) {
Box::new(Expression::NumberLiteral(x["lhs"].parse::<i32>().unwrap()))
box NumberLiteral(x["lhs"].parse::<i32>().unwrap())
} else {
panic!("Could not read lhs: {:?}", &x["lhs"])
};
let rhs = if variable_regex.is_match(&x["rhs"]) {
Box::new(Expression::VariableReference(x["rhs"].to_string()))
box VariableReference(x["rhs"].to_string())
} else if number_regex.is_match(&x["rhs"]) {
Box::new(Expression::NumberLiteral(x["rhs"].parse::<i32>().unwrap()))
Box::new(NumberLiteral(x["rhs"].parse::<i32>().unwrap()))
} else {
Box::new(parse_expression_rhs(x["rhs"].to_string()))
box parse_expression_rhs(x["rhs"].to_string())
};
match &x["op"] {
"+" => Expression::Add(lhs, rhs),
"-" => Expression::Sub(lhs, rhs),
"*" => Expression::Mult(lhs, rhs),
"/" => Expression::Div(lhs, rhs),
"**" if number_regex.is_match(&x["rhs"]) => Expression::Pow(lhs, rhs),
"+" => Add(lhs, rhs),
"-" => Sub(lhs, rhs),
"*" => Mult(lhs, rhs),
"/" => Div(lhs, rhs),
"**" if number_regex.is_match(&x["rhs"]) => Pow(lhs, rhs),
_ => unimplemented!(),
}
}
@ -50,7 +51,7 @@ fn parse_expression_rhs(text: String) -> Expression {
"<" => Condition::Lt(parse_expression_rhs(x["condlhs"].to_string()), parse_expression_rhs(x["condrhs"].to_string())),
_ => unimplemented!(),
};
Expression::IfElse(box condition, box parse_expression_rhs(x["consequent"].to_string()), box parse_expression_rhs(x["alternative"].to_string()))
IfElse(box condition, box parse_expression_rhs(x["consequent"].to_string()), box parse_expression_rhs(x["alternative"].to_string()))
},
None => panic!("Could not parse rhs of expression: {:?}", text),
},
@ -119,13 +120,13 @@ pub fn parse_program(file: File) -> Prog {
fn flatten_expression(defs_flattened: &mut Vec<Definition>, num_variables: &mut i32, expr: Expression) -> Expression {
match expr {
x @ Expression::NumberLiteral(_) |
x @ Expression::VariableReference(_) => x,
ref x @ Expression::Add(..) |
ref x @ Expression::Sub(..) |
ref x @ Expression::Mult(..) |
ref x @ Expression::Div(..) if x.is_flattened() => x.clone(),
Expression::Add(box left, box right) => {
x @ NumberLiteral(_) |
x @ VariableReference(_) => x,
ref x @ Add(..) |
ref x @ Sub(..) |
ref x @ Mult(..) |
ref x @ Div(..) if x.is_flattened() => x.clone(),
Add(box left, box right) => {
let left_flattened = flatten_expression(defs_flattened, num_variables, left);
let right_flattened = flatten_expression(defs_flattened, num_variables, right);
let new_left = if left_flattened.is_linear() {
@ -134,7 +135,7 @@ fn flatten_expression(defs_flattened: &mut Vec<Definition>, num_variables: &mut
let new_name = format!("sym_{}", num_variables);
*num_variables += 1;
defs_flattened.push(Definition::Definition(new_name.to_string(), left_flattened));
Expression::VariableReference(new_name)
VariableReference(new_name)
};
let new_right = if right_flattened.is_linear() {
right_flattened
@ -142,11 +143,11 @@ fn flatten_expression(defs_flattened: &mut Vec<Definition>, num_variables: &mut
let new_name = format!("sym_{}", num_variables);
*num_variables += 1;
defs_flattened.push(Definition::Definition(new_name.to_string(), right_flattened));
Expression::VariableReference(new_name)
VariableReference(new_name)
};
Expression::Add(box new_left, box new_right)
Add(box new_left, box new_right)
},
Expression::Sub(box left, box right) => {
Sub(box left, box right) => {
let left_flattened = flatten_expression(defs_flattened, num_variables, left);
let right_flattened = flatten_expression(defs_flattened, num_variables, right);
let new_left = if left_flattened.is_linear() {
@ -155,7 +156,7 @@ fn flatten_expression(defs_flattened: &mut Vec<Definition>, num_variables: &mut
let new_name = format!("sym_{}", num_variables);
*num_variables += 1;
defs_flattened.push(Definition::Definition(new_name.to_string(), left_flattened));
Expression::VariableReference(new_name)
VariableReference(new_name)
};
let new_right = if right_flattened.is_linear() {
right_flattened
@ -163,11 +164,11 @@ fn flatten_expression(defs_flattened: &mut Vec<Definition>, num_variables: &mut
let new_name = format!("sym_{}", num_variables);
*num_variables += 1;
defs_flattened.push(Definition::Definition(new_name.to_string(), right_flattened));
Expression::VariableReference(new_name)
VariableReference(new_name)
};
Expression::Sub(box new_left, box new_right)
Sub(box new_left, box new_right)
},
Expression::Mult(box left, box right) => {
Mult(box left, box right) => {
let left_flattened = flatten_expression(defs_flattened, num_variables, left);
let right_flattened = flatten_expression(defs_flattened, num_variables, right);
let new_left = if left_flattened.is_linear() {
@ -176,7 +177,7 @@ fn flatten_expression(defs_flattened: &mut Vec<Definition>, num_variables: &mut
let new_name = format!("sym_{}", num_variables);
*num_variables += 1;
defs_flattened.push(Definition::Definition(new_name.to_string(), left_flattened));
Expression::VariableReference(new_name)
VariableReference(new_name)
};
let new_right = if right_flattened.is_linear() {
right_flattened
@ -184,11 +185,11 @@ fn flatten_expression(defs_flattened: &mut Vec<Definition>, num_variables: &mut
let new_name = format!("sym_{}", num_variables);
*num_variables += 1;
defs_flattened.push(Definition::Definition(new_name.to_string(), right_flattened));
Expression::VariableReference(new_name)
VariableReference(new_name)
};
Expression::Mult(box new_left, box new_right)
Mult(box new_left, box new_right)
},
Expression::Div(box left, box right) => {
Div(box left, box right) => {
let left_flattened = flatten_expression(defs_flattened, num_variables, left);
let right_flattened = flatten_expression(defs_flattened, num_variables, right);
let new_left = if left_flattened.is_linear() {
@ -197,7 +198,7 @@ fn flatten_expression(defs_flattened: &mut Vec<Definition>, num_variables: &mut
let new_name = format!("sym_{}", num_variables);
*num_variables += 1;
defs_flattened.push(Definition::Definition(new_name.to_string(), left_flattened));
Expression::VariableReference(new_name)
VariableReference(new_name)
};
let new_right = if right_flattened.is_linear() {
right_flattened
@ -205,23 +206,23 @@ fn flatten_expression(defs_flattened: &mut Vec<Definition>, num_variables: &mut
let new_name = format!("sym_{}", num_variables);
*num_variables += 1;
defs_flattened.push(Definition::Definition(new_name.to_string(), right_flattened));
Expression::VariableReference(new_name)
VariableReference(new_name)
};
Expression::Div(box new_left, box new_right)
Div(box new_left, box new_right)
},
Expression::Pow(base, exponent) => {
Pow(base, exponent) => {
// TODO currently assuming that base is number or variable
match exponent {
box Expression::NumberLiteral(x) if x > 1 => {
box NumberLiteral(x) if x > 1 => {
match base {
box Expression::VariableReference(ref var) => {
box VariableReference(ref var) => {
let id = if x > 2 {
let tmp_expression = flatten_expression(
defs_flattened,
num_variables,
Expression::Pow(
box Expression::VariableReference(var.to_string()),
box Expression::NumberLiteral(x - 1)
Pow(
box VariableReference(var.to_string()),
box NumberLiteral(x - 1)
)
);
let new_name = format!("sym_{}", num_variables);
@ -231,14 +232,14 @@ fn flatten_expression(defs_flattened: &mut Vec<Definition>, num_variables: &mut
} else {
var.to_string()
};
Expression::Mult(
box Expression::VariableReference(id.to_string()),
box Expression::VariableReference(var.to_string())
Mult(
box VariableReference(id.to_string()),
box VariableReference(var.to_string())
)
},
box Expression::NumberLiteral(var) => Expression::Mult(
box Expression::NumberLiteral(var),
box Expression::NumberLiteral(var)
box NumberLiteral(var) => Mult(
box NumberLiteral(var),
box NumberLiteral(var)
),
_ => panic!("Only variables and numbers allowed in pow base")
}
@ -246,17 +247,17 @@ fn flatten_expression(defs_flattened: &mut Vec<Definition>, num_variables: &mut
_ => panic!("Expected number > 1 as pow exponent"),
}
},
Expression::IfElse(box condition, consequent, alternative) => {
IfElse(box condition, consequent, alternative) => {
let condition_true = flatten_condition(defs_flattened, num_variables, condition);
// condition_false = 1 - condition_true
// (condition_true * consequent) + (condition_false * alternatuve)
flatten_expression(
defs_flattened,
num_variables,
Expression::Add(
box Expression::Mult(box condition_true.clone(), consequent),
box Expression::Mult(
box Expression::Sub(box Expression::NumberLiteral(1), box condition_true),
Add(
box Mult(box condition_true.clone(), consequent),
box Mult(
box Sub(box NumberLiteral(1), box condition_true),
alternative
)
)
@ -282,9 +283,9 @@ fn flatten_condition(defs_flattened: &mut Vec<Definition>, num_variables: &mut i
*num_variables += 1;
defs_flattened.push(Definition::Definition(
cond_result.to_string(),
Expression::Sub(
box Expression::VariableReference(lhs_name.to_string()),
box Expression::VariableReference(rhs_name.to_string())
Sub(
box VariableReference(lhs_name.to_string()),
box VariableReference(rhs_name.to_string())
)
));
let bits = 8;
@ -292,18 +293,18 @@ fn flatten_condition(defs_flattened: &mut Vec<Definition>, num_variables: &mut i
let new_name = format!("{}_b{}", &cond_result, i);
defs_flattened.push(Definition::Definition(
new_name.to_string(),
Expression::Mult(
box Expression::VariableReference(new_name.to_string()),
box Expression::VariableReference(new_name.to_string())
Mult(
box VariableReference(new_name.to_string()),
box VariableReference(new_name.to_string())
)
));
}
let mut expr = Expression::VariableReference(format!("{}_b0", &cond_result)); // * 2^0
let mut expr = VariableReference(format!("{}_b0", &cond_result)); // * 2^0
for i in 1..bits {
expr = Expression::Add(
box Expression::Mult(
box Expression::VariableReference(format!("{}_b{}", &cond_result, i)),
box Expression::NumberLiteral(2i32.pow(i))
expr = Add(
box Mult(
box VariableReference(format!("{}_b{}", &cond_result, i)),
box NumberLiteral(2i32.pow(i))
),
box expr
);
@ -311,7 +312,7 @@ fn flatten_condition(defs_flattened: &mut Vec<Definition>, num_variables: &mut i
defs_flattened.push(Definition::Definition(cond_result.to_string(), expr));
let cond_true = format!("{}_b{}", &cond_result, bits - 1);
Expression::VariableReference(cond_true)
VariableReference(cond_true)
}
}
}

View file

@ -1,17 +1,20 @@
use ast::*;
use ast::Expression::*;
use std::collections::HashMap;
fn count_variables_add(expr: Expression) -> HashMap<String, i32> {
let mut count = HashMap::new();
match expr {
Expression::Add(box lhs, box rhs) => {
NumberLiteral(x) => { count.insert("~one".to_string(), x); },
VariableReference(var) => { count.insert(var, 1); },
Add(box lhs, box rhs) => {
match (lhs, rhs) {
(Expression::NumberLiteral(x), Expression::NumberLiteral(y)) => {
(NumberLiteral(x), NumberLiteral(y)) => {
let num = count.entry("~one".to_string()).or_insert(0);
*num += x + y;
},
(Expression::VariableReference(v), Expression::NumberLiteral(x)) |
(Expression::NumberLiteral(x), Expression::VariableReference(v)) => {
(VariableReference(v), NumberLiteral(x)) |
(NumberLiteral(x), VariableReference(v)) => {
{
let num = count.entry("~one".to_string()).or_insert(0);
*num += x;
@ -19,7 +22,7 @@ fn count_variables_add(expr: Expression) -> HashMap<String, i32> {
let var = count.entry(v).or_insert(0);
*var += 1;
},
(Expression::VariableReference(v1), Expression::VariableReference(v2)) => {
(VariableReference(v1), VariableReference(v2)) => {
{
let var1 = count.entry(v1).or_insert(0);
*var1 += 1;
@ -27,8 +30,8 @@ fn count_variables_add(expr: Expression) -> HashMap<String, i32> {
let var2 = count.entry(v2).or_insert(0);
*var2 += 1;
},
(Expression::NumberLiteral(x), e @ Expression::Add(..)) |
(e @ Expression::Add(..), Expression::NumberLiteral(x)) => {
(NumberLiteral(x), e @ Add(..)) |
(e @ Add(..), NumberLiteral(x)) => {
{
let num = count.entry("~one".to_string()).or_insert(0);
*num += x;
@ -39,8 +42,8 @@ fn count_variables_add(expr: Expression) -> HashMap<String, i32> {
*val += *value;
}
},
(Expression::VariableReference(v), e @ Expression::Add(..)) |
(e @ Expression::Add(..), Expression::VariableReference(v)) => {
(VariableReference(v), e @ Add(..)) |
(e @ Add(..), VariableReference(v)) => {
{
let var = count.entry(v).or_insert(0);
*var += 1;
@ -51,10 +54,10 @@ fn count_variables_add(expr: Expression) -> HashMap<String, i32> {
*val += *value;
}
},
(Expression::NumberLiteral(x), Expression::Mult(box Expression::NumberLiteral(n), box Expression::VariableReference(v))) |
(Expression::NumberLiteral(x), Expression::Mult(box Expression::VariableReference(v), box Expression::NumberLiteral(n))) |
(Expression::Mult(box Expression::NumberLiteral(n), box Expression::VariableReference(v)), Expression::NumberLiteral(x)) |
(Expression::Mult(box Expression::VariableReference(v), box Expression::NumberLiteral(n)), Expression::NumberLiteral(x)) => {
(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(0);
*num += x;
@ -70,78 +73,79 @@ fn count_variables_add(expr: Expression) -> HashMap<String, i32> {
count
}
// lhs = rhy
fn swap_sub(lhs: &Expression, rhs: &Expression) -> (Expression, Expression) {
match (lhs.clone(), rhs.clone()) {
// TODO need all cases? need more?
(v1 @ NumberLiteral(_), v2 @ NumberLiteral(_)) |
(v1 @ VariableReference(_), v2 @ NumberLiteral(_)) |
(v1 @ NumberLiteral(_), v2 @ VariableReference(_)) |
(v1 @ VariableReference(_), v2 @ VariableReference(_)) => (v1, v2),
(var @ VariableReference(_), Add(left, box right)) => {
let (l, r) = swap_sub(&var, &right);
(l, Add(left, box r))
},
(var @ VariableReference(_), Sub(box left, box right)) => {
let (l, r) = swap_sub(&left, &right);
(Add(box var, box r), l)
}
e @ _ => panic!("Unexpected input: {} = {}", e.0, e.1),
}
}
pub fn r1cs_expression(idx: usize, expr: Expression, variables: &mut Vec<String>, a_row: &mut Vec<(usize, i32)>, b_row: &mut Vec<(usize, i32)>, c_row: &mut Vec<(usize, i32)>) {
match expr {
e @ Expression::Add(..) => {
for (key, value) in count_variables_add(e) {
e @ Add(..) |
e @ Sub(..) => { // a - b = c --> b + c = a
let (lhs, rhs) = swap_sub(&VariableReference(variables[idx].to_string()), &e);
for (key, value) in count_variables_add(rhs) {
a_row.push((variables.iter().position(|r| r == &key).unwrap(), value));
}
b_row.push((0, 1));
c_row.push((idx, 1));
},
Expression::Sub(lhs, rhs) => { // a - b = c --> b + c = a
for (key, value) in count_variables_add(Expression::Add(rhs, box Expression::VariableReference(variables[idx].to_string()))) {
a_row.push((variables.iter().position(|r| r == &key).unwrap(), value));
for (key, value) in count_variables_add(lhs) {
c_row.push((variables.iter().position(|r| r == &key).unwrap(), value));
}
b_row.push((0, 1));
match lhs {
box Expression::NumberLiteral(x) => c_row.push((0, x)),
box Expression::VariableReference(x) => c_row.push((variables.iter().position(|r| r == &x).unwrap(), 1)),
e @ _ => panic!("unimplemented: {}", e),
};
// a_row.push((idx, 1));
// match lhs {
// box Expression::NumberLiteral(x) => c_row.push((0, x)),
// box Expression::VariableReference(x) => c_row.push((variables.iter().position(|r| r == &x).unwrap(), 1)),
// _ => panic!("Not flattened!"),
// };
// match rhs {
// box Expression::NumberLiteral(x) => b_row.push((0, x)),
// box Expression::VariableReference(x) => b_row.push((variables.iter().position(|r| r == &x).unwrap(), 1)),
// _ => panic!("Not flattened!"),
// };
},
Expression::Mult(lhs, rhs) => {
Mult(lhs, rhs) => {
c_row.push((idx, 1));
match lhs {
box Expression::NumberLiteral(x) => a_row.push((0, x)),
box Expression::VariableReference(x) => a_row.push((variables.iter().position(|r| r == &x).unwrap(), 1)),
box e @ Expression::Add(..) => for (key, value) in count_variables_add(e) {
box NumberLiteral(x) => a_row.push((0, x)),
box VariableReference(x) => a_row.push((variables.iter().position(|r| r == &x).unwrap(), 1)),
box e @ Add(..) => for (key, value) in count_variables_add(e) {
a_row.push((variables.iter().position(|r| r == &key).unwrap(), value));
},
e @ _ => panic!("Not flattened: {}", e),
};
match rhs {
box Expression::NumberLiteral(x) => b_row.push((0, x)),
box Expression::VariableReference(x) => b_row.push((variables.iter().position(|r| r == &x).unwrap(), 1)),
box e @ Expression::Add(..) => for (key, value) in count_variables_add(e) {
box NumberLiteral(x) => b_row.push((0, x)),
box VariableReference(x) => b_row.push((variables.iter().position(|r| r == &x).unwrap(), 1)),
box e @ Add(..) => for (key, value) in count_variables_add(e) {
b_row.push((variables.iter().position(|r| r == &key).unwrap(), value));
},
e @ _ => panic!("Not flattened: {}", e),
};
},
Expression::Div(lhs, rhs) => { // a / b = c --> c * b = a
Div(lhs, rhs) => { // a / b = c --> c * b = a
a_row.push((idx, 1));
match lhs {
box Expression::NumberLiteral(x) => c_row.push((0, x)),
box Expression::VariableReference(x) => c_row.push((variables.iter().position(|r| r == &x).unwrap(), 1)),
_ => panic!("Not flattened!"),
box NumberLiteral(x) => c_row.push((0, x)),
box VariableReference(x) => c_row.push((variables.iter().position(|r| r == &x).unwrap(), 1)),
_ => unimplemented!(),
};
match rhs {
box Expression::NumberLiteral(x) => b_row.push((0, x)),
box Expression::VariableReference(x) => b_row.push((variables.iter().position(|r| r == &x).unwrap(), 1)),
_ => panic!("Not flattened!"),
box NumberLiteral(x) => b_row.push((0, x)),
box VariableReference(x) => b_row.push((variables.iter().position(|r| r == &x).unwrap(), 1)),
_ => unimplemented!(),
};
},
Expression::Pow(_, _) => panic!("Pow not flattened"),
Expression::IfElse(_, _, _) => panic!("IfElse not flattened"),
Expression::VariableReference(var) => {
Pow(_, _) => panic!("Pow not flattened"),
IfElse(_, _, _) => panic!("IfElse not flattened"),
VariableReference(var) => {
a_row.push((variables.iter().position(|r| r == &var).unwrap(), 1));
b_row.push((0, 1));
c_row.push((idx, 1));
},
Expression::NumberLiteral(x) => {
NumberLiteral(x) => {
a_row.push((0, x));
b_row.push((0, 1));
c_row.push((idx, 1));