Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Ops require their own extensions #734

Closed
wants to merge 30 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
f1e1e6f
Add Value::extension_reqs (not used yet)
acl-cqc Dec 1, 2023
cdc5785
Add OpTrait::extension_delta, non-empty for Const or DataflowOp
acl-cqc Dec 1, 2023
9e1b3eb
Fix test_conditional_inference
acl-cqc Dec 1, 2023
b47ad17
Fix test_tuple_sum by build_traits.rs: when adding load_const, do not…
acl-cqc Dec 1, 2023
bb66a8b
Fix static_targets
acl-cqc Dec 1, 2023
35e1787
add_constant drop ExtensionSet parameter - always empty
acl-cqc Dec 1, 2023
1da3a63
Fix replace::test::cfg (pending issue #388)
acl-cqc Dec 1, 2023
6c76919
clippy (cross-version issues)
acl-cqc Dec 2, 2023
25852a3
...and fmt
acl-cqc Dec 2, 2023
4856b17
Union OpDef's extension with that from SignatureFunc - in former not …
acl-cqc Dec 1, 2023
d07d186
Fix simple_linear (with lift)
acl-cqc Dec 1, 2023
dee0825
Fix nonlinear_and_outputs with another Lift
acl-cqc Dec 1, 2023
5ae9281
Fix nested_identity + copy_insertion (many Lift's + parameterize over…
acl-cqc Dec 1, 2023
265df79
fix op_def.rs tests
acl-cqc Dec 2, 2023
b87c884
Fix search_variable_deps to handle solved Meta, and fix replace test
acl-cqc Dec 2, 2023
97f9b87
Fix (simple_)replacement tests
acl-cqc Dec 2, 2023
9f51a9b
fix test_ext_edge
acl-cqc Dec 2, 2023
bc585f4
fix test_local_const
acl-cqc Dec 2, 2023
4721505
fix full_region/flat_region tests
acl-cqc Dec 2, 2023
91c1b22
Fix test_binary_signatures
acl-cqc Dec 2, 2023
3a281c4
Fix dataflow_ports_only
acl-cqc Dec 2, 2023
89cea89
sibling_subgraph: add lift nodes to test, pass extension delta to con…
acl-cqc Dec 2, 2023
6f0b215
Merge remote-tracking branch 'origin/main' into HEAD
acl-cqc Dec 12, 2023
4c4bb87
Add ExtensionSet::union_over
acl-cqc Dec 12, 2023
b8de62f
driveby turn lambda into ExtensionSet::union
acl-cqc Dec 12, 2023
b407523
Merge remote-tracking branch 'origin/main' into HEAD
acl-cqc Dec 12, 2023
7f59d6f
Merge commit 'b4075239' into fix/ops_require_ext
acl-cqc Dec 12, 2023
66bff43
Add extra set in 'impl SignatureFunc' rather than 'impl OpDef'
acl-cqc Dec 12, 2023
fe8eaf1
a bit of clippy
acl-cqc Dec 12, 2023
22c4458
Fix cross-version unused-imports in views/tests.rs
acl-cqc Dec 12, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 28 additions & 7 deletions src/builder/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,22 +137,33 @@ mod test {
test::{build_main, NAT, QB},
Dataflow, DataflowSubContainer, Wire,
},
extension::prelude::BOOL_T,
extension::{prelude::BOOL_T, ExtensionSet},
ops::{custom::OpaqueOp, LeafOp},
type_row,
types::FunctionType,
utils::test_quantum_extension::{cx_gate, h_gate, measure},
utils::test_quantum_extension::{cx_gate, h_gate, measure, EXTENSION_ID},
};

#[test]
fn simple_linear() {
let build_res = build_main(
FunctionType::new(type_row![QB, QB], type_row![QB, QB]).into(),
FunctionType::new_endo(type_row![QB, QB])
.with_extension_delta(&ExtensionSet::singleton(&EXTENSION_ID))
.into(),
|mut f_build| {
let wires = f_build.input_wires().collect();
let mut wires: [Wire; 2] = f_build.input_wires_arr();
[wires[1]] = f_build
.add_dataflow_op(
LeafOp::Lift {
type_row: vec![QB].into(),
new_extension: EXTENSION_ID,
},
[wires[1]],
)?
.outputs_arr();

let mut linear = CircuitBuilder {
wires,
wires: Vec::from(wires),
builder: &mut f_build,
};

Expand Down Expand Up @@ -184,10 +195,20 @@ mod test {
.into(),
);
let build_res = build_main(
FunctionType::new(type_row![QB, QB, NAT], type_row![QB, QB, BOOL_T]).into(),
FunctionType::new(type_row![QB, QB, NAT], type_row![QB, QB, BOOL_T])
.with_extension_delta(&ExtensionSet::singleton(&EXTENSION_ID))
.into(),
|mut f_build| {
let [q0, q1, angle]: [Wire; 3] = f_build.input_wires_arr();

let [angle] = f_build
.add_dataflow_op(
LeafOp::Lift {
type_row: vec![NAT].into(),
new_extension: EXTENSION_ID,
},
[angle],
)?
.outputs_arr();
let mut linear = f_build.as_circuit(vec![q0, q1]);

let measure_out = linear
Expand Down
48 changes: 42 additions & 6 deletions src/builder/dataflow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,9 +213,9 @@ pub(crate) mod test {
use crate::hugr::validate::InterGraphEdgeError;
use crate::ops::{handle::NodeHandle, LeafOp, OpTag};

use crate::std_extensions::logic::test::and_op;
use crate::std_extensions::logic::{self, test::and_op};
use crate::types::Type;
use crate::utils::test_quantum_extension::h_gate;
use crate::utils::test_quantum_extension::{self, h_gate};
use crate::{
builder::{
test::{n_identity, BIT, NAT, QB},
Expand All @@ -235,13 +235,25 @@ pub(crate) mod test {
let _f_id = {
let mut func_builder = module_builder.define_function(
"main",
FunctionType::new(type_row![NAT, QB], type_row![NAT, QB]).into(),
FunctionType::new(type_row![NAT, QB], type_row![NAT, QB])
.with_extension_delta(&ExtensionSet::singleton(
&test_quantum_extension::EXTENSION_ID,
))
.into(),
)?;

let [int, qb] = func_builder.input_wires_arr();

let q_out = func_builder.add_dataflow_op(h_gate(), vec![qb])?;

let [int] = func_builder
.add_dataflow_op(
LeafOp::Lift {
type_row: vec![NAT].into(),
new_extension: test_quantum_extension::EXTENSION_ID,
},
[int],
)?
.outputs_arr();
let inner_builder = func_builder.dfg_builder(
FunctionType::new(type_row![NAT], type_row![NAT]),
None,
Expand All @@ -260,7 +272,7 @@ pub(crate) mod test {
}

// Scaffolding for copy insertion tests
fn copy_scaffold<F>(f: F, msg: &'static str) -> Result<(), BuildError>
fn copy_scaffold<F>(f: F, delta: &ExtensionSet, msg: &'static str) -> Result<(), BuildError>
where
F: FnOnce(FunctionBuilder<&mut Hugr>) -> Result<BuildHandle<FuncID<true>>, BuildError>,
{
Expand All @@ -269,7 +281,9 @@ pub(crate) mod test {

let f_build = module_builder.define_function(
"main",
FunctionType::new(type_row![BOOL_T], type_row![BOOL_T, BOOL_T]).into(),
FunctionType::new(type_row![BOOL_T], type_row![BOOL_T, BOOL_T])
.with_extension_delta(delta)
.into(),
)?;

f(f_build)?;
Expand All @@ -287,25 +301,47 @@ pub(crate) mod test {
let [b1] = f_build.input_wires_arr();
f_build.finish_with_outputs([b1, b1])
},
&ExtensionSet::new(),
"Copy input and output",
)?;

let es = ExtensionSet::singleton(&logic::EXTENSION_ID);
copy_scaffold(
|mut f_build| {
let [b1] = f_build.input_wires_arr();
let xor = f_build.add_dataflow_op(and_op(), [b1, b1])?;
let [b1] = f_build
.add_dataflow_op(
LeafOp::Lift {
type_row: vec![BOOL_T].into(),
new_extension: logic::EXTENSION_ID,
},
[b1],
)?
.outputs_arr();
f_build.finish_with_outputs([xor.out_wire(0), b1])
},
&es,
"Copy input and use with binary function",
)?;

copy_scaffold(
|mut f_build| {
let [b1] = f_build.input_wires_arr();
let xor1 = f_build.add_dataflow_op(and_op(), [b1, b1])?;
let [b1] = f_build
.add_dataflow_op(
LeafOp::Lift {
type_row: vec![BOOL_T].into(),
new_extension: logic::EXTENSION_ID,
},
[b1],
)?
.outputs_arr();
let xor2 = f_build.add_dataflow_op(and_op(), [b1, xor1.out_wire(0)])?;
f_build.finish_with_outputs([xor2.out_wire(0), b1])
},
&es,
"Copy multiple times",
)?;

Expand Down
3 changes: 2 additions & 1 deletion src/extension/infer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -648,11 +648,12 @@ impl UnificationContext {
fn search_variable_deps(&self) -> HashSet<Meta> {
let mut seen = HashSet::new();
let mut new_variables: HashSet<Meta> = self.variables.clone();
let constraints_for_solved = HashSet::new();
while !new_variables.is_empty() {
new_variables = new_variables
.into_iter()
.filter(|m| seen.insert(*m))
.flat_map(|m| self.get_constraints(&m).unwrap())
.flat_map(|m| self.get_constraints(&m).unwrap_or(&constraints_for_solved))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAICS solved constraints get removed here:

hugr/src/extension/infer.rs

Lines 633 to 635 in 6959c89

to_delete.iter().for_each(|m| {
self.constraints.remove(m);
});

so we have to handle them somehow. However I haven't looked into this all that hard so may have missed something @croyzor ?

.map(|c| match c {
Constraint::Plus(_, other) => self.resolve(*other),
Constraint::Equal(other) => self.resolve(*other),
Expand Down
29 changes: 15 additions & 14 deletions src/extension/op_def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ impl SignatureFunc {
///
/// This function will return an error if the type arguments are invalid or
/// there is some error in type computation.
pub fn compute_signature(
fn compute_signature(
&self,
def: &OpDef,
args: &[TypeArg],
Expand All @@ -245,10 +245,10 @@ impl SignatureFunc {
}
};

let res = pf.instantiate(args, exts)?;
// TODO bring this assert back once resource inference is done?
// https://github.com/CQCL/hugr/issues/388
// debug_assert!(res.extension_reqs.contains(def.extension()));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assert should stay in, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now the inner function, called by the outer which modifies the result to add the necessary extra Extension.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But, seems we can now just do it here. A lot has changed since this PR started!!

let mut res = pf.instantiate(args, exts)?;
res.extension_reqs = res
.extension_reqs
.union(&ExtensionSet::singleton(def.extension()));
Ok(res)
}
}
Expand Down Expand Up @@ -541,10 +541,10 @@ mod test {
let args = [TypeArg::BoundedNat { n: 3 }, USIZE_T.into()];
assert_eq!(
def.compute_signature(&args, &PRELUDE_REGISTRY),
Ok(FunctionType::new(
vec![USIZE_T; 3],
vec![Type::new_tuple(vec![USIZE_T; 3])]
))
Ok(
FunctionType::new(vec![USIZE_T; 3], vec![Type::new_tuple(vec![USIZE_T; 3])])
.with_extension_delta(&ExtensionSet::singleton(&EXT_ID))
)
);
assert_eq!(def.validate_args(&args, &PRELUDE_REGISTRY, &[]), Ok(()));

Expand All @@ -554,10 +554,10 @@ mod test {
let args = [TypeArg::BoundedNat { n: 3 }, tyvar.clone().into()];
assert_eq!(
def.compute_signature(&args, &PRELUDE_REGISTRY),
Ok(FunctionType::new(
tyvars.clone(),
vec![Type::new_tuple(tyvars)]
))
Ok(
FunctionType::new(tyvars.clone(), vec![Type::new_tuple(tyvars)])
.with_extension_delta(&ExtensionSet::singleton(&EXT_ID))
)
);
def.validate_args(&args, &PRELUDE_REGISTRY, &[TypeBound::Eq.into()])
.unwrap();
Expand Down Expand Up @@ -610,7 +610,8 @@ mod test {
def.validate_args(&args, &EMPTY_REG, &decls).unwrap();
assert_eq!(
def.compute_signature(&args, &EMPTY_REG),
Ok(FunctionType::new_endo(vec![tv]))
Ok(FunctionType::new_endo(vec![tv])
.with_extension_delta(&ExtensionSet::singleton(&EXT_ID)))
);
Ok(())
}
Expand Down
29 changes: 23 additions & 6 deletions src/hugr/rewrite/replace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -477,12 +477,11 @@ mod test {
.unwrap()
.into();
let just_list = TypeRow::from(vec![listy.clone()]);
let exset = ExtensionSet::singleton(&collections::EXTENSION_NAME);
let intermed = TypeRow::from(vec![listy.clone(), USIZE_T]);

let mut cfg = CFGBuilder::new(
// One might expect an extension_delta of "collections" here, but push/pop
// have an empty delta themselves, pending https://github.com/CQCL/hugr/issues/388
FunctionType::new_endo(just_list.clone()),
FunctionType::new_endo(just_list.clone()).with_extension_delta(&exset),
)?;

let pred_const = cfg.add_constant(ops::Const::unary_unit_sum())?;
Expand Down Expand Up @@ -628,13 +627,31 @@ mod test {
},
op_sig.input()
);
h.simple_entry_builder(op_sig.output, 1, op_sig.extension_reqs.clone())?
h.simple_entry_builder(op_sig.output.clone(), 1, op_sig.extension_reqs.clone())?
} else {
h.simple_block_builder(op_sig, 1)?
h.simple_block_builder(op_sig.clone(), 1)?
};
let op: OpType = op.into();
let op = bb.add_dataflow_op(op, bb.input_wires())?;
let load_pred = bb.load_const(pred_const)?;
let mut load_pred = bb.load_const(pred_const)?;
let const_ty = bb
.hugr()
.get_optype(pred_const.node())
.as_const()
.unwrap()
.const_type()
.clone();
for e in op_sig.extension_reqs.iter() {
[load_pred] = bb
.add_dataflow_op(
LeafOp::Lift {
type_row: vec![const_ty.clone()].into(),
new_extension: e.clone(),
},
[load_pred],
)?
.outputs_arr();
}
bb.finish_with_outputs(load_pred, op.outputs())
}

Expand Down
11 changes: 7 additions & 4 deletions src/hugr/rewrite/simple_replace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ pub(in crate::hugr::rewrite) mod test {
HugrBuilder, ModuleBuilder,
};
use crate::extension::prelude::BOOL_T;
use crate::extension::{EMPTY_REG, PRELUDE_REGISTRY};
use crate::extension::{ExtensionSet, EMPTY_REG, PRELUDE_REGISTRY};
use crate::hugr::views::{HugrView, SiblingSubgraph};
use crate::hugr::{Hugr, HugrMut, Rewrite};
use crate::ops::dataflow::DataflowOpTrait;
Expand All @@ -230,7 +230,7 @@ pub(in crate::hugr::rewrite) mod test {
use crate::std_extensions::logic::test::and_op;
use crate::type_row;
use crate::types::{FunctionType, Type};
use crate::utils::test_quantum_extension::{cx_gate, h_gate};
use crate::utils::test_quantum_extension::{cx_gate, h_gate, EXTENSION_ID};
use crate::{IncomingPort, Node};

use super::SimpleReplacement;
Expand All @@ -249,17 +249,20 @@ pub(in crate::hugr::rewrite) mod test {
fn make_hugr() -> Result<Hugr, BuildError> {
let mut module_builder = ModuleBuilder::new();
let _f_id = {
let delta = ExtensionSet::singleton(&EXTENSION_ID);
let mut func_builder = module_builder.define_function(
"main",
FunctionType::new(type_row![QB, QB, QB], type_row![QB, QB, QB]).into(),
FunctionType::new_endo(type_row![QB, QB, QB])
.with_extension_delta(&delta)
.into(),
)?;

let [qb0, qb1, qb2] = func_builder.input_wires_arr();

let q_out = func_builder.add_dataflow_op(h_gate(), vec![qb2])?;

let mut inner_builder = func_builder.dfg_builder(
FunctionType::new(type_row![QB, QB], type_row![QB, QB]),
FunctionType::new_endo(type_row![QB, QB]).with_extension_delta(&delta),
None,
[qb0, qb1],
)?;
Expand Down
18 changes: 11 additions & 7 deletions src/hugr/validate/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::macros::const_extension_ids;
use crate::ops::dataflow::IOTrait;
use crate::ops::{self, Const, LeafOp, OpType};
use crate::std_extensions::logic::test::{and_op, or_op};
use crate::std_extensions::logic::{self, NotOp};
use crate::std_extensions::logic::{self, NotOp, EXTENSION_ID};
use crate::types::type_param::{TypeArg, TypeArgError, TypeParam};
use crate::types::{CustomType, FunctionType, PolyFuncType, Type, TypeBound, TypeRow};
use crate::values::Value;
Expand Down Expand Up @@ -360,17 +360,18 @@ fn cfg_children_restrictions() {

#[test]
fn test_ext_edge() -> Result<(), HugrError> {
let mut h = closed_dfg_root_hugr(FunctionType::new(
type_row![BOOL_T, BOOL_T],
type_row![BOOL_T],
));
let delta = ExtensionSet::singleton(&EXTENSION_ID);
let mut h = closed_dfg_root_hugr(
FunctionType::new(type_row![BOOL_T, BOOL_T], type_row![BOOL_T])
.with_extension_delta(&delta),
);
let [input, output] = h.get_io(h.root()).unwrap();

// Nested DFG BOOL_T -> BOOL_T
let sub_dfg = h.add_node_with_parent(
h.root(),
ops::DFG {
signature: FunctionType::new_endo(type_row![BOOL_T]),
signature: FunctionType::new_endo(type_row![BOOL_T]).with_extension_delta(&delta),
},
)?;
// this Xor has its 2nd input unconnected
Expand Down Expand Up @@ -411,7 +412,10 @@ const_extension_ids! {

#[test]
fn test_local_const() -> Result<(), HugrError> {
let mut h = closed_dfg_root_hugr(FunctionType::new(type_row![BOOL_T], type_row![BOOL_T]));
let mut h = closed_dfg_root_hugr(
FunctionType::new_endo(type_row![BOOL_T])
.with_extension_delta(&ExtensionSet::singleton(&EXTENSION_ID)),
);
let [input, output] = h.get_io(h.root()).unwrap();
let and = h.add_node_with_parent(h.root(), and_op())?;
h.connect(input, 0, and, 0)?;
Expand Down
Loading