Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add pauli_twirl_2q_gates function (#13331)
* 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