Skip to content

feat!: Allow making (and sharing) new FuncDecls in linearization #2108

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

Draft
wants to merge 21 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
4db3f5d
ci: Run ci checks on PRs to any branch
aborgna-q Apr 15, 2025
209b2ea
Merge branch 'main' into release-rs-v0.16.0
aborgna-q Apr 15, 2025
81447ec
feat!: Allow generic Nodes in HugrMut insert operations (#2075)
aborgna-q Apr 15, 2025
ef1cba0
fix!: Don't expose `HugrMutInternals` (#2071)
aborgna-q Apr 15, 2025
fac6c8b
feat!: Mark all Error enums as non_exhaustive (#2056)
aborgna-q Apr 15, 2025
baaca02
feat!: Handle CallIndirect in Dataflow Analysis (#2059)
acl-cqc Apr 16, 2025
195f30c
Merge branch 'main' into release-rs-v0.16.0
aborgna-q Apr 16, 2025
6347756
feat: Make NodeHandle generic (#2092)
aborgna-q Apr 16, 2025
5b43c0d
feat!: remove ExtensionValue (#2093)
ss2165 Apr 17, 2025
89c2680
feat!: ComposablePass trait allowing sequencing and validation (#1895)
acl-cqc Apr 22, 2025
d8a5d67
feat!: ReplaceTypes: allow lowering ops into a Call to a function alr…
acl-cqc Apr 23, 2025
2430f56
(breaking) callback takes &mut CallbackHandler
acl-cqc Apr 9, 2025
15f4467
rm trait Linearizer, CallbackHandler stores cache and (alone) provide…
acl-cqc Apr 23, 2025
28ac1b1
Tidy up, moving copy_discard_op
acl-cqc Apr 23, 2025
bcd01dc
Merge commit 'd8a5d679' into HEAD
acl-cqc Apr 23, 2025
7a1d2b0
Define replace_types::CallbackHandler similarly, duplicate create_fun…
acl-cqc Apr 23, 2025
abc037f
Missing doc...needs more updates
acl-cqc Apr 23, 2025
42daba5
Combine the two CallbackHandler structs by (erm...) deref
acl-cqc Apr 25, 2025
cb2e138
separate get_function from make_function, removing callback
acl-cqc Apr 25, 2025
1ac57a5
Generalize test to check lazy too
acl-cqc Apr 25, 2025
d073f35
clippy
acl-cqc Apr 25, 2025
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
2 changes: 1 addition & 1 deletion hugr-core/src/builder/build_traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ pub trait Container {
}

/// Insert a copy of a HUGR as a child of the container.
fn add_hugr_view(&mut self, child: &impl HugrView) -> InsertionResult {
fn add_hugr_view<H: HugrView>(&mut self, child: &H) -> InsertionResult<H::Node, Node> {
let parent = self.container_node();
self.hugr_mut().insert_from_view(parent, child)
}
Expand Down
65 changes: 2 additions & 63 deletions hugr-core/src/extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@ use derive_more::Display;
use thiserror::Error;

use crate::hugr::IdentList;
use crate::ops::constant::{ValueName, ValueNameRef};
use crate::ops::custom::{ExtensionOp, OpaqueOp};
use crate::ops::{self, OpName, OpNameRef};
use crate::ops::{OpName, OpNameRef};
use crate::types::type_param::{TypeArg, TypeArgError, TypeParam};
use crate::types::RowVariable;
use crate::types::{check_typevar_decl, CustomType, Substitution, TypeBound, TypeName};
Expand Down Expand Up @@ -378,6 +377,7 @@ pub static EMPTY_REG: ExtensionRegistry = ExtensionRegistry {
/// TODO: decide on failure modes
#[derive(Debug, Clone, Error, PartialEq, Eq)]
#[allow(missing_docs)]
#[non_exhaustive]
pub enum SignatureError {
/// Name mismatch
#[error("Definition name ({0}) and instantiation name ({1}) do not match.")]
Expand Down Expand Up @@ -496,37 +496,6 @@ impl CustomConcrete for CustomType {
}
}

/// A constant value provided by a extension.
/// Must be an instance of a type available to the extension.
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct ExtensionValue {
extension: ExtensionId,
name: ValueName,
typed_value: ops::Value,
}

impl ExtensionValue {
/// Returns a reference to the typed value of this [`ExtensionValue`].
pub fn typed_value(&self) -> &ops::Value {
&self.typed_value
}

/// Returns a mutable reference to the typed value of this [`ExtensionValue`].
pub(super) fn typed_value_mut(&mut self) -> &mut ops::Value {
&mut self.typed_value
}

/// Returns a reference to the name of this [`ExtensionValue`].
pub fn name(&self) -> &str {
self.name.as_str()
}

/// Returns a reference to the extension this [`ExtensionValue`] belongs to.
pub fn extension(&self) -> &ExtensionId {
&self.extension
}
}

/// A unique identifier for a extension.
///
/// The actual [`Extension`] is stored externally.
Expand Down Expand Up @@ -582,8 +551,6 @@ pub struct Extension {
pub runtime_reqs: ExtensionSet,
/// Types defined by this extension.
types: BTreeMap<TypeName, TypeDef>,
/// Static values defined by this extension.
values: BTreeMap<ValueName, ExtensionValue>,
/// Operation declarations with serializable definitions.
// Note: serde will serialize this because we configure with `features=["rc"]`.
// That will clone anything that has multiple references, but each
Expand All @@ -607,7 +574,6 @@ impl Extension {
version,
runtime_reqs: Default::default(),
types: Default::default(),
values: Default::default(),
operations: Default::default(),
}
}
Expand Down Expand Up @@ -679,11 +645,6 @@ impl Extension {
self.types.get(type_name)
}

/// Allows read-only access to the values in this Extension
pub fn get_value(&self, value_name: &ValueNameRef) -> Option<&ExtensionValue> {
self.values.get(value_name)
}

/// Returns the name of the extension.
pub fn name(&self) -> &ExtensionId {
&self.name
Expand All @@ -704,25 +665,6 @@ impl Extension {
self.types.iter()
}

/// Add a named static value to the extension.
pub fn add_value(
&mut self,
name: impl Into<ValueName>,
typed_value: ops::Value,
) -> Result<&mut ExtensionValue, ExtensionBuildError> {
let extension_value = ExtensionValue {
extension: self.name.clone(),
name: name.into(),
typed_value,
};
match self.values.entry(extension_value.name.clone()) {
btree_map::Entry::Occupied(_) => {
Err(ExtensionBuildError::ValueExists(extension_value.name))
}
btree_map::Entry::Vacant(ve) => Ok(ve.insert(extension_value)),
}
}

/// Instantiate an [`ExtensionOp`] which references an [`OpDef`] in this extension.
pub fn instantiate_extension_op(
&self,
Expand Down Expand Up @@ -783,9 +725,6 @@ pub enum ExtensionBuildError {
/// Existing [`TypeDef`]
#[error("Extension already has an type called {0}.")]
TypeDefExists(TypeName),
/// Existing [`ExtensionValue`]
#[error("Extension already has an extension value called {0}.")]
ValueExists(ValueName),
}

/// A set of extensions identified by their unique [`ExtensionId`].
Expand Down
11 changes: 2 additions & 9 deletions hugr-core/src/extension/resolution/extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::sync::Arc;

use crate::extension::{Extension, ExtensionId, ExtensionRegistry, OpDef, SignatureFunc, TypeDef};

use super::types_mut::{resolve_signature_exts, resolve_value_exts};
use super::types_mut::resolve_signature_exts;
use super::{ExtensionResolutionError, WeakExtensionRegistry};

impl ExtensionRegistry {
Expand Down Expand Up @@ -59,14 +59,7 @@ impl Extension {
for type_def in self.types.values_mut() {
resolve_typedef_exts(&self.name, type_def, extensions, &mut used_extensions)?;
}
for val in self.values.values_mut() {
resolve_value_exts(
None,
val.typed_value_mut(),
extensions,
&mut used_extensions,
)?;
}

let ops = mem::take(&mut self.operations);
for (op_id, mut op_def) in ops {
// TODO: We should be able to clone the definition if needed by using `make_mut`,
Expand Down
114 changes: 73 additions & 41 deletions hugr-core/src/hugr/hugrmut.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
//! Low-level interface for modifying a HUGR.

use core::panic;
use std::collections::{BTreeMap, HashMap};
use std::collections::{BTreeMap, HashMap, HashSet};
use std::sync::Arc;

use portgraph::view::{NodeFilter, NodeFiltered};
use portgraph::{LinkMut, PortMut, PortView, SecondaryMap};

use crate::core::HugrNode;
use crate::extension::ExtensionRegistry;
use crate::hugr::internal::HugrInternals;
use crate::hugr::views::SiblingSubgraph;
use crate::hugr::{HugrView, Node, OpType, RootTagged};
use crate::hugr::{NodeMetadata, Rewrite};
Expand Down Expand Up @@ -162,10 +164,10 @@ pub trait HugrMut: HugrMutInternals {
/// correspondingly for `Dom` edges)
fn copy_descendants(
&mut self,
root: Node,
new_parent: Node,
root: Self::Node,
new_parent: Self::Node,
subst: Option<Substitution>,
) -> BTreeMap<Node, Node> {
) -> BTreeMap<Self::Node, Self::Node> {
panic_invalid_node(self, root);
panic_invalid_node(self, new_parent);
self.hugr_mut().copy_descendants(root, new_parent, subst)
Expand Down Expand Up @@ -225,7 +227,7 @@ pub trait HugrMut: HugrMutInternals {
///
/// If the root node is not in the graph.
#[inline]
fn insert_hugr(&mut self, root: Node, other: Hugr) -> InsertionResult {
fn insert_hugr(&mut self, root: Self::Node, other: Hugr) -> InsertionResult<Node, Self::Node> {
panic_invalid_node(self, root);
self.hugr_mut().insert_hugr(root, other)
}
Expand All @@ -236,7 +238,11 @@ pub trait HugrMut: HugrMutInternals {
///
/// If the root node is not in the graph.
#[inline]
fn insert_from_view(&mut self, root: Node, other: &impl HugrView) -> InsertionResult {
fn insert_from_view<H: HugrView>(
&mut self,
root: Self::Node,
other: &H,
) -> InsertionResult<H::Node, Self::Node> {
panic_invalid_node(self, root);
self.hugr_mut().insert_from_view(root, other)
}
Expand All @@ -255,12 +261,12 @@ pub trait HugrMut: HugrMutInternals {
// TODO: Try to preserve the order when possible? We cannot always ensure
// it, since the subgraph may have arbitrary nodes without including their
// parent.
fn insert_subgraph(
fn insert_subgraph<H: HugrView>(
&mut self,
root: Node,
other: &impl HugrView,
subgraph: &SiblingSubgraph,
) -> HashMap<Node, Node> {
root: Self::Node,
other: &H,
subgraph: &SiblingSubgraph<H::Node>,
) -> HashMap<H::Node, Self::Node> {
panic_invalid_node(self, root);
self.hugr_mut().insert_subgraph(root, other, subgraph)
}
Expand Down Expand Up @@ -307,20 +313,32 @@ pub trait HugrMut: HugrMutInternals {

/// Records the result of inserting a Hugr or view
/// via [HugrMut::insert_hugr] or [HugrMut::insert_from_view].
pub struct InsertionResult {
///
/// Contains a map from the nodes in the source HUGR to the nodes in the
/// target HUGR, using their respective `Node` types.
pub struct InsertionResult<SourceN = Node, TargetN = Node> {
/// The node, after insertion, that was the root of the inserted Hugr.
///
/// That is, the value in [InsertionResult::node_map] under the key that was the [HugrView::root]
pub new_root: Node,
pub new_root: TargetN,
/// Map from nodes in the Hugr/view that was inserted, to their new
/// positions in the Hugr into which said was inserted.
pub node_map: HashMap<Node, Node>,
pub node_map: HashMap<SourceN, TargetN>,
}

fn translate_indices(
/// Translate a portgraph node index map into a map from nodes in the source
/// HUGR to nodes in the target HUGR.
///
/// This is as a helper in `insert_hugr` and `insert_subgraph`, where the source
/// HUGR may be an arbitrary `HugrView` with generic node types.
fn translate_indices<N: HugrNode>(
mut source_node: impl FnMut(portgraph::NodeIndex) -> N,
mut target_node: impl FnMut(portgraph::NodeIndex) -> Node,
node_map: HashMap<portgraph::NodeIndex, portgraph::NodeIndex>,
) -> impl Iterator<Item = (Node, Node)> {
node_map.into_iter().map(|(k, v)| (k.into(), v.into()))
) -> impl Iterator<Item = (N, Node)> {
node_map
.into_iter()
.map(move |(k, v)| (source_node(k), target_node(v)))
}

/// Impl for non-wrapped Hugrs. Overwrites the recursive default-impls to directly use the hugr.
Expand Down Expand Up @@ -406,7 +424,11 @@ impl<T: RootTagged<RootHandle = Node, Node = Node> + AsMut<Hugr>> HugrMut for T
(src_port, dst_port)
}

fn insert_hugr(&mut self, root: Node, mut other: Hugr) -> InsertionResult {
fn insert_hugr(
&mut self,
root: Self::Node,
mut other: Hugr,
) -> InsertionResult<Node, Self::Node> {
let (new_root, node_map) = insert_hugr_internal(self.as_mut(), root, &other);
// Update the optypes and metadata, taking them from the other graph.
//
Expand All @@ -423,11 +445,16 @@ impl<T: RootTagged<RootHandle = Node, Node = Node> + AsMut<Hugr>> HugrMut for T
);
InsertionResult {
new_root,
node_map: translate_indices(node_map).collect(),
node_map: translate_indices(|n| other.get_node(n), |n| self.get_node(n), node_map)
.collect(),
}
}

fn insert_from_view(&mut self, root: Node, other: &impl HugrView) -> InsertionResult {
fn insert_from_view<H: HugrView>(
&mut self,
root: Self::Node,
other: &H,
) -> InsertionResult<H::Node, Self::Node> {
let (new_root, node_map) = insert_hugr_internal(self.as_mut(), root, other);
// Update the optypes and metadata, copying them from the other graph.
//
Expand All @@ -444,22 +471,28 @@ impl<T: RootTagged<RootHandle = Node, Node = Node> + AsMut<Hugr>> HugrMut for T
);
InsertionResult {
new_root,
node_map: translate_indices(node_map).collect(),
node_map: translate_indices(|n| other.get_node(n), |n| self.get_node(n), node_map)
.collect(),
}
}

fn insert_subgraph(
fn insert_subgraph<H: HugrView>(
&mut self,
root: Node,
other: &impl HugrView,
subgraph: &SiblingSubgraph,
) -> HashMap<Node, Node> {
root: Self::Node,
other: &H,
subgraph: &SiblingSubgraph<H::Node>,
) -> HashMap<H::Node, Self::Node> {
// Create a portgraph view with the explicit list of nodes defined by the subgraph.
let portgraph: NodeFiltered<_, NodeFilter<&[Node]>, &[Node]> =
let context: HashSet<portgraph::NodeIndex> = subgraph
.nodes()
.iter()
.map(|&n| other.get_pg_index(n))
.collect();
let portgraph: NodeFiltered<_, NodeFilter<HashSet<portgraph::NodeIndex>>, _> =
NodeFiltered::new_node_filtered(
other.portgraph(),
|node, ctx| ctx.contains(&node.into()),
subgraph.nodes(),
|node, ctx| ctx.contains(&node),
context,
);
let node_map = insert_subgraph_internal(self.as_mut(), root, other, &portgraph);
// Update the optypes and metadata, copying them from the other graph.
Expand All @@ -473,25 +506,24 @@ impl<T: RootTagged<RootHandle = Node, Node = Node> + AsMut<Hugr>> HugrMut for T
self.use_extensions(exts);
}
}
translate_indices(node_map).collect()
translate_indices(|n| other.get_node(n), |n| self.get_node(n), node_map).collect()
}

fn copy_descendants(
&mut self,
root: Node,
new_parent: Node,
root: Self::Node,
new_parent: Self::Node,
subst: Option<Substitution>,
) -> BTreeMap<Node, Node> {
) -> BTreeMap<Self::Node, Self::Node> {
let mut descendants = self.base_hugr().hierarchy.descendants(root.pg_index());
let root2 = descendants.next();
debug_assert_eq!(root2, Some(root.pg_index()));
let nodes = Vec::from_iter(descendants);
let node_map = translate_indices(
portgraph::view::Subgraph::with_nodes(&mut self.as_mut().graph, nodes)
.copy_in_parent()
.expect("Is a MultiPortGraph"),
)
.collect::<BTreeMap<_, _>>();
let node_map = portgraph::view::Subgraph::with_nodes(&mut self.as_mut().graph, nodes)
.copy_in_parent()
.expect("Is a MultiPortGraph");
let node_map = translate_indices(|n| self.get_node(n), |n| self.get_node(n), node_map)
.collect::<BTreeMap<_, _>>();

for node in self.children(root).collect::<Vec<_>>() {
self.set_parent(*node_map.get(&node).unwrap(), new_parent);
Expand Down Expand Up @@ -563,10 +595,10 @@ fn insert_hugr_internal<H: HugrView>(
/// sibling order in the hierarchy. This is due to the subgraph not necessarily
/// having a single root, so the logic for reconstructing the hierarchy is not
/// able to just do a BFS.
fn insert_subgraph_internal(
fn insert_subgraph_internal<N: HugrNode>(
hugr: &mut Hugr,
root: Node,
other: &impl HugrView,
other: &impl HugrView<Node = N>,
portgraph: &impl portgraph::LinkView,
) -> HashMap<portgraph::NodeIndex, portgraph::NodeIndex> {
let node_map = hugr
Expand Down
1 change: 0 additions & 1 deletion hugr-core/src/hugr/rewrite/simple_replace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use std::collections::HashMap;

use crate::core::HugrNode;
use crate::hugr::hugrmut::InsertionResult;
pub use crate::hugr::internal::HugrMutInternals;
use crate::hugr::views::SiblingSubgraph;
use crate::hugr::{HugrMut, HugrView, Rewrite};
use crate::ops::{OpTag, OpTrait, OpType};
Expand Down
1 change: 1 addition & 0 deletions hugr-core/src/hugr/serialize/upgrade.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use thiserror::Error;

#[derive(Debug, Error)]
#[non_exhaustive]
pub enum UpgradeError {
#[error(transparent)]
Deserialize(#[from] serde_json::Error),
Expand Down
Loading
Loading