pub struct Circuit { /* private fields */ }
Expand description
Represents an arithmetic circuit. This struct manages nodes, gates, and the evaluation process of the circuit. It supports adding various types of nodes, including constants, variables, and operations, and provides methods to evaluate the circuit, check constraints, and apply custom operations.
Implementations§
Source§impl Circuit
impl Circuit
Sourcepub fn init(&mut self) -> usize
pub fn init(&mut self) -> usize
Inserts an input node into the circuit. Any number of input
nodes can be inserted. Their values are then set in sequence
by passing a list of u32
s to circuit.evaluate(&[])
.
Returns the index of the newly inserted node.
§Usage:
let mut circuit = capy_graph::Circuit::new();
let x = circuit.init();
let y = circuit.init();
let z = circuit.init();
let debug = true;
assert!(circuit.evaluate(&[1, 2, 3], debug).is_ok());
Sourcepub fn constant(&mut self, value: u32) -> usize
pub fn constant(&mut self, value: u32) -> usize
Inserts a constant-valued node into the circuit. Returns the index of the newly inserted node.
§Usage:
let mut circuit = capy_graph::Circuit::new();
let x = circuit.constant(42);
let y = circuit.mul(x, x);
Sourcepub fn add(&mut self, idx: usize, idx2: usize) -> usize
pub fn add(&mut self, idx: usize, idx2: usize) -> usize
Inserts an addition
node into the circuit. It has max fan-in
of 2 and accepts the indices of the nodes to add. Addition is
saturated; overflow yields the max u32
value, underflow yields
the minimum.
§Usage:
let mut circuit = capy_graph::Circuit::new();
let x = circuit.constant(42);
let y = circuit.add(x, x);
Sourcepub fn mul(&mut self, idx1: usize, idx2: usize) -> usize
pub fn mul(&mut self, idx1: usize, idx2: usize) -> usize
Inserts a multiplication
node into the circuit. It has max fan-in
of 2 and accepts the indices of the nodes to multiply. Multiplication
is saturated; overflow yields the max u32
value, underflow yields
the minimum.
§Usage:
let mut circuit = capy_graph::Circuit::new();
let x = circuit.constant(42);
let y = circuit.mul(x, x);
Sourcepub fn hint(
&mut self,
idx: usize,
func: Arc<dyn Fn(u32) -> u32 + Send + Sync>,
) -> usize
pub fn hint( &mut self, idx: usize, func: Arc<dyn Fn(u32) -> u32 + Send + Sync>, ) -> usize
Inserts a custom function into the circuit. This function
is passed as a closure with trait bounds restricted to
Send
+ Sync
in order to support layerization
and parallel circuit evaluation. The circuit will
catch any panics (i.e. dividing by zero) as a CircuitError
.
§Usage:
use capy_graph::Circuit;
use std::sync::Arc;
let mut circuit = Circuit::new();
let two = circuit.init();
let b = circuit.constant(16);
// the circuit doesn't support division, so we hint it
let c = circuit.hint(
b,
Arc::new(|x: u32| x / 8) as Arc<dyn Fn(u32) -> u32 + Send + Sync>
);
// then we establish a constraint to ensure the hint is executed correctly
let constraint = circuit.mul(c, two);
circuit.assert_equal(two, c);
let debug = true;
assert!(circuit.evaluate(&[2], debug).is_ok());
assert!(circuit.check_constraints().is_ok());
Sourcepub fn assert_equal(&mut self, idx1: usize, idx2: usize)
pub fn assert_equal(&mut self, idx1: usize, idx2: usize)
Inserts a constraint-check between two nodes into the circuit. This is useful for asserting that custom functions were executed correctly.
§Usage:
let mut circuit = capy_graph::Circuit::new();
let x = circuit.init();
let y = circuit.constant(42);
circuit.assert_equal(x, y);
circuit.evaluate(&[42], false);
assert!(circuit.check_constraints().is_ok());
Sourcepub fn check_constraints(&self) -> Result<(), CircuitError>
pub fn check_constraints(&self) -> Result<(), CircuitError>
Checks if all constraints in the circuit are satisfied.
Returns Ok(())
if all constraints are satisfied, or
Err(CircuitError::ConstraintCheckFailure)
if any constraint fails.
§Usage:
let mut circuit = capy_graph::Circuit::new();
let x = circuit.init();
let y = circuit.constant(42);
circuit.assert_equal(x, y);
circuit.evaluate(&[42], false);
assert!(circuit.check_constraints().is_ok());
Sourcepub fn evaluate(
&mut self,
input_vals: &[u32],
debug: bool,
) -> Result<(), CircuitError>
pub fn evaluate( &mut self, input_vals: &[u32], debug: bool, ) -> Result<(), CircuitError>
Evaluates the circuit, initializing all init
nodes to a list of input u32
values.
Inputs are initialized sequentially as they appear in the input list.
Gracefully errors on any panic introduced from a custom hint or when attempting
to evaluate an empty circuit.
Optionally print debug information from the evaluation. These details include:
- evaluation circuit evaluation time
- number of layers
- number of gates
- number of hints
- number of constraints
- number of gates processed per second
§Example Usage:
use capy_graph::Circuit;
use std::sync::Arc;
let mut circuit = Circuit::new();
let x = circuit.constant(10);
let y = circuit.add(x, x);
let custom_operation = Arc::new(|val: u32| val * 2);
let z = circuit.hint(x, custom_operation);
circuit.assert_equal(y, z);
let input_values = vec![10];
let debug = true;
assert!(circuit.evaluate(&input_values, debug).is_ok());
assert!(circuit.check_constraints().is_ok());
Sourcepub fn generate_random(&mut self, num_gates: usize)
pub fn generate_random(&mut self, num_gates: usize)
Generate an arbitrary-size, random combination of nodes and gates for testing purposes.
Includes a mix of variants from the Gate
enum as well as a custom hint. Automatically
constrains the hint and creates random dependencies between nodes.
§Usage:
use capy_graph::Circuit;
let mut circuit = Circuit::new();
// Generate a large random circuit
let num_gates = 100000;
circuit.generate_random(num_gates);
// Mock input
let inputs = vec![42; 10];
// Evaluate the circuit
assert!(circuit.evaluate(&inputs, true).is_ok());
// check all random constraints
assert!(circuit.check_constraints().is_ok());
Trait Implementations§
Auto Trait Implementations§
impl !Freeze for Circuit
impl !RefUnwindSafe for Circuit
impl Send for Circuit
impl Sync for Circuit
impl Unpin for Circuit
impl !UnwindSafe for Circuit
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read more