CQCL/tket2

bug: Rewrite when LHS has no inputs

PabloAndresCQ opened this issue · 0 comments

I stumbled upon this during the hack week project for MBQCification. The example below is a simplified version replicating the error.

Circuit:
image

LHS:
image

RHS:
image

Code to generate these and reproduce the error:

use hugr::{
    builder::{BuildError, DFGBuilder, Dataflow, DataflowHugr}, 
    extension::{
        prelude::QB_T, PRELUDE_REGISTRY
    }, 
    types::FunctionType, Hugr, HugrView
};
use tket2::{portmatching::{CircuitPattern, PatternMatcher}, Tk2Op};
use urlencoding;
use webbrowser;

// Copied from Dan's
fn viz_hugr(hugr: &impl HugrView) {
    let mut base: String = "https://dreampuf.github.io/GraphvizOnline/#".into();
    base.push_str(&urlencoding::encode(hugr.dot_string().as_ref()));
    webbrowser::open(&base).unwrap();
}

fn alloc() -> Result<Hugr, BuildError> {
    let mut h = DFGBuilder::new(FunctionType::new(vec![], vec![QB_T]))?;

    let res = h.add_dataflow_op(Tk2Op::QAlloc, [])?;
    let q = res.out_wire(0);

    h.finish_hugr_with_outputs([q], &PRELUDE_REGISTRY)   
}

fn alloc_reset() -> Result<Hugr, BuildError> {
    let mut h = DFGBuilder::new(FunctionType::new(vec![], vec![QB_T]))?;

    let res = h.add_dataflow_op(Tk2Op::QAlloc, [])?;
    let q = res.out_wire(0);
    let res = h.add_dataflow_op(Tk2Op::Reset, [q])?;
    let q = res.out_wire(0);

    h.finish_hugr_with_outputs([q], &PRELUDE_REGISTRY)   
}

pub fn circ_example() -> Result<Hugr, BuildError> {

    let mut h = DFGBuilder::new(FunctionType::new(vec![QB_T], vec![QB_T]))?;
    let mut inps = h.input_wires();
    let q_in = inps.next().unwrap();

    let res = h.add_dataflow_op(Tk2Op::QAlloc, [])?;
    let q_out = res.out_wire(0);
    let res = h.add_dataflow_op(Tk2Op::CZ, [q_in, q_out])?;
    let q_in = res.out_wire(0);
    let q_out = res.out_wire(1);
    h.add_dataflow_op(Tk2Op::QFree, [q_in])?;
    
    h.finish_hugr_with_outputs([q_out], &PRELUDE_REGISTRY)
}
fn main() {
    let mut circ = circ_example().unwrap();

    let lhs = alloc().unwrap();
    let rhs = alloc_reset().unwrap();

    viz_hugr(&circ);
    viz_hugr(&lhs);
    viz_hugr(&rhs);
    
    let p = CircuitPattern::try_from_circuit(&lhs).unwrap();
    let m = PatternMatcher::from_patterns(vec![p]);

    let matches = m.find_matches(&circ);
    for matched in matches {
        matched
            .to_rewrite(&circ, rhs.clone())
            .unwrap()
            .apply(&mut circ)
            .unwrap_or_else(|e| {
                dbg!(matched.to_rewrite(&circ, rhs.clone()));
                panic!("{}", e)
        })
    }
}

The error:

A node requested for removal is invalid.
stack backtrace:
   0: rust_begin_unwind
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:645:5
   1: core::panicking::panic_fmt
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/panicking.rs:72:14
   2: core::panicking::panic_display
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/panicking.rs:196:5
   3: mbqcification::main::{{closure}}::panic_cold_display
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/panic.rs:99:13
   4: mbqcification::main::{{closure}}
             at ./src/main.rs:75:17
   5: core::result::Result<T,E>::unwrap_or_else
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/result.rs:1426:23
   6: mbqcification::main
             at ./src/main.rs:69:9
   7: core::ops::function::FnOnce::call_once
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/ops/function.rs:250:5