Skip to content
This repository has been archived by the owner on Apr 9, 2024. It is now read-only.

Commit

Permalink
chore!: Reorganiser compiler in terms of optimisers and transformers (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
TomAFrench authored Feb 14, 2023
1 parent db8e828 commit 9329307
Show file tree
Hide file tree
Showing 14 changed files with 179 additions and 176 deletions.
4 changes: 3 additions & 1 deletion acir/src/circuit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ const VERSION_NUMBER: u32 = 0;

#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
pub struct Circuit {
// current_witness_index is the highest witness index in the circuit. The next witness to be added to this circuit
// will take on this value. (The value is cached here as an optimization.)
pub current_witness_index: u32,
pub opcodes: Vec<Opcode>,
pub public_inputs: PublicInputs,
Expand Down Expand Up @@ -204,7 +206,7 @@ mod test {
Opcode::Arithmetic(crate::native_types::Expression {
mul_terms: vec![],
linear_combinations: vec![],
q_c: FieldElement::from_hex("FFFF").unwrap(),
q_c: FieldElement::from(8u128),
}),
range_opcode(),
and_opcode(),
Expand Down
1 change: 1 addition & 0 deletions acir/src/native_types/witness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use flate2::{
};
use serde::{Deserialize, Serialize};

// Witness might be a misnomer. This is an index that represents the position a witness will take
#[derive(
Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Default, Serialize, Deserialize,
)]
Expand Down
56 changes: 35 additions & 21 deletions acvm/src/compiler.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// The various passes that we can use over ACIR
pub mod fallback;
pub mod optimizer;
pub mod optimizers;
pub mod transformers;

use crate::Language;
use acir::{
Expand All @@ -9,10 +9,9 @@ use acir::{
BlackBoxFunc,
};
use indexmap::IndexMap;
use optimizer::{CSatOptimizer, GeneralOptimizer};
use optimizers::GeneralOptimizer;
use thiserror::Error;

use self::{fallback::IsBlackBoxSupported, optimizer::R1CSOptimizer};
use transformers::{CSatTransformer, FallbackTransformer, IsBlackBoxSupported, R1CSTransformer};

#[derive(PartialEq, Eq, Debug, Error)]
pub enum CompileError {
Expand All @@ -29,33 +28,48 @@ pub fn compile(
// Currently the optimizer and reducer are one in the same
// for CSAT

// Fallback pass
let fallback = fallback::fallback(acir, is_black_box_supported)?;
// Fallback transformer pass
let acir = FallbackTransformer::transform(acir, is_black_box_supported)?;

// General optimizer pass
let mut opcodes: Vec<Opcode> = Vec::new();
for opcode in acir.opcodes {
match opcode {
Opcode::Arithmetic(arith_expr) => {
opcodes.push(Opcode::Arithmetic(GeneralOptimizer::optimize(arith_expr)))
}
other_gate => opcodes.push(other_gate),
};
}
let acir = Circuit { opcodes, ..acir };

let optimizer = match &np_language {
let transformer = match &np_language {
crate::Language::R1CS => {
let optimizer = R1CSOptimizer::new(fallback);
return Ok(optimizer.optimize());
let transformer = R1CSTransformer::new(acir);
return Ok(transformer.transform());
}
crate::Language::PLONKCSat { width } => CSatOptimizer::new(*width),
crate::Language::PLONKCSat { width } => CSatTransformer::new(*width),
};

// TODO: the code below is only for CSAT optimizer
// TODO: the code below is only for CSAT transformer
// TODO it may be possible to refactor it in a way that we do not need to return early from the r1cs
// TODO or at the very least, we could put all of it inside of CSatOptimizer pass

// Optimize the arithmetic gates by reducing them into the correct width and
// creating intermediate variables when necessary
let mut optimized_gates = Vec::new();
let mut transformed_gates = Vec::new();

let mut next_witness_index = fallback.current_witness_index + 1;
for opcode in fallback.opcodes {
let mut next_witness_index = acir.current_witness_index + 1;
for opcode in acir.opcodes {
match opcode {
Opcode::Arithmetic(arith_expr) => {
let mut intermediate_variables: IndexMap<Witness, Expression> = IndexMap::new();

let arith_expr =
optimizer.optimize(arith_expr, &mut intermediate_variables, next_witness_index);
let arith_expr = transformer.transform(
arith_expr,
&mut intermediate_variables,
next_witness_index,
);

// Update next_witness counter
next_witness_index += intermediate_variables.len() as u32;
Expand All @@ -67,18 +81,18 @@ pub fn compile(
new_gates.push(arith_expr);
new_gates.sort();
for gate in new_gates {
optimized_gates.push(Opcode::Arithmetic(gate));
transformed_gates.push(Opcode::Arithmetic(gate));
}
}
other_gate => optimized_gates.push(other_gate),
other_gate => transformed_gates.push(other_gate),
}
}

let current_witness_index = next_witness_index - 1;

Ok(Circuit {
current_witness_index,
opcodes: optimized_gates,
public_inputs: fallback.public_inputs, // The optimizer does not add public inputs
opcodes: transformed_gates,
public_inputs: acir.public_inputs, // The optimizer does not add public inputs
})
}
97 changes: 0 additions & 97 deletions acvm/src/compiler/fallback.rs

This file was deleted.

7 changes: 0 additions & 7 deletions acvm/src/compiler/optimizer/mod.rs

This file was deleted.

35 changes: 0 additions & 35 deletions acvm/src/compiler/optimizer/r1cs_optimizer.rs

This file was deleted.

3 changes: 3 additions & 0 deletions acvm/src/compiler/optimizers/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
mod general;

pub use general::GeneralOpt as GeneralOptimizer;
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,30 @@ use acir::{
};
use indexmap::IndexMap;

use super::general_optimizer::GeneralOpt;
// Optimizer struct with all of the related optimizations to the arithmetic gate

// Is this more of a Reducer than an optimizer?
// Should we give it all of the gates?
// Have a single optimizer that you instantiate with a width, then pass many gates through
pub struct Optimizer {
// Have a single transformer that you instantiate with a width, then pass many gates through
pub struct CSatTransformer {
width: usize,
}

impl Optimizer {
// Configure the width for the Optimizer
pub fn new(width: usize) -> Optimizer {
impl CSatTransformer {
// Configure the width for the optimizer
pub fn new(width: usize) -> CSatTransformer {
assert!(width > 2);

Optimizer { width }
CSatTransformer { width }
}

// Still missing dead witness optimization.
// To do this, we will need the whole set of arithmetic gates
// I think it can also be done before the local optimization seen here, as dead variables will come from the user
pub fn optimize(
pub fn transform(
&self,
gate: Expression,
intermediate_variables: &mut IndexMap<Witness, Expression>,
num_witness: u32,
) -> Expression {
let gate = GeneralOpt::optimize(gate);

// Here we create intermediate variables and constrain them to be equal to any subset of the polynomial that can be represented as a full gate
let gate = self.full_gate_scan_optimization(gate, intermediate_variables, num_witness);
// The last optimization to do is to create intermediate variables in order to flatten the fan-in and the amount of mul terms
Expand Down Expand Up @@ -348,8 +343,9 @@ fn simple_reduction_smoke_test() {

let num_witness = 4;

let optimizer = Optimizer::new(3);
let got_optimized_gate_a = optimizer.optimize(gate_a, &mut intermediate_variables, num_witness);
let optimizer = CSatTransformer::new(3);
let got_optimized_gate_a =
optimizer.transform(gate_a, &mut intermediate_variables, num_witness);

// a = b + c + d => a - b - c - d = 0
// For width3, the result becomes:
Expand Down
Loading

0 comments on commit 9329307

Please sign in to comment.