Struct Circuit

Source
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

Source

pub fn new() -> Self

Create a new circuit and initialize all fields to empty.

Source

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 u32s 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());
Source

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);
Source

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);
Source

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);
Source

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());
Source

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());
Source

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());
Source

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());
Source

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§

Source§

impl Default for Circuit

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl Display for Circuit

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V