-
Notifications
You must be signed in to change notification settings - Fork 1
Implement lowering a cirq.Circuit to squin #294
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
Conversation
|
For single qubit gate with arbitrary power, my understand is it can always decomposed into 1Q rotation gate (cirq has a unitary to angle helper) for arbitrary multi-qubit power I am not sure. |
Good point! For controlled gates to a power we can do something similar, I think, although I couldn't find a similar helper method (for single qubit gates it's |
Codecov ReportAttention: Patch coverage is
📢 Thoughts on this report? Let us know! |
☂️ Python Coverage
Overall Coverage
New Files
Modified Files
|
|
When transpling to squin, could you also give an option that moments are transpiled correctly to preserve ordering? This follows the PR that I made a few days ago #288 where I parallelize, represented by cirq moments. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the PR itself LGTM. I left a comment to improve in the future PR. We should get this basic API in first.
| def visit_Moment( | ||
| self, state: lowering.State[CirqNode], node: cirq.Moment | ||
| ) -> lowering.Result: | ||
| for op_ in node.operations: | ||
| state.lower(op_) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe in a separate PR, to address @jon-wurtz 's comment, we should:
- lower moment with same gate into
broadcast(op, ...) - lower moment with different gate into
parallelstatement (which will be added on Kirin side)
to facilitate this we may want to just add a Moment statement as an IR to temperarily perserve this highlevel structure coming from cirq and then implement a rewrite from Moment to squin.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or a Moment should be rewrite into something like a Parallel with a region?
| # TODO: can there be a circuit without qubits? | ||
| n_qubits = cirq.num_qubits(self.circuit) | ||
| n = frame.push(py.Constant(n_qubits)) | ||
| self.qreg = frame.push(qubit.New(n_qubits=n.result)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might it be better to have the register be an input to the kernel instead of inside of the kernel? Otherwise, the kernel generated cannot be used as a subroutine elsewhere. Likewise, returning the qubit register. See QuEraComputing/bloqade#249.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jon-wurtz see my comment in the RFC issue (let's leave the discussion in on place). Ideally we support both, loading a "standalone" circuit as well as passing the register as an argument, controlled by a kwarg.
|
Could this handle cirq feed forward, e.g. q0, q1 = cirq.LineQubit.range(2)
circuit = cirq.Circuit(
cirq.H(q0), # Prepare qubit q0 in superposition
cirq.measure(q0, key='m'), # Measure qubit q0
cirq.X(q1).with_classical_controls('m') # Apply X gate to q1 if measurement 'm' is 1
)which creates a circuit like or more complex classical control like https://quantumai.google/cirq/build/classical_control |
|
@weinbe58 @Roger-luo I think we need to add a new operator statement in order to support the Basically, this channel maps |0> to |1> and vise-versa, but at different probabilities. So essentially I need both processes separately. Mapping from |1> to |0> can be done via |
|
@jon-wurtz classical control is still missing. That needs to be lowered to an |
can we limit this PR to have the basic only? otherwise it will take forever to merge...
I think that's ok? I don't see a reason why no. but in a separate PR maybe I think the cirq feature covered in this PR already good enough for most people. |
|
@Roger-luo Okay, then I'll leave this PR open a bit longer to give people some more time to respond on the RFC. I'll create follow-up issues for the missing features. Then we can merge this PR. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would be nice if we can add a docstring to the entry before merging.
Addresses #283 For now, I went with the syntax `squin.load_circuit(circuit: cirq.Circuit)`. So you can e.g. do ```python q0 = cirq.NamedQubit("q0") q1 = cirq.NamedQubit("q1") circuit = cirq.Circuit( cirq.H(q1), cirq.X(q0).controlled_by(q1), cirq.Rx(rads=math.pi / 4).on(q0).controlled_by(q1), cirq.measure(q0, q1), ) main = squin.load_circuit(circuit) ``` ~~@Roger-luo @weinbe58 one open question here: cirq support arbitrary powers of gates, e.g. `cirq.H(q0)**0.123`. Should we add a `Pow` statement to squin to properly support this? I think pyqrack can also handle it, but I'll have to check again. Also, not sure what this should look like when running on hardware, but we can still error in the runtime.~~ **Edit**: turns out arbitrary powers are quite easy since we can just use the cirq helper `in_su2` to get the corresponding rotation and lower that. Also, for multi-qubit gates they usually mean "apply a controlled single qubit gate with an exponent", which again corresponds to a rotation. Thanks @kaihsin for pointing to the helper method. ## TODOs: - [x] support (arbitrary) powers of operators? - ~~[ ] Lowering of noisy circuits~~ done, except #301 - [x] Add missing gates (e.g. three-qubit controls are still missing) - [ ] Make sure the set of supported gates is complete - ~~ [ ] Optionally return the quantum register (and possibly other things) ~~ see #302 - ~~ [ ] Optionally pass in the quantum register as argument to the method ~~ see #302 - ~~[ ] Support classical control by lowering to `if` ~~ see #303
Addresses #283
For now, I went with the syntax
squin.load_circuit(circuit: cirq.Circuit).So you can e.g. do
@Roger-luo @weinbe58 one open question here: cirq support arbitrary powers of gates, e.g.cirq.H(q0)**0.123. Should we add aPowstatement to squin to properly support this? I think pyqrack can also handle it, but I'll have to check again. Also, not sure what this should look like when running on hardware, but we can still error in the runtime.Edit: turns out arbitrary powers are quite easy since we can just use the cirq helper
in_su2to get the corresponding rotation and lower that. Also, for multi-qubit gates they usually mean "apply a controlled single qubit gate with an exponent", which again corresponds to a rotation. Thanks @kaihsin for pointing to the helper method.TODOs:
[ ] Lowering of noisy circuitsdone, except Add new squin operator mapping |0> to |1> and |1> to |1> #301if~~ see Support for classical control when loading cirq.Circuit #303