Skip to content

Commit

Permalink
docs: Add builder module docs + example (#853)
Browse files Browse the repository at this point in the history
drive-by: Make the `CircuitBuilder` constructor a bit more generic.
  • Loading branch information
aborgna-q authored Mar 1, 2024
1 parent 197541b commit 065f675
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 6 deletions.
88 changes: 87 additions & 1 deletion src/builder.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,90 @@
//! Tools for building valid HUGRs.
//! Utilities for building valid HUGRs.
//!
//! This module includes various tools for building HUGRs.
//!
//! Depending on the type of HUGR you want to build, you may want to use one of
//! the following builders:
//!
//! - [ModuleBuilder]: For building a module with function declarations and
//! definitions.
//! - [DFGBuilder]: For building a dataflow graph.
//! - [FunctionBuilder]: A `DFGBuilder` specialised in defining functions with a
//! dataflow graph.
//! - [CFGBuilder]: For building a control flow graph.
//! - [ConditionalBuilder]: For building a conditional node.
//! - [TailLoopBuilder]: For building a tail-loop node.
//!
//! Additionally, the [CircuitBuilder] provides an alternative to the
//! [DFGBuilder] when working with circuits, where some inputs of operations directly
//! correspond to some outputs and operations can be directly appended using
//! unit indices.
//!
//! # Example
//!
//! The following example shows how to build a simple HUGR module with two
//! dataflow functions, one built using the `DFGBuilder` and the other using the
//! `CircuitBuilder`.
//!
//! ```rust
//! # use hugr::Hugr;
//! # use hugr::builder::{BuildError, BuildHandle, Container, DFGBuilder, Dataflow, DataflowHugr, ModuleBuilder, DataflowSubContainer, HugrBuilder};
//! use hugr::extension::prelude::BOOL_T;
//! use hugr::std_extensions::logic::{NotOp, LOGIC_REG};
//! use hugr::types::FunctionType;
//!
//! # fn doctest() -> Result<(), BuildError> {
//! let hugr = {
//! let mut module_builder = ModuleBuilder::new();
//!
//! // Add a `main` function with signature `bool -> bool`.
//! //
//! // This block returns a handle to the built function.
//! let _dfg_handle = {
//! let mut dfg = module_builder.define_function(
//! "main",
//! FunctionType::new(vec![BOOL_T], vec![BOOL_T]).into(),
//! )?;
//!
//! // Get the wires from the function inputs.
//! let [w] = dfg.input_wires_arr();
//!
//! // Add an operation connected to the input wire, and get the new dangling wires.
//! let [w] = dfg.add_dataflow_op(NotOp, [w])?.outputs_arr();
//!
//! // Finish the function, connecting some wires to the output.
//! dfg.finish_with_outputs([w])
//! }?;
//!
//! // Add a similar function, using the circuit builder interface.
//! let _circuit_handle = {
//! let mut dfg = module_builder.define_function(
//! "circuit",
//! FunctionType::new(vec![BOOL_T, BOOL_T], vec![BOOL_T, BOOL_T]).into(),
//! )?;
//! let mut circuit = dfg.as_circuit(dfg.input_wires());
//!
//! // Add multiple operations, indicating only the wire index.
//! circuit.append(NotOp, [0])?.append(NotOp, [1])?;
//!
//! // Finish the circuit, and return the dataflow graph after connecting its outputs.
//! let outputs = circuit.finish();
//! dfg.finish_with_outputs(outputs)
//! }?;
//!
//! // Finish building the HUGR, consuming the builder.
//! //
//! // Requires a registry with all the extensions used in the module.
//! module_builder.finish_hugr(&LOGIC_REG)
//! }?;
//!
//! // The built HUGR is always valid.
//! hugr.validate(&LOGIC_REG).unwrap_or_else(|e| {
//! panic!("HUGR validation failed: {e}");
//! });
//! # Ok(())
//! # }
//! # doctest().unwrap();
//! ```
//!
use thiserror::Error;

Expand Down
2 changes: 1 addition & 1 deletion src/builder/build_traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,7 @@ pub trait Dataflow: Container {

/// For the vector of `wires`, produce a `CircuitBuilder` where ops can be
/// added using indices in to the vector.
fn as_circuit(&mut self, wires: Vec<Wire>) -> CircuitBuilder<Self> {
fn as_circuit(&mut self, wires: impl IntoIterator<Item = Wire>) -> CircuitBuilder<Self> {
CircuitBuilder::new(wires, self)
}
}
Expand Down
9 changes: 6 additions & 3 deletions src/builder/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,11 @@ pub enum CircuitBuildError {
impl<'a, T: Dataflow + ?Sized> CircuitBuilder<'a, T> {
/// Construct a new [`CircuitBuilder`] from a vector of incoming wires and the
/// builder for the graph
pub fn new(wires: Vec<Wire>, builder: &'a mut T) -> Self {
Self { wires, builder }
pub fn new(wires: impl IntoIterator<Item = Wire>, builder: &'a mut T) -> Self {
Self {
wires: wires.into_iter().collect(),
builder,
}
}

/// Number of wires tracked, upper bound of valid wire indices
Expand Down Expand Up @@ -188,7 +191,7 @@ mod test {
|mut f_build| {
let [q0, q1, angle]: [Wire; 3] = f_build.input_wires_arr();

let mut linear = f_build.as_circuit(vec![q0, q1]);
let mut linear = f_build.as_circuit([q0, q1]);

let measure_out = linear
.append(cx_gate(), [0, 1])?
Expand Down
2 changes: 1 addition & 1 deletion src/hugr/rewrite/simple_replace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,7 @@ pub(in crate::hugr::rewrite) mod test {
fn test_replace_cx_cross() {
let q_row: Vec<Type> = vec![QB, QB];
let mut builder = DFGBuilder::new(FunctionType::new(q_row.clone(), q_row)).unwrap();
let mut circ = builder.as_circuit(builder.input_wires().collect());
let mut circ = builder.as_circuit(builder.input_wires());
circ.append(cx_gate(), [0, 1]).unwrap();
circ.append(cx_gate(), [1, 0]).unwrap();
let wires = circ.finish();
Expand Down

0 comments on commit 065f675

Please sign in to comment.