Feature/conjugation#18
Conversation
… tuple when encountering measurement as the conjugated circuitop
… PBCCompiler.jl and pair_transformation.jl. Remove functions unrelated to current feature
… tuple when encountering measurement as the conjugated circuitop
… PBCCompiler.jl and pair_transformation.jl. Remove functions unrelated to current feature
….jl into feature/conjugation
Benchmark Results (Julia v1)Time benchmarks
Memory benchmarks
|
a1fdae2 to
7e1ec9c
Compare
|
I didn't change anything within pipeline.yml, but now we are seeing 2 failing checks regarding buildkite. |
9599aa9 to
f46c267
Compare
Krastanov
left a comment
There was a problem hiding this comment.
mostly comments on style and simplification
| using Makie | ||
| using PBCCompiler | ||
| using PBCCompiler: Circuit, CircuitOp, affectedqubits | ||
| using PBCCompiler: Circuit, CircuitOp, _affectedqubits |
| This helper function ensures that both operators are represented over the | ||
| union of their affected qubits. It reorders strings to a canonical qubit | ||
| ordering and pads missing sites with Identity operators ('_') to ensure | ||
| equal string length. |
There was a problem hiding this comment.
some markdown formatting issue
| pu1=_affectedpaulis(op1) | ||
| pu2=_affectedpaulis(op2) | ||
| @debug("Affected Paulis of op1: ", pu1) | ||
| @debug("Affected Paulis of op2: ", pu2) | ||
| qu1=_affectedqubits(op1) | ||
| qu2=_affectedqubits(op2) | ||
| @debug("Affected qubits of op1: ", qu1) | ||
| @debug("Affected qubits of op2: ", qu2) | ||
| AffectedQubbits=sort(union(qu1,qu2)) | ||
| @debug("Affected qubits of both ops: ", AffectedQubbits) | ||
| Paulilen=maximum(AffectedQubbits) | ||
| @debug("Length of the affected Pauli string: ", Paulilen) | ||
| Pauli1=embed(Paulilen, op1.qubits, pu1) | ||
| Pauli2=embed(Paulilen, op2.qubits, pu2) | ||
| @debug("New Pauli string of op1: ", Pauli1) | ||
| @debug("New Pauli string of op2: ", Pauli2) | ||
| return (Pauli1, Pauli2) |
There was a problem hiding this comment.
| pu1=_affectedpaulis(op1) | |
| pu2=_affectedpaulis(op2) | |
| @debug("Affected Paulis of op1: ", pu1) | |
| @debug("Affected Paulis of op2: ", pu2) | |
| qu1=_affectedqubits(op1) | |
| qu2=_affectedqubits(op2) | |
| @debug("Affected qubits of op1: ", qu1) | |
| @debug("Affected qubits of op2: ", qu2) | |
| AffectedQubbits=sort(union(qu1,qu2)) | |
| @debug("Affected qubits of both ops: ", AffectedQubbits) | |
| Paulilen=maximum(AffectedQubbits) | |
| @debug("Length of the affected Pauli string: ", Paulilen) | |
| Pauli1=embed(Paulilen, op1.qubits, pu1) | |
| Pauli2=embed(Paulilen, op2.qubits, pu2) | |
| @debug("New Pauli string of op1: ", Pauli1) | |
| @debug("New Pauli string of op2: ", Pauli2) | |
| return (Pauli1, Pauli2) | |
| pu1 = paulis(op1) | |
| pu2 = paulis(op2) | |
| qu1 = affectedqubits(op1) | |
| qu2 = affectedqubits(op2) | |
| paulilen = max(maximum(qu1), maximum(q2)) | |
| pauli1 = embed(paulilen, op1.qubits, pu1) | |
| pauli2 = embed(paulilen, op2.qubits, pu2) | |
| return (pauli1, pauli2) |
| @match (op1, op2) begin | ||
| #scenario 1: One of them is classical controlled gate | ||
| (op,CircuitOp.BitConditional(inner_op, bit)) || (CircuitOp.BitConditional(inner_op, bit), op) => begin | ||
| println("Invalid input: Need to determine gate present first") |
There was a problem hiding this comment.
throw(AppropriateErrorType(message)), not println
| @match (op1, op2) begin | ||
| #scenario 1: One of them is classical controlled gate | ||
| (op,CircuitOp.BitConditional(inner_op, bit)) || (CircuitOp.BitConditional(inner_op, bit), op) => begin | ||
| println("Invalid input: Need to determine gate present first") | ||
| end | ||
| #scenario 2: One of them is Pauli Conditional gate | ||
| (op, CircuitOp.PauliConditional(cp, cq, tp, tq)) || (CircuitOp.PauliConditional(cp, cq, tp, tq), op) => begin | ||
| @debug("One of the operations is a Pauli conditional gate. ") | ||
| cop=CircuitOp.ExpQuatPiPauli(cp, cq) | ||
| top=CircuitOp.ExpQuatPiPauli(tp, tq) | ||
| comm_cop=check_commutation(op, cop) | ||
| comm_top=check_commutation(op, top) | ||
| if comm_cop == 0 && comm_top == 0 | ||
| @debug("The operation commutes with both the control and target Paulis of the conditional gate.") | ||
| elseif comm_cop != 0 && comm_top != 0 | ||
| @debug("The operation anticommutes with both the control and target Paulis of the conditional gate.") | ||
| else | ||
| @debug("The operation commutes with one of the control and target Paulis of the conditional gate, and anticommutes with the other.") | ||
| end | ||
| return (comm_cop, comm_top) | ||
| end | ||
| #scenario 3: Both are Pauli Product Rotations | ||
| _ => begin | ||
| (Pauli1,Pauli2)=_complete_paulis(op1, op2) | ||
| commutativity=comm(Pauli1,Pauli2) | ||
| if commutativity == 0 | ||
| @debug("The two operations commute.") | ||
| else | ||
| @debug("The two operations anticommute.") | ||
| end | ||
| return commutativity | ||
| end | ||
|
|
||
|
|
||
| end |
There was a problem hiding this comment.
this match statement seems incomplete and a bit inconsistent
There was a problem hiding this comment.
This either needs to return "something" or raise an error on meaningless combinations of ops. E.g. you can return "nothing" if it is poorly defined what is happening.
Fewer debug statements.
Make sure that all possible combinations of operators are actually tested. In the docstring clearly state what happens with the more nontrivial combinations.
| (CircuitOp.ExpQuatPiPauli(pauli=+ XXY, qubits=[1, 2, 3]), CircuitOp.PauliConditional(control_pauli=+ Z, control_qubits=[1], target_pauli=+ X, target_qubits=[2])) | ||
| ``` | ||
| """ | ||
| function conjugate(op1::CircuitOp.Type, op2::CircuitOp.Type) #first input is the one we conjugate by, second input is the one we want to conjugate |
There was a problem hiding this comment.
try to split this into two much smaller and much simpler
2. nonclifford_to_front
uses conjugate_noncliff
pivot -- either measurement or exp*pauli
-- BitConditional in which case return nothing
moved_conjugated -- the selected noncliff op, error if it is not noncliff
3. clifford_to_end
uses conjugate_measurement
pivot -- clifford (pi/2 or pi/4)
-- everything else returns nothing
moved_conjugate -- measurements, error if it is not
| typeofp=variant_name(op2) | ||
| if typeofp == :Measurement | ||
| constructor=getproperty(CircuitOp, typeofp) |
There was a problem hiding this comment.
avoid this type of introspection, just use standard pattern matching, as it keeps the code simpler. Forcing yourself to figure out the match way of writing this usually leads to a simpler piece of code
Edit this message to describe your submission -- delete the instruction content and put in your own.
Please address only one topic or issue per pull request! Many small PRs are much easier to review and merge than one large PR.
If this is your first submission to this organization and you are not a developer known in the Julia ecosystem, do not use LLMs -- we need to trust you first before we trust the LLM under your control.
If you want to submit an unfinished piece of work in order to get comments and discuss, please mark the pull request as a draft and ping the repository maintainer.
Before merging, all changes and new functionality should be marked in the CHANGELOG file, but feel free to just leave your CHANGELOG notes in the PR description, to avoid merge conflicts with other requests modifying that file. The maintainer will add these CHANGELOG notes for you if you do so.
Before considering your pull request ready for review and merging, make sure that all of the following are completed (please keep the clecklist as part of your PR):
If you are submitting for a bug bounty:
If possible, keep your git history not too wild (rebase and squash commits, keep commits small and semantically separated) so that review is easier.