Skip to content

Commit

Permalink
Add pauli_twirl_2q_gates function (#13331)
Browse files Browse the repository at this point in the history
* Add twirl_circuit function

This commit adds a new function twirl_circuit to apply Pauli twirling to
a given circuit. This function only works with a fixed set of two qubit
gates and is not a general solution. For performance this new function
is written in rust and uses static lookup tables for the twirling sets
around the fixed two qubit gates that are randomly sampled. There is
an option to perform twirling multiple times and return a list of
circuits instead of just doing it once. Ideally we'd do this in
parallel, but we're currently blocked on the use of OnceCell in the
PackedInstruction and the ParameterTable from parallelizing with
CircuitData. We can further improve the performance of this new
function by using a parallel iterator once #13219 is resolved. The
function is written in a way to make this simple in the future.

Fixes #13325

Co-authored-by: Paul Nation <nonhermitian@gmail.com>

* Update asv benchmarks to use new function

* Apply suggestions from code review

Co-authored-by: Julien Gacon <gaconju@gmail.com>

* Expand testing coverage

* Add capacity option to clone_empty_from

* Make static twirling tables more compact

* Make num_trials default to None to return a single circuit

* Allow for multiple twirling gates

This commit expands the twirling_gate argument to work with strings
instead of classes and also specify a list of gates instead of a single
gate type. It also changes the default to `None` to twirl all supported
gates in the circuit.

* Fix typo in max seed value

* Avoid vec for qubits

* Recurse into control flow for twirling

This commit updates the twirl_circuits logic to recurse into a control
flow operation and twirl any gates that are potentially in the block.

* Avoid extra calls to interner

Previously for each twirled gate we were calling the interner 4 times
once for each new gate. However, there are only 2 qargs being used and
we only need half of the interning calls by reusing the interned qubits
between the two gates. This commit reworks the logic to make this
optimization.

* Rename clone_empty_from to clone_empty_like

* Improve docs for new rust space methods

* Unify seeding logic

This commit removes the final logic branch for when we're generating > 4
circuit outputs. That was previously left in place to prepare for
building the output circuits in parallel using a rayon iterator.
However, we're currently blocked form doing that and having different
seeding behavior for a fixed seed when you move from 3 to 5 output
circuits is probably unexpected. This standardizes on the lower overhead
sequential iterator path, if/when we make it parallel we can switch the
seeding behavior over to the other form.

* Fix lint

* Preserve Python space circuit metadata in output twirled circuits

* Add option to run Optimize1qGatesDecomposition

This commit adds a new option to the function to enable running the 1q
optimization pass as part of the twirling function. The typical workflow
is to run twirling after transpilation to generate a lot of random
twirled circuits, in this workflow we need to adjust the pauli gates
generated during twirling to match the backend's target. The
Optimize1qGatesDecomposition pass that's passed in is used as a
container for the arguments, we call the pass internally via rust for
lower overhead.

* Handle all gates with a matrix

This commit expands the twirling function to work with any gate object
that has a matrix. For the gates outside the previosuly supported set of
CX, ECR, CZ, and iSwap we compute the twirling set on demand for any
gate when the function is called now. This lets the function work for
any gate even custom ones as long as they define a matrix.

* Add checking on custom gates to ensure they're valid for twirling

* Fix lint

* Pre-compute pauli gate products

* Use square of norm to save a sqrt

* Switch from taking pass to a Target

Forcing users to instantiate a Optimize1qGatesDecomposition transpiler
pass was a bit heavy when the twirling function wasn't actually calling
the pass directly. All the pass was being used for was to pull the
constraints out and pass it to Rust. It is simpler for users to just
give the target to the function directly and also simplifies the
function's code.

* Apply suggestions from code review

Co-authored-by: Julien Gacon <gaconju@gmail.com>

* Adjust docstring

* Update tests for new function name

* Update release note for new function name too

* Rename set_qargs to add_qargs

---------

Co-authored-by: Paul Nation <nonhermitian@gmail.com>
Co-authored-by: Julien Gacon <gaconju@gmail.com>
  • Loading branch information
3 people authored Nov 7, 2024
1 parent 3cbab95 commit 3e136d7
Show file tree
Hide file tree
Showing 12 changed files with 981 additions and 155 deletions.
1 change: 1 addition & 0 deletions crates/accelerate/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ pub mod star_prerouting;
pub mod stochastic_swap;
pub mod synthesis;
pub mod target_transpiler;
pub mod twirling;
pub mod two_qubit_decompose;
pub mod uc_gate;
pub mod unitary_synthesis;
Expand Down
Loading

0 comments on commit 3e136d7

Please sign in to comment.