use acir::{
native_types::{Expression, Witness},
FieldElement,
};
use indexmap::IndexMap;
pub(crate) struct GeneralOptimizer;
impl GeneralOptimizer {
pub(crate) fn optimize(opcode: Expression) -> Expression {
let opcode = remove_zero_coefficients(opcode);
let opcode = simplify_mul_terms(opcode);
simplify_linear_terms(opcode)
}
}
fn remove_zero_coefficients(mut opcode: Expression) -> Expression {
opcode.mul_terms.retain(|(scale, _, _)| !scale.is_zero());
opcode.linear_combinations.retain(|(scale, _)| !scale.is_zero());
opcode
}
fn simplify_mul_terms(mut gate: Expression) -> Expression {
let mut hash_map: IndexMap<(Witness, Witness), FieldElement> = IndexMap::new();
for (scale, w_l, w_r) in gate.mul_terms.into_iter() {
let mut pair = [w_l, w_r];
pair.sort();
*hash_map.entry((pair[0], pair[1])).or_insert_with(FieldElement::zero) += scale;
}
gate.mul_terms = hash_map.into_iter().map(|((w_l, w_r), scale)| (scale, w_l, w_r)).collect();
gate
}
fn simplify_linear_terms(mut gate: Expression) -> Expression {
let mut hash_map: IndexMap<Witness, FieldElement> = IndexMap::new();
for (scale, witness) in gate.linear_combinations.into_iter() {
*hash_map.entry(witness).or_insert_with(FieldElement::zero) += scale;
}
gate.linear_combinations = hash_map
.into_iter()
.filter(|(_, scale)| scale != &FieldElement::zero())
.map(|(witness, scale)| (scale, witness))
.collect();
gate
}