Skip to content

Feature/conjugation#18

Open
Bloooman wants to merge 62 commits into
QuantumSavory:masterfrom
Bloooman:feature/conjugation
Open

Feature/conjugation#18
Bloooman wants to merge 62 commits into
QuantumSavory:masterfrom
Bloooman:feature/conjugation

Conversation

@Bloooman
Copy link
Copy Markdown

@Bloooman Bloooman commented Apr 28, 2026

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):

  • The code is properly formatted and commented.
  • Substantial new functionality is documented within the docs.
  • All new functionality is tested.
  • All of the automated tests on github pass.
  • We recently started enforcing formatting checks. If formatting issues are reported in the new code you have written, please correct them. There will be plenty of old code that is flagged as we are slowly transitioning to enforced formatting. Please do not worry about or address older formatting issues -- keep your PR just focused on your planned contribution.

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.

… tuple when encountering measurement as the conjugated circuitop
… PBCCompiler.jl and pair_transformation.jl. Remove functions unrelated to current feature
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 28, 2026

Benchmark Results (Julia v1)

Time benchmarks
master c32e173... master / c32e173...
traversal/combine/10 2.93 ± 0.3 μs 2.91 ± 0.25 μs 1.01 ± 0.14
traversal/combine/100 0.0322 ± 0.0011 ms 0.0317 ± 0.00097 ms 1.01 ± 0.047
traversal/combine/1000 0.327 ± 0.014 ms 0.321 ± 0.013 ms 1.02 ± 0.059
traversal/direction/left_100 0.2 ± 0.02 μs 0.2 ± 0.011 μs 1 ± 0.11
traversal/direction/right_100 0.21 ± 0.02 μs 0.21 ± 0.011 μs 1 ± 0.11
traversal/mixed/noop_100 0.17 ± 0.011 μs 0.17 ± 0.011 μs 1 ± 0.092
traversal/mixed/swap_100 0.21 ± 0.019 μs 0.21 ± 0.019 μs 1 ± 0.13
traversal/noop/10 0.05 ± 0.01 μs 0.06 ± 0.01 μs 0.833 ± 0.22
traversal/noop/100 0.16 ± 0.01 μs 0.161 ± 0.01 μs 0.994 ± 0.088
traversal/noop/1000 1.24 ± 0.02 μs 1.24 ± 0.02 μs 1 ± 0.023
traversal/swap/10 0.07 ± 0.02 μs 0.07 ± 0.019 μs 1 ± 0.39
traversal/swap/100 0.22 ± 0.02 μs 0.22 ± 0.011 μs 1 ± 0.1
traversal/swap/1000 1.68 ± 0.021 μs 1.67 ± 0.039 μs 1.01 ± 0.027
time_to_load 1.55 ± 0.018 s 1.52 ± 0.022 s 1.02 ± 0.019
Memory benchmarks
master c32e173... master / c32e173...
traversal/combine/10 0.207 k allocs: 6.75 kB 0.207 k allocs: 6.75 kB 1
traversal/combine/100 2.28 k allocs: 0.0725 MB 2.28 k allocs: 0.0725 MB 1
traversal/combine/1000 23 k allocs: 0.732 MB 23 k allocs: 0.732 MB 1
traversal/direction/left_100 0 allocs: 0 B 0 allocs: 0 B
traversal/direction/right_100 0 allocs: 0 B 0 allocs: 0 B
traversal/mixed/noop_100 0 allocs: 0 B 0 allocs: 0 B
traversal/mixed/swap_100 0 allocs: 0 B 0 allocs: 0 B
traversal/noop/10 0 allocs: 0 B 0 allocs: 0 B
traversal/noop/100 0 allocs: 0 B 0 allocs: 0 B
traversal/noop/1000 1 allocs: 16 B 1 allocs: 16 B 1
traversal/swap/10 0 allocs: 0 B 0 allocs: 0 B
traversal/swap/100 0 allocs: 0 B 0 allocs: 0 B
traversal/swap/1000 1 allocs: 16 B 1 allocs: 16 B 1
time_to_load 0.149 k allocs: 11.1 kB 0.149 k allocs: 11.1 kB 1

@Bloooman Bloooman force-pushed the feature/conjugation branch from a1fdae2 to 7e1ec9c Compare April 28, 2026 19:55
@Bloooman
Copy link
Copy Markdown
Author

I didn't change anything within pipeline.yml, but now we are seeing 2 failing checks regarding buildkite.
Is there anything I can do on my end to fix this 2 failing checks?

@Bloooman Bloooman force-pushed the feature/conjugation branch from 9599aa9 to f46c267 Compare May 12, 2026 16:27
Copy link
Copy Markdown
Member

@Krastanov Krastanov left a comment

Choose a reason for hiding this comment

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

mostly comments on style and simplification

using Makie
using PBCCompiler
using PBCCompiler: Circuit, CircuitOp, affectedqubits
using PBCCompiler: Circuit, CircuitOp, _affectedqubits
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

undo the renaming

Comment thread src/pair_transformation.jl Outdated
Comment on lines +42 to +45
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.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

some markdown formatting issue

Comment thread src/pair_transformation.jl Outdated
Comment on lines +66 to +82
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)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
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)

Comment thread src/pair_transformation.jl Outdated
@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")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

throw(AppropriateErrorType(message)), not println

Comment on lines +114 to +148
@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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this match statement seems incomplete and a bit inconsistent

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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.

Comment thread src/pair_transformation.jl Outdated
(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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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

Comment thread src/pair_transformation.jl Outdated
Comment on lines +217 to +219
typeofp=variant_name(op2)
if typeofp == :Measurement
constructor=getproperty(CircuitOp, typeofp)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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

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