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

feat!: Rewriter API + ECCRewriter #93

Merged
merged 16 commits into from
Sep 7, 2023
Merged

feat!: Rewriter API + ECCRewriter #93

merged 16 commits into from
Sep 7, 2023

Conversation

lmondada
Copy link
Contributor

@lmondada lmondada commented Sep 7, 2023

  • refactor!: Standardise ECC naming
  • feat: Add Subcircuit and move CircuitRewrite
  • refactor: CircuitMatch stores PatternID
  • feat: Add ECCRewriter

BREAKING CHANGE: RepCircSet is now EqCircClass.
BREAKING CHANGE: rep_sets_from_path is now load_eccs_json_file.
BREAKING CHANGE: CircuitMatch.pattern is now a PatternID instead of a reference and no longer
has a 'p pattern lifetime.
BREAKING CHANGE: CircuitRewrite was moved to ::rewrite.

@lmondada lmondada requested a review from cqc-alec September 7, 2023 07:13
@lmondada
Copy link
Contributor Author

lmondada commented Sep 7, 2023

I've broken the PR into commits that should help reviewing. Happy to break this into multiple PRs if you prefer.

Copy link
Collaborator

@cqc-alec cqc-alec left a comment

Choose a reason for hiding this comment

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

Looks good, just a few comments.

///
/// An ECC always has a representative circuit, so it will be of size at
/// least 1.
#[allow(clippy::len_without_is_empty)]
Copy link
Collaborator

Choose a reason for hiding this comment

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

I guess we could avoid having to suppress this warning by having an is_empty() that returns false. Or we could call this method something else e.g. n_others.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Renaming is a good option. I've chosen n_circuits.

circ: &'a C,
) -> Result<Self, InvalidCircuitMatch> {
let mut checker = ConvexChecker::new(circ);
Self::try_from_root_match_with_checker(root, pattern, circ, &mut checker)
Self::try_from_root_match_with_checker(root, pattern_id, pattern, circ, &mut checker)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Feels odd to be passing around both the pattern ID and the pattern; can the pattern be retrieved from the ID?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Mmmm, I agree that this is ugly. The problem is that the pattern ID is only unique to a CircuitMatcher object, so the alternative is to carry around a reference to a matcher.

I might break this into separate calls.

Comment on lines 45 to 46
/// Rewrites, stored as a map from PatternID to TargetIDs.
rewrite_rules: Vec<Vec<TargetID>>,
Copy link
Collaborator

Choose a reason for hiding this comment

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

This doesn't look like a map from PatternID to TargetIDs. Presumably the pattern ID is used as the index into the outer vector. Suggest rewording docstring.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes that's true, I've made this clearer.

//! generates rewrites to replace them with other circuits within the same
//! equivalence class.
//!
//! Equivalence classes are generated using Quartz.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should include a reference here.

impl ECCRewriter {
/// Create a new rewriter from equivalent circuit classes in JSON file.
///
/// This uses the Quartz JSON file format to store equivalent circuit classes.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Reference?

src/rewrite/ecc_rewriter.rs Outdated Show resolved Hide resolved
let all_hugrs = rep_sets.iter().flat_map(|rs| rs.circuits());
let all_circs = all_hugrs
.map(|hugr| SiblingGraph::<DfgID>::new(hugr, hugr.root()))
// TODO: collect to vec because of lifetime issues that should not exist
Copy link
Collaborator

Choose a reason for hiding this comment

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

What's the TODO? It seems we are collecting to vec ... is the TODO to not do this?

Copy link
Contributor Author

@lmondada lmondada Sep 7, 2023

Choose a reason for hiding this comment

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

Indeed, I meant the opposite. This is an issue that I'm unable to solve -- every time I try to refactor the relevant lifetime bounds it fails, so will leave this to someone more skilled than me.

I don't think this will be a bottleneck in terms of performance so I can also remove the TODO if you prefer, but I found it is reasonable to highlight this problem here. For the time being I've rephrased the TODO and made my point clearer.

@lmondada
Copy link
Contributor Author

lmondada commented Sep 7, 2023

Removing the duplicate PatternID and pattern reference in CircuitMatch::try_from_root_match proved to be a bit more intricate than expected.

The main code is definitely cleaner now, at the expense of slightly messier Python bindings. I think that's a fair tradeoff, especially given that the Python layer really is just a prototype at the moment.

EDIT: I also took the opportunity to rename CircuitMatch into PatternMatch.

@lmondada lmondada requested a review from cqc-alec September 7, 2023 12:48
src/portmatching/pyo3.rs Outdated Show resolved Hide resolved
Comment on lines 97 to 98
/// The incoming port boundary.
pub inputs: Vec<Vec<(Node, Port)>>,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Probably needs some more explanation in the doc as it's not obvious how a Vec<Vec<(Node, Port)>> corresponds to an incoming port boundary (nor why it's a different type from the outgoing boundary).

circ: &'a C,
) -> Result<Self, InvalidCircuitMatch> {
matcher: &CircuitMatcher,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should we rename this to PatternMatcher?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I guess everything in tket2 relates to circuits, so Circuit prefixes are generally redundant.

@lmondada lmondada requested a review from cqc-alec September 7, 2023 13:36
@lmondada lmondada merged commit f4ed814 into main Sep 7, 2023
7 checks passed
@lmondada lmondada deleted the feat/ecc-rewriter branch September 7, 2023 14:45
ss2165 pushed a commit that referenced this pull request Sep 7, 2023
- refactor!: Standardise ECC naming
- feat: Add Subcircuit and move CircuitRewrite
- refactor: CircuitMatch stores PatternID
- feat: Add ECCRewriter

BREAKING CHANGE: `CircuitMatch` is now `PatternMatch`, `CircuitMatcher` is now `PatternMatcher`.
BREAKING CHANGE: RepCircSet is now EqCircClass.
BREAKING CHANGE: rep_sets_from_path is now load_eccs_json_file.
BREAKING CHANGE: CircuitMatch.pattern is now a PatternID instead of a
reference and no longer
has a 'p pattern lifetime.
BREAKING CHANGE: CircuitRewrite was moved to ::rewrite.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants