use crate::Register;
use std::ops::{Range, RangeInclusive};
use std::iter::Iterator;
#[macro_export]
macro_rules! program {
(@name_tuple ($($body:tt)*) <- $name:ident; $($tail:tt)*) => {
($($body)* $name)
};
(@name_tuple ($($body:tt)*) <- $name:ident, $($tail:tt)*) => {
program!(@name_tuple ($($body)* $name,) <- $($tail)*)
};
(@splitter($builder:expr, $reg_vec:ident) $name:ident; $($tail:tt)*) => {
let tmp_indices = $name.indices.clone();
let tmp_register_wrapper = RegisterDataWrapper::new(&$name, $reg_vec.len());
let tmp_name: Vec<Option<Register>> = $builder.split_all($name).into_iter().map(|q| Some(q)).collect();
let $name = tmp_register_wrapper;
$reg_vec.push((tmp_name, tmp_indices, stringify!($name)));
};
(@splitter($builder:expr, $reg_vec:ident) $name:ident, $($tail:tt)*) => {
program!(@splitter($builder, $reg_vec) $name; $($tail)*);
program!(@splitter($builder, $reg_vec) $($tail)*);
};
(@joiner($builder:expr, $reg_vec:ident) $name:ident; $($tail:tt)*) => {
let $name: Vec<Register> = $reg_vec.pop().unwrap().0.into_iter().map(|q| q.unwrap()).collect();
let $name: Register = $builder.merge($name)?;
};
(@joiner($builder:expr, $reg_vec:ident) $name:ident, $($tail:tt)*) => {
program!(@joiner($builder, $reg_vec) $name; $($tail)*);
program!(@joiner($builder, $reg_vec) $($tail)*);
};
(@args_acc($builder:expr, $reg_vec:ident, $args:ident, $group_vec:ident) $name:ident,|; $($tail:tt)*) => {
let tmp_all_indices: Vec<_> = (0 .. $reg_vec[$name.index].0.len()).collect();
program!(@args_acc($builder, $reg_vec, $args, $group_vec) $name tmp_all_indices,|; $($tail)*)
};
(@args_acc($builder:expr, $reg_vec:ident, $args:ident, $group_vec:ident) $name:ident,| $($tail:tt)*) => {
let tmp_all_indices: Vec<_> = (0 .. $reg_vec[$name.index].0.len()).collect();
program!(@args_acc($builder, $reg_vec, $args, $group_vec) $name tmp_all_indices,| $($tail)*)
};
(@args_acc($builder:expr, $reg_vec:ident, $args:ident, $group_vec:ident) $name:ident, $($tail:tt)*) => {
let tmp_all_indices: Vec<_> = (0 .. $reg_vec[$name.index].0.len()).collect();
program!(@args_acc($builder, $reg_vec, $args, $group_vec) $name tmp_all_indices, $($tail)*)
};
(@args_acc($builder:expr, $reg_vec:ident, $args:ident) |$name:ident, $($tail:tt)*) => {
let tmp_all_indices: Vec<_> = (0 .. $reg_vec[$name.index].0.len()).collect();
program!(@args_acc($builder, $reg_vec, $args) |$name tmp_all_indices, $($tail)*)
};
(@args_acc($builder:expr, $reg_vec:ident, $args:ident, $group_vec:ident) $name:ident $indices:expr,|; $($tail:tt)*) => {
program!(@extract_to_args($builder, $reg_vec, $group_vec) $name $indices);
let tmp_r = $builder.merge($group_vec)?;
$args.push(tmp_r);
};
(@args_acc($builder:expr, $reg_vec:ident, $args:ident, $group_vec:ident) $name:ident $indices:expr,| $($tail:tt)*) => {
program!(@extract_to_args($builder, $reg_vec, $group_vec) $name $indices);
let tmp_r = $builder.merge($group_vec)?;
$args.push(tmp_r);
program!(@args_acc($builder, $reg_vec, $args) $($tail)*)
};
(@args_acc($builder:expr, $reg_vec:ident, $args:ident, $group_vec:ident) $name:ident $indices:expr, $($tail:tt)*) => {
program!(@extract_to_args($builder, $reg_vec, $group_vec) $name $indices);
program!(@args_acc($builder, $reg_vec, $args, $group_vec) $($tail)*)
};
(@args_acc($builder:expr, $reg_vec:ident, $args:ident) |$name:ident $indices:expr, $($tail:tt)*) => {
let mut tmp_grouped_args: Vec<Register> = vec![];
program!(@args_acc($builder, $reg_vec, $args, tmp_grouped_args) $name $indices, $($tail)*)
};
(@args_acc($builder:expr, $reg_vec:ident, $args:ident) $name:ident; $($tail:tt)*) => {
let tmp_all_indices: Vec<_> = (0 .. $reg_vec[$name.index].0.len()).collect();
program!(@args_acc($builder, $reg_vec, $args) $name tmp_all_indices; $($tail)*)
};
(@args_acc($builder:expr, $reg_vec:ident, $args:ident) $name:ident, $($tail:tt)*) => {
let tmp_all_indices: Vec<_> = (0 .. $reg_vec[$name.index].0.len()).collect();
program!(@args_acc($builder, $reg_vec, $args) $name tmp_all_indices, $($tail)*)
};
(@args_acc($builder:expr, $reg_vec:ident, $args:ident) $name:ident $indices:expr, $($tail:tt)*) => {
program!(@extract_to_args($builder, $reg_vec, $args) $name $indices);
program!(@args_acc($builder, $reg_vec, $args) $($tail)*)
};
(@args_acc($builder:expr, $reg_vec:ident, $args:ident) $name:ident $indices:expr;) => {
program!(@extract_to_args($builder, $reg_vec, $args) $name $indices);
};
(@args_acc($builder:expr, $reg_vec:ident, $args:ident) $name:ident $indices:expr; $($tail:tt)*) => {
program!(@args_acc($builder, $reg_vec, $args) $name $indices;);
};
(@extract_to_args($builder:expr, $reg_vec:ident, $args:ident) $name:ident $indices:expr) => {
let mut tmp_acc: Vec<Register> = vec![];
for indx in &$indices {
let tmp_indx_iter: QubitIndices = indx.into();
for indx in tmp_indx_iter.get_indices() {
let tmp_reg = $reg_vec[$name.index].0[indx].take();
let tmp_reg = tmp_reg.ok_or_else(|| CircuitError::new(format!("Failed to fetch {}[{}]. May have already been used on this line.", $reg_vec[$name.index].2, indx)))?;
tmp_acc.push(tmp_reg);
}
}
if tmp_acc.len() > 0 {
let tmp_r = $builder.merge(tmp_acc)?;
$args.push(tmp_r);
}
};
(@replace_registers($builder:expr, $reg_vec:ident, $to_replace:ident)) => {
for tmp_register in $to_replace.into_iter() {
let tmp_indices = tmp_register.indices.clone();
let tmp_registers = $builder.split_all(tmp_register);
for (tmp_register, tmp_index) in tmp_registers.into_iter().zip(tmp_indices.into_iter()) {
for (tmp_reg_holes, tmp_reg_hole_indices, _) in $reg_vec.iter_mut() {
let found = tmp_reg_hole_indices.iter()
.position(|hole_indx| *hole_indx == tmp_index);
if let Some(found) = found {
tmp_reg_holes[found] = Some(tmp_register);
break;
}
}
}
}
for (tmp_regs, tmp_indices, tmp_name) in $reg_vec.iter_mut() {
tmp_regs.iter().zip(tmp_indices.iter()).enumerate().try_for_each(|(indx, (opt_reg, reg_indx))| {
if opt_reg.is_none() {
let func_name = stringify!($func);
CircuitError::make_err(format!("Could not retrieve {}[{}] (absolute index {}). It was not returned from call to {}.", tmp_name, indx, reg_indx, func_name))
} else {
Ok(())
}
})?;
}
};
(@skip_to_next_program($builder:expr, $reg_vec:ident) $name:ident;) => {};
(@skip_to_next_program($builder:expr, $reg_vec:ident) $name:ident $indices:expr;) => {};
(@skip_to_next_program($builder:expr, $reg_vec:ident) $name:ident,|;) => {};
(@skip_to_next_program($builder:expr, $reg_vec:ident) $name:ident $indices:expr,|;) => {};
(@skip_to_next_program($builder:expr, $reg_vec:ident) |$name:ident, $($tail:tt)*) => {
program!(@skip_to_next_program($builder, $reg_vec) $($tail)*)
};
(@skip_to_next_program($builder:expr, $reg_vec:ident) |$name:ident $indices:expr, $($tail:tt)*) => {
program!(@skip_to_next_program($builder, $reg_vec) $($tail)*)
};
(@skip_to_next_program($builder:expr, $reg_vec:ident) $name:ident,|; $($tail:tt)*) => {
program!(@program($builder, $reg_vec) $($tail)*)
};
(@skip_to_next_program($builder:expr, $reg_vec:ident) $name:ident $indices:expr,|; $($tail:tt)*) => {
program!(@program($builder, $reg_vec) $($tail)*)
};
(@skip_to_next_program($builder:expr, $reg_vec:ident) $name:ident,| $($tail:tt)*) => {
program!(@skip_to_next_program($builder, $reg_vec) $($tail)*)
};
(@skip_to_next_program($builder:expr, $reg_vec:ident) $name:ident $indices:expr,| $($tail:tt)*) => {
program!(@skip_to_next_program($builder, $reg_vec) $($tail)*)
};
(@skip_to_next_program($builder:expr, $reg_vec:ident) $name:ident; $($tail:tt)*) => {
program!(@program($builder, $reg_vec) $($tail)*)
};
(@skip_to_next_program($builder:expr, $reg_vec:ident) $name:ident $indices:expr; $($tail:tt)*) => {
program!(@program($builder, $reg_vec) $($tail)*)
};
(@skip_to_next_program($builder:expr, $reg_vec:ident) $name:ident, $($tail:tt)*) => {
program!(@skip_to_next_program($builder, $reg_vec) $($tail)*)
};
(@skip_to_next_program($builder:expr, $reg_vec:ident) $name:ident $indices:expr, $($tail:tt)*) => {
program!(@skip_to_next_program($builder, $reg_vec) $($tail)*)
};
(@program($builder:expr, $reg_vec:ident) control $func:ident $($tail:tt)*) => {
program!(@program($builder, $reg_vec) control(!0) $func $($tail)*)
};
(@program($builder:expr, $reg_vec:ident) control($control:expr) $func:ident $($tail:tt)*) => {
let mut tmp_acc_vec: Vec<Register> = vec![];
program!(@args_acc($builder, $reg_vec, tmp_acc_vec) $($tail)*);
let tmp_cr = tmp_acc_vec.remove(0);
let tmp_crs = $builder.split_all(tmp_cr);
let (tmp_crs,_) = tmp_crs.into_iter().fold((vec![], $control), |(mut qubit_acc, mask_acc), qubit| {
let lowest = mask_acc & 1;
let qubit = if lowest == 0 {
$builder.not(qubit)
} else {
qubit
};
qubit_acc.push(qubit);
(qubit_acc, mask_acc >> 1)
});
let tmp_cr = $builder.merge(tmp_crs)?;
let mut tmp_cb = $builder.with_condition(tmp_cr);
let mut tmp_results: Vec<Register> = $func(&mut tmp_cb, tmp_acc_vec)?;
let tmp_cr = tmp_cb.release_register();
let tmp_crs = $builder.split_all(tmp_cr);
let (tmp_crs,_) = tmp_crs.into_iter().fold((vec![], $control), |(mut qubit_acc, mask_acc), qubit| {
let lowest = mask_acc & 1;
let qubit = if lowest == 0 {
$builder.not(qubit)
} else {
qubit
};
qubit_acc.push(qubit);
(qubit_acc, mask_acc >> 1)
});
let tmp_cr = $builder.merge(tmp_crs)?;
tmp_results.push(tmp_cr);
program!(@replace_registers($builder, $reg_vec, tmp_results));
program!(@skip_to_next_program($builder, $reg_vec) $($tail)*);
};
(@program($builder:expr, $reg_vec:ident) $func:ident $($tail:tt)*) => {
let mut acc_vec: Vec<Register> = vec![];
program!(@args_acc($builder, $reg_vec, acc_vec) $($tail)*);
let tmp_results: Vec<Register> = $func($builder, acc_vec)?;
program!(@replace_registers($builder, $reg_vec, tmp_results));
program!(@skip_to_next_program($builder, $reg_vec) $($tail)*);
};
(@skip_to_program($builder:expr, $reg_vec:ident) $name:ident; $($tail:tt)*) => {
program!(@program($builder, $reg_vec) $($tail)*)
};
(@skip_to_program($builder:expr, $reg_vec:ident) $name:ident, $($tail:tt)*) => {
program!(@skip_to_program($builder, $reg_vec) $($tail)*)
};
($builder:expr, $($tail:tt)*) => {
{
let mut register_vec: Vec<(Vec<Option<Register>>, Vec<u64>, &str)> = vec![];
program!(@splitter($builder, register_vec) $($tail)*);
program!(@skip_to_program($builder, register_vec) $($tail)*);
program!(@joiner($builder, register_vec) $($tail)*);
program!(@name_tuple () <- $($tail)*)
}
};
}
#[derive(Debug)]
pub struct QubitIndices {
indices: Vec<usize>
}
impl QubitIndices {
pub fn get_indices(self) -> Vec<usize> {
self.indices
}
}
impl From<Range<usize>> for QubitIndices {
fn from(indices: Range<usize>) -> Self {
let indices: Vec<_> = indices.collect();
indices.into()
}
}
impl From<Range<u64>> for QubitIndices {
fn from(indices: Range<u64>) -> Self {
let indices: Vec<_> = indices.map(|indx| indx as usize).collect();
indices.into()
}
}
impl From<Range<u32>> for QubitIndices {
fn from(indices: Range<u32>) -> Self {
let indices: Vec<_> = indices.map(|indx| indx as usize).collect();
indices.into()
}
}
impl From<Range<i64>> for QubitIndices {
fn from(indices: Range<i64>) -> Self {
let indices: Vec<_> = indices.map(|indx| indx as usize).collect();
indices.into()
}
}
impl From<Range<i32>> for QubitIndices {
fn from(indices: Range<i32>) -> Self {
let indices: Vec<_> = indices.map(|indx| indx as usize).collect();
indices.into()
}
}
impl From<&Range<usize>> for QubitIndices {
fn from(indices: &Range<usize>) -> Self {
(indices.start .. indices.end).into()
}
}
impl From<&Range<u64>> for QubitIndices {
fn from(indices: &Range<u64>) -> Self {
(indices.start .. indices.end).into()
}
}
impl From<&Range<u32>> for QubitIndices {
fn from(indices: &Range<u32>) -> Self {
(indices.start .. indices.end).into()
}
}
impl From<&Range<i64>> for QubitIndices {
fn from(indices: &Range<i64>) -> Self {
(indices.start .. indices.end).into()
}
}
impl From<&Range<i32>> for QubitIndices {
fn from(indices: &Range<i32>) -> Self {
(indices.start .. indices.end).into()
}
}
impl From<RangeInclusive<usize>> for QubitIndices {
fn from(indices: RangeInclusive<usize>) -> Self {
let indices: Vec<_> = indices.collect();
indices.into()
}
}
impl From<RangeInclusive<u64>> for QubitIndices {
fn from(indices: RangeInclusive<u64>) -> Self {
let indices: Vec<_> = indices.map(|indx| indx as usize).collect();
indices.into()
}
}
impl From<RangeInclusive<u32>> for QubitIndices {
fn from(indices: RangeInclusive<u32>) -> Self {
let indices: Vec<_> = indices.map(|indx| indx as usize).collect();
indices.into()
}
}
impl From<RangeInclusive<i64>> for QubitIndices {
fn from(indices: RangeInclusive<i64>) -> Self {
let indices: Vec<_> = indices.map(|indx| indx as usize).collect();
indices.into()
}
}
impl From<RangeInclusive<i32>> for QubitIndices {
fn from(indices: RangeInclusive<i32>) -> Self {
let indices: Vec<_> = indices.map(|indx| indx as usize).collect();
indices.into()
}
}
impl From<&RangeInclusive<usize>> for QubitIndices {
fn from(indices: &RangeInclusive<usize>) -> Self {
(*indices.start() .. *indices.end()+1).into()
}
}
impl From<&RangeInclusive<u64>> for QubitIndices {
fn from(indices: &RangeInclusive<u64>) -> Self {
(*indices.start() .. *indices.end()+1).into()
}
}
impl From<&RangeInclusive<u32>> for QubitIndices {
fn from(indices: &RangeInclusive<u32>) -> Self {
(*indices.start() .. *indices.end()+1).into()
}
}
impl From<&RangeInclusive<i64>> for QubitIndices {
fn from(indices: &RangeInclusive<i64>) -> Self {
(*indices.start() .. *indices.end()+1).into()
}
}
impl From<&RangeInclusive<i32>> for QubitIndices {
fn from(indices: &RangeInclusive<i32>) -> Self {
(*indices.start() .. *indices.end()+1).into()
}
}
impl<T: Into<usize>> From<Vec<T>> for QubitIndices {
fn from(indices: Vec<T>) -> Self {
let indices: Vec<usize> = indices.into_iter().map(|indx| indx.into()).collect();
Self {
indices
}
}
}
impl From<usize> for QubitIndices {
fn from(item: usize) -> Self {
Self {
indices: vec![item]
}
}
}
impl From<&usize> for QubitIndices {
fn from(item: &usize) -> Self {
(*item).into()
}
}
#[derive(Debug)]
pub struct RegisterDataWrapper {
pub indices: Vec<u64>,
pub n: u64,
pub index: usize,
}
impl RegisterDataWrapper {
pub fn new(r: &Register, index: usize) -> Self {
Self {
indices: r.indices.clone(),
n: r.n(),
index
}
}
pub fn n(&self) -> u64 {
self.n
}
}
#[cfg(test)]
mod common_circuit_tests {
use super::*;
use crate::pipeline::make_circuit_matrix;
use crate::{run_debug, CircuitError, OpBuilder, UnitaryBuilder, Register};
#[test]
fn test_program_macro() -> Result<(), CircuitError> {
let n = 3;
let mut b = OpBuilder::new();
let ra = b.register(n)?;
let rb = b.register(n)?;
let cnot = |b: &mut dyn UnitaryBuilder, mut rs: Vec<Register>| -> Result<Vec<Register>, CircuitError> {
let rb = rs.pop().unwrap();
let ra = rs.pop().unwrap();
let (ra, rb) = b.cnot(ra, rb);
Ok(vec![ra, rb])
};
let (ra, rb) = program!(&mut b, ra, rb;
cnot ra, rb[2];
cnot ra[0], rb;
);
let r = b.merge(vec![ra, rb])?;
run_debug(&r)?;
let macro_circuit = make_circuit_matrix::<f64>(2*n, &r, true);
let mut b = OpBuilder::new();
let ra = b.register(n)?;
let rb = b.register(n)?;
let (r, rb) = b.split(rb, &[2])?;
let (ra, r) = b.cnot(ra, r);
let rb = b.merge_with_indices(rb, vec![r], &[2])?;
let (r, ra) = b.split(ra, &[0])?;
let (r, rb) = b.cnot(r, rb);
let ra = b.merge_with_indices(ra, vec![r], &[0])?;
let r = b.merge(vec![ra, rb])?;
run_debug(&r)?;
let basic_circuit = make_circuit_matrix::<f64>(2*n, &r, true);
assert_eq!(macro_circuit, basic_circuit);
Ok(())
}
#[test]
fn test_program_macro_reuse() -> Result<(), CircuitError> {
let n = 3;
let mut b = OpBuilder::new();
let r = b.register(n)?;
let cnot = |b: &mut dyn UnitaryBuilder, mut rs: Vec<Register>| -> Result<Vec<Register>, CircuitError> {
let rb = rs.pop().unwrap();
let ra = rs.pop().unwrap();
let (ra, rb) = b.cnot(ra, rb);
Ok(vec![ra, rb])
};
let r = program!(&mut b, r;
cnot r[0], r[1];
);
run_debug(&r)?;
let macro_circuit = make_circuit_matrix::<f64>(n, &r, true);
let mut b = OpBuilder::new();
let r = b.register(n)?;
let (r1, r2) = b.split(r, &[0])?;
let (r2, r3) = b.split(r2, &[0])?;
let (r1, r2) = b.cnot(r1, r2);
let r = b.merge(vec![r1, r2, r3])?;
run_debug(&r)?;
let basic_circuit = make_circuit_matrix::<f64>(n, &r, true);
assert_eq!(macro_circuit, basic_circuit);
Ok(())
}
#[test]
fn test_program_macro_group() -> Result<(), CircuitError> {
let n = 3;
let mut b = OpBuilder::new();
let ra = b.register(n)?;
let rb = b.register(n)?;
let cnot = |b: &mut dyn UnitaryBuilder, mut rs: Vec<Register>| -> Result<Vec<Register>, CircuitError> {
let rb = rs.pop().unwrap();
let ra = rs.pop().unwrap();
let (ra, rb) = b.cnot(ra, rb);
Ok(vec![ra, rb])
};
let (ra, rb) = program!(&mut b, ra, rb;
cnot |ra[0], ra[2],| rb[2];
);
let r = b.merge(vec![ra, rb])?;
run_debug(&r)?;
let macro_circuit = make_circuit_matrix::<f64>(2*n, &r, true);
let mut b = OpBuilder::new();
let ra = b.register(n)?;
let rb = b.register(n)?;
let (r, rb) = b.split(rb, &[2])?;
let (ra_side, ra_mid) = b.split(ra, &[0, 2])?;
let (ra_side, r) = b.cnot(ra_side, r);
let ra_sides = b.split_all(ra_side);
let ra = b.merge_with_indices(ra_mid, ra_sides, &[0, 2])?;
let rb = b.merge_with_indices(rb, vec![r], &[2])?;
let r = b.merge(vec![ra, rb])?;
run_debug(&r)?;
let basic_circuit = make_circuit_matrix::<f64>(2*n, &r, true);
assert_eq!(macro_circuit, basic_circuit);
Ok(())
}
#[test]
fn test_program_macro_inline_range() -> Result<(), CircuitError> {
let n = 3;
let mut b = OpBuilder::new();
let r = b.register(n)?;
let cnot = |b: &mut dyn UnitaryBuilder, mut rs: Vec<Register>| -> Result<Vec<Register>, CircuitError> {
let rb = rs.pop().unwrap();
let ra = rs.pop().unwrap();
let (ra, rb) = b.cnot(ra, rb);
Ok(vec![ra, rb])
};
let r = program!(&mut b, r;
cnot r[0..2], r[2];
);
run_debug(&r)?;
let macro_circuit = make_circuit_matrix::<f64>(n, &r, true);
let mut b = OpBuilder::new();
let r = b.register(n)?;
let (r1, r2) = b.split(r, &[2])?;
let (r2, r1) = b.cnot(r2, r1);
let r = b.merge(vec![r1, r2])?;
run_debug(&r)?;
let basic_circuit = make_circuit_matrix::<f64>(n, &r, true);
assert_eq!(macro_circuit, basic_circuit);
Ok(())
}
#[test]
fn test_program_macro_inline_control() -> Result<(), CircuitError> {
let n = 3;
let mut b = OpBuilder::new();
let r = b.register(n)?;
let not = |b: &mut dyn UnitaryBuilder, mut rs: Vec<Register>| -> Result<Vec<Register>, CircuitError> {
let ra = rs.pop().unwrap();
let ra = b.not(ra);
Ok(vec![ra])
};
let r = program!(&mut b, r;
control not r[0..2], r[2];
);
run_debug(&r)?;
let macro_circuit = make_circuit_matrix::<f64>(n, &r, true);
let mut b = OpBuilder::new();
let r = b.register(n)?;
let (r1, r2) = b.split(r, &[2])?;
let (r2, r1) = b.cnot(r2, r1);
let r = b.merge(vec![r1, r2])?;
run_debug(&r)?;
let basic_circuit = make_circuit_matrix::<f64>(n, &r, true);
assert_eq!(macro_circuit, basic_circuit);
Ok(())
}
#[test]
fn test_program_macro_inline_control_expr() -> Result<(), CircuitError> {
let n = 3;
let mut b = OpBuilder::new();
let r = b.register(n)?;
let not = |b: &mut dyn UnitaryBuilder, mut rs: Vec<Register>| -> Result<Vec<Register>, CircuitError> {
let ra = rs.pop().unwrap();
let ra = b.not(ra);
Ok(vec![ra])
};
let r = program!(&mut b, r;
control(00) not r[0..2], r[2];
);
run_debug(&r)?;
let macro_circuit = make_circuit_matrix::<f64>(n, &r, true);
let mut b = OpBuilder::new();
let r = b.register(n)?;
let (r1, r2) = b.split(r, &[2])?;
let r2 = b.not(r2);
let (r2, r1) = b.cnot(r2, r1);
let r2 = b.not(r2);
let r = b.merge(vec![r1, r2])?;
run_debug(&r)?;
let basic_circuit = make_circuit_matrix::<f64>(n, &r, true);
assert_eq!(macro_circuit, basic_circuit);
Ok(())
}
}