Skip to content

Commit f4ac585

Browse files
committed
Update to hugr 0.20
1 parent 6d2568a commit f4ac585

File tree

6 files changed

+38
-50
lines changed

6 files changed

+38
-50
lines changed

tket2-exts/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,4 @@ repository = "https://github.com/CQCL/tket2/tree/main/tket2-exts"
3434

3535
[build-system]
3636
requires = ["hatchling"]
37-
build-backend = "hatchling.build"
37+
build-backend = "hatchling.build"

tket2/src/serialize/pytket.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ pub enum OpConvertError<N = hugr::Node> {
260260
args: Vec<ElementId>,
261261
},
262262
/// A node parameter output could not be evaluated.
263-
#[display("Could not compute output parameter #{out_index} for operation {} given inputs [{}].", op.name(), params.iter().join(", "))]
263+
#[display("Could not compute output parameter #{out_index} for operation {op} given inputs [{}].", params.iter().join(", "))]
264264
CannotComputeParams {
265265
/// The operation being encoded
266266
op: OpType,

tket2/src/serialize/pytket/encoder.rs

Lines changed: 17 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@ pub use config::{default_encoder_config, Tk1EncoderConfig};
99
use hugr::envelope::EnvelopeConfig;
1010
use hugr::hugr::views::SiblingSubgraph;
1111
use hugr::package::Package;
12+
use hugr_core::hugr::internal::PortgraphNodeMap;
1213
pub use value_tracker::{
1314
RegisterCount, TrackedBit, TrackedParam, TrackedQubit, TrackedValue, TrackedValues,
1415
ValueTracker,
1516
};
1617

17-
use hugr::ops::{NamedOp, OpTrait, OpType};
18+
use hugr::ops::{OpTrait, OpType};
1819
use hugr::types::EdgeKind;
1920

2021
use std::borrow::Cow;
@@ -23,8 +24,6 @@ use std::sync::Arc;
2324

2425
use hugr::{HugrView, Wire};
2526
use itertools::Itertools;
26-
use portgraph::algorithms::TopoSort;
27-
use portgraph::LinkView;
2827
use tket_json_rs::circuit_json::{self, SerialCircuit};
2928
use unsupported_tracker::UnsupportedTracker;
3029

@@ -93,34 +92,15 @@ impl<H: HugrView> Tk1EncoderContext<H> {
9392
) -> Result<(), Tk1ConvertError<H::Node>> {
9493
// Normally we'd use `SiblingGraph` here, but it doesn't support generic node types.
9594
// See https://github.com/CQCL/hugr/issues/2010
96-
let hugr = circ.hugr();
97-
let root = circ.parent();
98-
let portgraph = hugr.portgraph();
99-
let hierarchy = hugr.hierarchy();
100-
let region =
101-
portgraph::view::FlatRegion::new(&portgraph, &hierarchy, hugr.get_pg_index(root));
102-
103-
// Collect all initial nodes in the region (nodes with no predecessors).
104-
let initials: Vec<_> = hugr
105-
.children(root)
106-
.filter_map(|node| {
107-
let pg_node = hugr.get_pg_index(node);
108-
region
109-
.input_links(pg_node)
110-
.next()
111-
.is_none()
112-
.then_some(pg_node)
113-
})
114-
.collect();
115-
116-
let topo: TopoSort<'_, _, HashSet<_>> =
117-
portgraph::algorithms::toposort(region, initials, portgraph::Direction::Outgoing);
95+
let (region, node_map) = circ.hugr().region_portgraph(circ.parent());
11896
let io_nodes = circ.io_nodes();
97+
11998
// TODO: Use weighted topological sort to try and explore unsupported
12099
// ops first (that is, ops with no available emitter in `self.config`),
121100
// to ensure we group them as much as possible.
122-
for pg_node in topo {
123-
let node = hugr.get_node(pg_node);
101+
let mut topo = petgraph::visit::Topo::new(&region);
102+
while let Some(pg_node) = topo.next(&region) {
103+
let node = node_map.from_portgraph(pg_node);
124104
if io_nodes.contains(&node) {
125105
// I/O nodes are handled by `new` and `finish`.
126106
continue;
@@ -310,7 +290,7 @@ impl<H: HugrView> Tk1EncoderContext<H> {
310290
tk1_optype: tket_json_rs::OpType,
311291
node: H::Node,
312292
circ: &Circuit<H>,
313-
output_params: impl FnOnce(OutputParamArgs) -> Vec<String>,
293+
output_params: impl FnOnce(OutputParamArgs<'_>) -> Vec<String>,
314294
) -> Result<(), Tk1ConvertError<H::Node>> {
315295
self.emit_node_command(
316296
node,
@@ -345,7 +325,7 @@ impl<H: HugrView> Tk1EncoderContext<H> {
345325
&mut self,
346326
node: H::Node,
347327
circ: &Circuit<H>,
348-
output_params: impl FnOnce(OutputParamArgs) -> Vec<String>,
328+
output_params: impl FnOnce(OutputParamArgs<'_>) -> Vec<String>,
349329
make_operation: impl FnOnce(usize, usize, &[String]) -> tket_json_rs::circuit_json::Operation,
350330
) -> Result<(), Tk1ConvertError<H::Node>> {
351331
let TrackedValues {
@@ -411,7 +391,7 @@ impl<H: HugrView> Tk1EncoderContext<H> {
411391
&mut self,
412392
node: H::Node,
413393
circ: &Circuit<H>,
414-
output_params: impl FnOnce(OutputParamArgs) -> Vec<String>,
394+
output_params: impl FnOnce(OutputParamArgs<'_>) -> Vec<String>,
415395
) -> Result<(), Tk1ConvertError<H::Node>> {
416396
let input_values = self.get_input_values(node, circ)?;
417397
let output_counts = self.node_output_values(node, circ)?;
@@ -432,23 +412,23 @@ impl<H: HugrView> Tk1EncoderContext<H> {
432412
if input_values.qubits.len() != total_out_count.qubits {
433413
return Err(Tk1ConvertError::custom(format!(
434414
"Mismatched number of input and output qubits while trying to emit a transparent operation for {}. We have {} inputs but {} outputs.",
435-
circ.hugr().get_optype(node).name(),
415+
circ.hugr().get_optype(node),
436416
input_values.qubits.len(),
437417
total_out_count.qubits,
438418
)));
439419
}
440420
if input_values.bits.len() != total_out_count.bits {
441421
return Err(Tk1ConvertError::custom(format!(
442422
"Mismatched number of input and output bits while trying to emit a transparent operation for {}. We have {} inputs but {} outputs.",
443-
circ.hugr().get_optype(node).name(),
423+
circ.hugr().get_optype(node),
444424
input_values.bits.len(),
445425
total_out_count.bits,
446426
)));
447427
}
448428
if out_params.len() != total_out_count.params {
449429
return Err(Tk1ConvertError::custom(format!(
450430
"Not enough parameters in the input values for a {}. Expected {} but got {}.",
451-
circ.hugr().get_optype(node).name(),
431+
circ.hugr().get_optype(node),
452432
total_out_count.params,
453433
out_params.len()
454434
)));
@@ -506,7 +486,6 @@ impl<H: HugrView> Tk1EncoderContext<H> {
506486

507487
let unsupported_hugr = subgraph.extract_subgraph(circ.hugr(), &subcircuit_id);
508488
let payload = Package::from_hugr(unsupported_hugr)
509-
.unwrap()
510489
.store_str(EnvelopeConfig::text())
511490
.unwrap();
512491

@@ -677,7 +656,7 @@ impl<H: HugrView> Tk1EncoderContext<H> {
677656
circ: &Circuit<H>,
678657
qubits: &mut impl Iterator<Item = TrackedQubit>,
679658
input_params: &[String],
680-
output_params: impl FnOnce(OutputParamArgs) -> Vec<String>,
659+
output_params: impl FnOnce(OutputParamArgs<'_>) -> Vec<String>,
681660
wire_filter: impl Fn(Wire<H::Node>) -> bool,
682661
) -> Result<TrackedValues, Tk1ConvertError<H::Node>> {
683662
let output_counts = self.node_output_values(node, circ)?;
@@ -693,7 +672,7 @@ impl<H: HugrView> Tk1EncoderContext<H> {
693672
if out_params.len() != total_out_count.params {
694673
return Err(Tk1ConvertError::custom(format!(
695674
"Not enough parameters in the input values for a {}. Expected {} but got {}.",
696-
circ.hugr().get_optype(node).name(),
675+
circ.hugr().get_optype(node),
697676
total_out_count.params,
698677
out_params.len()
699678
)));
@@ -752,8 +731,7 @@ impl<H: HugrView> Tk1EncoderContext<H> {
752731
} else if Some(out_port) == static_output {
753732
let EdgeKind::Const(ty) = op.static_output().unwrap() else {
754733
return Err(Tk1ConvertError::custom(format!(
755-
"Cannot emit a static output for a {}.",
756-
op.name()
734+
"Cannot emit a static output for a {op}."
757735
)));
758736
};
759737
ty
@@ -772,8 +750,7 @@ impl<H: HugrView> Tk1EncoderContext<H> {
772750
let wire = hugr::Wire::new(node, out_port);
773751
let Some(count) = self.config().type_to_pytket(&ty)? else {
774752
return Err(Tk1ConvertError::custom(format!(
775-
"Found an unsupported type while encoding a {}.",
776-
op.name()
753+
"Found an unsupported type while encoding a {op}."
777754
)));
778755
};
779756
wire_counts.push((wire, count));

tket2/src/serialize/pytket/encoder/config.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::collections::{BTreeSet, HashMap, VecDeque};
77

88
use hugr::extension::{ExtensionId, ExtensionSet};
99
use hugr::ops::{ExtensionOp, Value};
10-
use hugr::types::{SumType, Type, TypeEnum};
10+
use hugr::types::{Signature, SumType, Type, TypeEnum};
1111

1212
use crate::serialize::pytket::extension::{
1313
FloatEmitter, PreludeEmitter, RotationEmitter, Tk1Emitter, Tk2Emitter,
@@ -182,9 +182,19 @@ impl<H: HugrView> Tk1EncoderConfig<H> {
182182
}
183183
}
184184
Value::Extension { e: opaque } => {
185-
let type_exts = opaque.extension_reqs();
185+
// Collect all extensions required to define the type.
186+
let typ = opaque.value().get_type();
187+
// TODO: Use Type::used_extensions once it gets published.
188+
// See <https://github.com/CQCL/hugr/pull/2224>
189+
let type_exts = Signature::new(vec![], vec![typ])
190+
.used_extensions()
191+
.unwrap_or_else(|e| {
192+
panic!("Tried to encode a type with partially extension. {e}");
193+
});
194+
let exts_set = ExtensionSet::from_iter(type_exts.ids().cloned());
195+
186196
let mut encoded = false;
187-
for e in self.emitters_for_extensions(&type_exts) {
197+
for e in self.emitters_for_extensions(&exts_set) {
188198
if let Some(vs) = e.const_to_pytket(opaque, encoder)? {
189199
values.append(vs);
190200
encoded = true;

tket2/src/serialize/pytket/extension/tk1.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
//! Encoder for pytket operations that cannot be represented naturally in tket2.
22
3-
use hugr::extension::prelude::{bool_t, qb_t};
4-
53
use crate::extension::rotation::rotation_type;
64
use crate::extension::{TKET1_EXTENSION, TKET1_EXTENSION_ID, TKET1_OP_NAME};
75
use crate::serialize::pytket::{Tk1ConvertError, Tk1EncoderContext};
@@ -10,7 +8,7 @@ use crate::Circuit;
108
use super::PytketEmitter;
119
use hugr::extension::prelude::{bool_t, qb_t};
1210
use hugr::extension::ExtensionId;
13-
use hugr::ops::{ExtensionOp, NamedOp};
11+
use hugr::ops::ExtensionOp;
1412
use hugr::types::{Signature, TypeArg};
1513
use hugr::{HugrView, IncomingPort};
1614
use tket_json_rs::circuit_json;
@@ -35,7 +33,7 @@ impl<H: HugrView> PytketEmitter<H> for Tk1Emitter {
3533
circ: &Circuit<H>,
3634
encoder: &mut Tk1EncoderContext<H>,
3735
) -> Result<bool, Tk1ConvertError<H::Node>> {
38-
if op.name() != format!("{TKET1_EXTENSION_ID}.{TKET1_OP_NAME}") {
36+
if op.qualified_id() != format!("{TKET1_EXTENSION_ID}.{TKET1_OP_NAME}") {
3937
return Ok(false);
4038
}
4139
let Some(TypeArg::String { arg }) = op.args().first() else {

tket2/src/serialize/pytket/tests.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,12 @@ fn compare_serial_circs(a: &SerialCircuit, b: &SerialCircuit) {
118118
assert_eq!(a.name, b.name);
119119
assert_eq!(a.phase, b.phase);
120120
assert_eq!(&a.qubits, &b.qubits);
121-
assert_eq!(&a.bits, &b.bits);
122121
assert_eq!(a.commands.len(), b.commands.len());
123122

123+
let bits_a: HashSet<_> = a.bits.iter().collect();
124+
let bits_b: HashSet<_> = b.bits.iter().collect();
125+
assert_eq!(bits_a, bits_b);
126+
124127
// We ignore the commands order here, as two encodings may swap
125128
// non-dependant operations.
126129
//

0 commit comments

Comments
 (0)