Skip to content

Conversation

@antalsz
Copy link
Contributor

@antalsz antalsz commented Oct 12, 2025

This PR removes the InstructionHandler type that is defined in terms of boxed closures, and replaces it with an InstructionHandler trait. This has the potential to provide signficant performance improvements (and I think it's probably cleaner regardless).

This PR also removes every Rust method that could use InstructionHandler but doesn't, requiring a deliberate use of an instruction handler. However, because we don't expose instruction handlers to Python, this is not true for our Python bindings. Ideally, this should not be a change for Python users, but I would appreciate close review of this part.

@github-actions
Copy link

github-actions bot commented Oct 12, 2025

PR Preview Action v1.6.2

🚀 View preview at
https://rigetti.github.io/quil-rs/pr-preview/pr-484/

Built to branch quil-py-docs at 2025-11-05 23:31 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@antalsz antalsz changed the title feat!: change InstructionalHandler to be a trait and require it everywhere in Rust feat!: change InstructionHandler to be a trait and require it everywhere in Rust Oct 15, 2025
@antalsz antalsz marked this pull request as ready for review October 15, 2025 06:07
Copy link

@windsurf-bot windsurf-bot bot left a comment

Choose a reason for hiding this comment

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

Other comments (5)
  • quil-rs/src/program/mod.rs (568-579) The new `simplify()` method doesn't follow the same naming convention as the removed `into_simplified()` method. The old method was intentionally named with the `into_` prefix (as indicated by the `#[allow(clippy::wrong_self_convention)]` annotation), but the new method doesn't maintain this convention. This could be confusing for users migrating from the old API, especially since the method doesn't actually consume `self`.
  • quil-rs/src/instruction/mod.rs (970-1283) The `memory_accesses` method in `DefaultHandler` is quite large (over 200 lines). Consider breaking it down into smaller methods grouped by instruction type (e.g., `handle_classical_instructions`, `handle_quantum_instructions`, etc.) to improve maintainability.
  • quil-rs/src/instruction/mod.rs (904-909) The implementation of `is_scheduled` in `DefaultHandler` now uses `self.role(instruction) == InstructionRole::RFControl` for most cases, which is different from the previous implementation that used a large match statement. This change in logic should be carefully tested to ensure it maintains the same behavior for all instruction types.
  • quil-rs/src/program/scheduling/graph.rs (216-217) The parameter order for `memory_accesses` is inconsistent with other handler methods. While `role` and `matching_frames` have the instruction as the last parameter, `memory_accesses` has it as the second parameter. Consider making the parameter order consistent across all methods.
  • quil-rs/src/program/scheduling/schedule.rs (213-213) For consistency with the renamed `instruction_duration_seconds` method, consider renaming `get_waveform_duration_seconds` to just `waveform_duration_seconds` (removing the 'get_' prefix).

💡 To request another review, post a new comment with "/windsurf-review".

@antalsz antalsz force-pushed the instruction-handler-improvements branch from 519d58d to be6c9ff Compare October 18, 2025 16:58
@Shadow53
Copy link
Contributor

This has the potential to provide signficant performance improvements (and I think it's probably cleaner regardless).

Have you verified any potential improvements with benchmarks?

Copy link
Contributor

@asaites asaites left a comment

Choose a reason for hiding this comment

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

Mostly, this looks great. Just one change that I see: this removed quil.program.Program.into_simplified. I recommend adding it in quilpy and regenerating the stubs.

}
}

pub trait ClassicalOperand: Clone + std::fmt::Debug {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why explicitly have these bounds on the trait?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think because they were in practice true and functionally this is a sealed trait. Plus having a Debug supertrait is always useful for debugging.

/// If you need custom instruction handling during simplification,
/// use [`InstructionHandler::simplify_program`] instead.
#[allow(clippy::wrong_self_convention)] // It's a Breaking Change to change it now.
pub fn into_simplified(&self) -> Result<Self> {
Copy link
Contributor

Choose a reason for hiding this comment

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

We likely want to have a version of this method still in quil, though I'm indifferent about whether it should have a name change. I would lean towards calling the Python version something like to_simplified instead, but keeping it into_simplified prevents breaking quil. Regardless, we just want program/quilpy.rs to add this to the impl Program block:

    #[pyo3(name = "into_simplified")]
    fn py_simplify(&self) -> Result<Program> {
        self.simplify(&DefaultHandler)
    }

And likely it should copy over the documentation as well.

Copy link
Contributor

Choose a reason for hiding this comment

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

And of course, the pyo3(name = ...) isn't strictly necessary, if you prefer setting the function name directly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done – I also marked it as #[deprecated] so that we can't accidentally use it in Rust. Let me know what you think of this approach!

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not convinced the python_only module or #[deprecated] annotations are needed:

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah I think you're right, I just got a bit overzealous. We could see about setting up a Clippy lint to forbid calls to methods named py_ but that's probably not necessary. I'll make the change!

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.

4 participants