Skip to main content
IBM Quantum Platform
Información sobre la traducción

Próximamente habrá traducciones a otros idiomas de esta página.

Qiskit SDK 2.6 release notes


2.6.1

Prelude

Qiskit v2.6.1 is a patch release that includes bug fixes for issues identified since the release of v2.6.0.

Bug Fixes


2.6.0

Prelude

Qiskit v2.6.0 is a new feature release of the Qiskit SDK.

This release introduces important new functionality into the Qiskit SDK, including the following:

  • A Multi-IR Pass Manager in C and Python: Added a new pass manager framework which can use different Intermediate Representations (IRs) as input and outputs. This framework is exposed to Python via the LoweringPassManager class and to the C API too. Refer to the C API Pass-manager infrastructure documentation for more details on using this new pass manager from C.

  • Custom Operations in C: Users are now able to create custom Operation types using the C API. See the QkCustomOp documentation for more details.

  • QPY 18 and C API:

    • QPY serialization and de-serialization is now available via the C API. Users are now able to use QPY for roundtrip serialization from C as well as inter-operate with Python workflows. Please note that loading QPY from C is only supported for payloads using QPY v13 and onwards. Refer to the QPY C API documentation for more details.
    • QPY v18 which introduces a new format version and produces payloads with smaller footprints. Refer to the QPY Version 18 documentation for more details on the changes in the new format revision.

C API Features

Circuits Features

  • The type that backs QuantumCircuit._data is now nameable as qiskit.circuit.CircuitData. All methods and attributes on the object are still private, regardless of their naming convention.

  • A new public constructor, QuantumCircuit.from_circuit_data(), allows reconstruction of a full circuit from the _data attribute.

  • Conversions between DAGCircuit and QuantumCircuit now shallow-copy any metadata if the copy_operations=True argument is set in circuit_to_dag(), dag_to_circuit(), QuantumCircuit.to_dag() or DAGCircuit.to_circuit(). This transitively affects compilation functions such as PassManager.run() and transpile().

  • Added support for passing an iterable of operation types to DAGCircuit.op_nodes(), for example dag.op_nodes(op=(Measure, Reset)). This allows collecting multiple instruction types in a single DAG iteration.

  • Updated QuantumCircuit.mcp() so that it automatically selects the best decomposition technique based on the number of control qubits. This improves the performance of MCPhaseGate, with circuit depth growing linearly in the number of qubits rather than quadratically as before. For gates with 2, 3, or 4 control qubits, the previous method is better in CNOT count, but for 5 or more control qubits, the new method is better.

  • Improve the default CX count in the definition of QuantumCircuit.mcx() and MCXGate with no ancilla qubits.

  • Added a compact exact decomposition for a singly-controlled RCCXGate. Calling RCCXGate.control() with one control now uses RC3XGate and CSdgGate, requiring 8 CX gates and 11 T or Tdg gates without ancillas. This also reduces the synthesis cost of higher-level controlled circuits containing RCCX gates, such as controlled modular adders.

  • Added ParameterExpression.structurally_equal(), which can be used to compare whether two expressions have equal internal structures. This is mostly useful for testing Qiskit itself.

  • Added a label argument to single-gate instruction methods on QuantumCircuit that previously did not expose one. This lets labels be set directly when adding these gates to a circuit using a method call (e.g. circuit.cp(..., label=...)).

  • Added a label argument to the RVGate constructor.

  • Added a new ParameterExpression.simplify() method that returns an algebraically simplified copy of the expression using the native symbolic engine. It collapses cancelling terms such as a + b - a - b to zero.

OpenQASM Features

QPY Features

  • QPY format version 18 significantly decreases the data size for most ClassicalRegister and QuantumRegister objects in a QuantumCircuit. The constant overhead for registers has increased by 1 byte, but then in the worst case for each bit contained in the register the overhead has decreased from 8 bytes per bit in the register to 4 bytes per bit in the register. In the common case where the registers are added to the circuit contiguously the space requirement goes from 8 bytes per bit to 4 bytes total to represent the register.

Quantum Information Features

  • The SparseObservable has a new method to_matrix(). This method returns the dense matrix representation of the observable. Its reduced time complexity is O(4n)O(4^n) where nn is the number of qubits. See the Python API docs for details.

Synthesis Features

  • Added synth_mcx_n_dirty_m15(), which implements Maslov’s Clifford+T-friendly dirty-ancilla MCX construction. It uses one ancilla for three or four controls and ⌈(k−2)/2⌉\lceil(k - 2) / 2\rceil ancillas for larger gates.

  • The clean-ancilla synth_mcx_n_clean_m15() implementation now also uses ⌈(k−2)/2⌉\lceil(k - 2) / 2\rceil ancillas instead of k−2k - 2, without changing its T or CX counts. Thus, QuantumCircuit.mcry() with mode=None can automatically select basic mode when at least ⌈(k−2)/2⌉\lceil(k - 2) / 2\rceil clean ancillas are available.

  • Added a new plugin, PauliEvolutionSynthesisMcts, for synthesizing PauliEvolutionGate objects. The implementation combines ideas from the papers MonteQ: A Monte Carlo Tree Search Based Quantum Circuit Synthesis Framework by Machiya et al. (https://arxiv.org/abs/2604.19029) and Faster and shorter synthesis of Hamiltonian simulation circuits by de Brugière et al. (https://arxiv.org/abs/2404.03280).

    Compared to the default plugin, PauliEvolutionSynthesisDefault, PauliEvolutionSynthesisMcts typically requires more runtime but often produces higher-quality circuits. It is also significantly faster than PauliEvolutionSynthesisRustiq while generally achieving better synthesis results.

    The quality of the generated circuits can be further improved by increasing the num_simulations option, at the cost of additional runtime. This overhead can be partially mitigated by executing simulations in parallel.

  • Added three synthesis functions for multi-controlled phase gates. synth_mcp_noaux_v24() uses the newer no-auxiliary decomposition based on multi-controlled RZ gates, and is the better choice for up to 4 control qubits. synth_mcp_noaux_sp22() implements the linear-depth strategy from da Silva et al. and is used for 5 or more control qubits. synth_mcp_noaux_default() is a dispatcher that selects between these two methods according to the number of control qubits.

  • Added a synthesis function for multi-controlled X gates with no ancilla qubits, synth_mcx_noaux_sp22() that implements the linear-depth strategy from da Silva et al. This method provides better CX counts than synth_mcx_noaux_v24(). Note that although this synthesis method grows quadratically in the number of controls, while the method in synth_mcx_noaux_hp24() grows linearly in the number of controls, it still yields better CX counts where n≤32n \leq 32.

Transpiler Features

  • Added an approximation_degree parameter to the CommutativeCancellation transpiler pass. The parameter accepts a floating-point value between 0 and 1 (with a default 1.0). This parameter is forwarded to the underlying commutation analysis for identifying gates that can be cancelled. The preset pass managers pass pass_manager_config.approximation_degree to CommutativeCancellation, using 1.0 when the config value is None.

  • Added the mcx.n_dirty_m15 high-level synthesis plugin. The default MCX synthesis plugin selects it for T-count optimization with three or more controls, and for two-qubit-count optimization with four or more controls, when enough dirty ancillas are available and no higher-priority clean-ancilla method applies. It can also be selected explicitly using HLSConfig, for example as HLSConfig(mcx=["n_dirty_m15"]). The plugin requires ⌈(k−2)/2⌉\lceil(k - 2) / 2\rceil clean or dirty ancillas for k≥4k \geq 4, and one ancilla for k=3k = 3.

  • Added a new high-level synthesis plugin MCXSynthesisNoAuxSP22 for the synthesis of MCXGate with no ancilla qubits.

  • Added a new optimization_level argument to the HighLevelSynthesis transpiler pass. This allows the pass to select synthesis methods that can produce more optimized circuits at the expense of increased runtime.

  • Added the PauliEvolutionSynthesisMcts plugin to the default synthesis plugin for PauliEvolutionGate. The plugin may be selected when optimization_level >= 2 and the target has all-to-all connectivity.

  • Added a new method SparseObservable.contains_projectors() that returns whether the observable contains any projector terms.

  • transpile() now accepts a Target instance as the second positional argument (the backend parameter). When a Target is passed this way, it is treated as if it had been passed via the target keyword argument, consistent with the existing behaviour of generate_preset_pass_manager(). This allows users to write:

    tqc = transpile(circuit, target)

    instead of:

    tqc = transpile(circuit, target=target)

    A TypeError is raised if a Target is passed positionally and target is also specified as a keyword argument. Fixed #15066.

Visualization Features

  • pi_check and circuit visualization now print rotation angles as π fractions with higher integers, up to 100 (for example 3π/35 or 17π instead of decimal approximations).

    See #16356.

C API Upgrade Notes

Circuits Upgrade Notes

  • The Delay instruction in circuits now has an upper bound of 2**63 - 1 on dt durations. This is a consequence of the backing data model moving to Rust.

  • The metadata attributes of DAGCircuit.metadata and DAGCircuit.name are no longer guaranteed to be preserved for any nested instance of ControlFlowOp when they contain circuit blocks of type DAGCircuit. This behavior was never supported/documented and therefore was never meant to be used in this context.

OpenQASM Upgrade Notes

  • OpenQASM 2 gate-body expressions are now evaluated in Rust. Real-valued expressions give the same results as before, but the exceptions raised for mathematically invalid ones have changed type: sqrt/ln of a non-positive argument, ^ with a negative base and non-integer exponent, and division by zero now all raise QASM2ParseError, where they previously raised ValueError, CircuitError and ZeroDivisionError respectively. They are still raised lazily, when the gate’s definition is first built.

QPY Upgrade Notes

  • Added a new QPY format version, 18, which is now used by default in qpy.dump(). If needed, users can specify a previous QPY format version by specifying the version argument of the on qpy.dump(). For more information about the format changes see the QPY Version 18 docs.

Miscellaneous Upgrade Notes

  • The use of multiprocessing with parallel_map() to run Python code in parallel on Linux has been disabled by default. This also changes the default multiprocessing behavior for functions that internally use parallel_map() such as transpile() and PassManager.run(). In previous releases on Linux systems it would default to running in parallel; however, this has proven to be unreliable especially when mixing threading with multiprocessing. This could result in deadlocks when downstream provider packages, such as qiskit-ibm-runtime, would use async Python. In general the importance of leveraging multiprocessing for performance has significantly diminished since Qiskit 1.0 as more of the library has enabled parallelism via Rust and multithreading which was already mutually exclusive with Python multiprocessing. If you would like to continue to use multiprocessing with parallel_map() or other Qiskit functions using it internally you can explicitly opt-in to enable multiprocessing. To explicitly enable multiprocessing on Linux (or any platform) you can either set an explicit start method to "fork" or "forkserver" using multiprocessing.set_start_method() (explicitly setting "spawn" still disables multiprocessing by default because of the extra overhead and complexities associated with it and you’ll need to enable multiprocessing with spawn using the other two options), set the environment variable QISKIT_PARALLEL=TRUE, or set parallel to True in your user configuration file.

Build System Changes

  • The minimum version of the build dependency setuptools-rust was bumped to 1.13, to use the new Extension(generated_files=...) argument.

  • The minimum supported Rust version (MSRV) to build Qiskit from source is now 1.89.

  • SparsePauliOp.simplify() no longer requires the optional sympy dependency when simplifying operators with ParameterExpression coefficients. It instead relies on Qiskit’s internal symbolic engine.

Bug Fixes

  • Fixed CommutativeCancellation incorrectly shifting the global phase by −π-\pi when accumulating a 2π2\pi rotation using a PhaseGate or U1Gate. Fixed #16377.

  • Fixed Initialize.gates_to_uncompute() to return a circuit with the correct number of qubits, when the gate was constructed using an integer form (e.g. Initialize(1, num_qubits=2)). Fixed #16413.

  • Fixed qasm3.dump_experimental() and dumps_experimental() incorrectly outputting a us suffix for delays specified in ms.

  • Fixed the conversion to ns in qasm3.dump_experimental() and dumps_experimental() when outputting delays specified in ps.

  • qk_control_flow_instruction_free() now safely accepts null pointers, consistent with the rest of the C API. See #17049.

  • Fixed a bug in CommutationChecker when checking commutativity of parameterized gates, such as RXGate, when the gates argument is specified. Fixed #16407.

  • Fixed a bug in CommutationChecker where passing an empty gates set now returns False instead of behaving like no filter was specified.

  • The qargs parameter is now correctly marked as const (const uint32_t *) in both qk_target_entry_add_property() and qk_target_update_property().

  • CouplingMap no longer stores parallel edges. A coupling given more than once, whether to the constructor or to add_edge(), now collapses onto the existing edge instead of being stored twice. Fixed #16987.

  • Fixed a bug where CouplingMap.is_symmetric could falsely report True when an edge was duplicated.

  • Fixed a bug in Optimize1qGatesDecomposition where the choice among the possible Euler bases for a resynthesized run ignored the error rates of the target and was made on gate count alone, with ties broken by an internal fixed ordering. The pass now selects the candidate decomposition with the lowest total error according to the target, as it did before the pass was ported to Rust. When no target is given (or it has no error rates), the selection still minimizes the gate count. Fixed #16460.

  • BitArray.from_counts() and BitArray.from_samples() now raise a ValueError with a descriptive message, instead of an obscure OverflowError (int too big to convert), when a value does not fit in the requested num_bits.

  • Fixed a deadlock in CommutationAnalysis and CommutativeCancellation when running multithreaded and the commutation of custom Python-defined gates had to be computed from their matrices. Fixed #16937.

  • Fixed parameter loss in Commuting2qBlock where the params attribute was hardcoded to an empty list, causing all parameters from input parametric gates to be lost. The fix properly extracts and preserves parameters from gate operations, including those in ParameterExpression objects. Fixed #16456.

  • Fixed an inconsistency in ConsolidateBlocks, which removed identity-equivalent sequences differently from how RemoveIdentityEquivalent and Qiskit’s other transpiler passes do. This has been fixed and ConsolidateBlocks now behaves consistently by using the average gate fidelity to check whether a sequence is close to the identity. This implies that sequences that are equivalent to the identity up to global phase are now also being removed.

  • Fixed ConsolidateBlocks incorrectly removing non-identity gates wider than 2 qubits with two unit roots present at the beginning of their main diagonal. Fixed #16852.

  • UnitarySynthesis no longer interprets an empty basis as a Clifford+T-only basis. In particular, unitaries are now left unchanged when no basis or target is supplied. Fixes #16688.

  • Fixed ParameterExpression equality so that mathematically equivalent expressions built via division and negative exponentiation (for example, 1 / x and x ** -1) now compare equal. Previously these produced structurally different expression trees and were treated as unequal even though they represent the same value. Fixed #16840.

  • OneQubitEulerDecomposer with the "U" or "U3" basis no longer emits a one-qubit gate that is equal to the identity. When the rotation angle is zero the gate only depends on phi + lam, but the two angles were checked separately, so a case like U(0, -pi, -pi) was not recognised as an identity. This also removes the redundant one-qubit gates that TwoQubitBasisDecomposer produced with those bases, for example when decomposing CXGate in the CX basis. Fixes #9315.

  • Fixed an issue with qpy.load() not respecting the min_qpy_version user config file option if the specified version was > 13.

  • Fixed an issue with the qpy.dump() function where in several cases it would previously crash the process if the payload specified it needed more memory than was available. For several of the cases fixed it will now raise a QpyError which can be caught and handled. However, in general QPY deserialization is not safe against resource exhaustion and running it may still cause an OOM failure that results in a hard process crash either from the operating system or the allocator. Fixes #16898.

  • Fixed a bug in OptimizeSwapBeforeMeasure that caused it to retarget measurements to the wrong qubits when loose qubits preceded the measured qubit. Fixes #16874.

  • Fixed an issue in qpy.load() where it would potentially panic when parsing a malformed payload that contained register bit indices not defined in the circuit. This will now properly return a QpyError instead.

  • Fixed a bug in QPY serialization where ParameterExpression objects containing expressions that can be evaluated to concrete values were not being deserialized correctly, resulting in a crash. Fixed #17164.

  • Fixed an issue in qasm3.dumps() where Qiskit objects (registers, parameters, gates) whose names collide with OpenQASM 3 built-in constants (pi, tau, euler and their Unicode letter aliases π, τ) were exported without renaming. The resulting programs could not be re-parsed with qasm3.loads() because the names collided with the predefined symbols in the OpenQASM 3 global scope. These names are now escaped using the same mechanism that already handles reserved keywords (for example, a Parameter named pi is exported as pi_0). See #16169.

  • Fixed a bug with the QPY serialization and deserialization of ancilla registers that made them load as non-ancilla registers. Fixed #11619.

  • Fixed a bug with the QPY serialization and deserialization of instructions containing SparseObservable data. Fixed #16722.

  • Fixed a panic in qs_decomposition() (and therefore in UnitaryGate.definition) when called on a 1×11 \times 1 unitary, that is, a unitary acting on zero qubits. The function now returns a zero-qubit QuantumCircuit whose global phase matches the phase of the input matrix. Fixed #17036.

  • Fixed an issue where drawing an empty circuit with no qubits and no classical bits using the C circuit drawer (e.g. via qk_circuit_draw()) caused a panic. Fixes #16723.

  • Fixed sampled_expectation_value() silently dropping the imaginary component of expectation values when the operator has complex coefficients. The function now returns complex values when the input coefficients are complex, and float values otherwise. Fixed #11393.

  • Fix a correctness bug in TwoQubitBasisDecomposer that provided faulty synthesis of certain unitary matrices U near the 2-CX / 3-CX boundary or where the U[0][0] element was 0.

    Fixed #17057.

  • Fixed a bug in synth_cnot_phase_aam() where the angles were reduced modulo π\pi instead of 2∗π2 * \pi.

  • Fixed a stack overflow when destructing very deeply nested trees of ParameterExpression.

  • PassManager.run() no longer clobbers the original_qubit_indices or num_input_qubits keys if they are set in a given property_set argument. See #8622.

Performance Improvements

  • qk_circuit_barrier() no longer re-allocates a temporary buffer to view the qubits array.

  • Improves runtime performance of the add_register() method on QuantumCircuit. Consequently, this change improves performance when creating QuantumCircuit as well. Generally, the time complexity of checking register name presence was reduced to O(1)O(1) from O(n)O(n). This was achieved by removing redundant error checking.

  • Improved the runtime performance of synth_qft_full() by migrating the implementation to Rust. Benchmarks show speedups ranging from ~9x at 5 qubits to ~30x at 200 qubits, and ~11x at 1000 qubits. See #16789.

  • Ported synth_cnot_phase_aam() to Rust. The new implementation is about 850x faster than the previous Python implementation when synthesizing a parity network with 120 terms on 150 qubits. See #12937 for more details.

  • Pauli.evolve() and PauliList.evolve() are faster in many cases where other is a Clifford and frame is 'h' (Heisenberg).

  • The methods Pauli.evolve() and PauliList.evolve() are now significantly faster at Schrödinger-frame evolution by a Clifford when the Paulis have few non-identity terms. See #16835.

  • QPY version 18 now stores each ParameterVector once per circuit payload, in a new PARAMETER_VECTOR_TABLE. QPY now avoids repeating the vector’s name and size for each element, and instead refers to each by index. An element now occupies 10 bytes instead of 34 plus the length of the vector’s name. For example: a circuit using a 100-element vector is now around 29% smaller.

  • QPY version 18 narrows the bit-term elements of the SPARSE_OBSERVABLE payload from uint16_t to uint8_t, reducing the representation for SparseObservable instances in QPY by 2 bytes per term in the observable.

  • Improved the performance of compilation into Clifford+T basis sets (for example, using generate_preset_clifford_t_pass_manager()) by removing transpiler passes that have little or no impact on the quality of the resulting circuit. See #16406 for more details.

  • Improved the runtime performance of synth_mcx_n_clean_m15() function by migrating the implementation to Rust. The function synthesizes multi-controlled X gates using clean ancillary qubits (Maslov 2016). Benchmarks show 1.5-1.6x speedup across control qubit counts from 50 to 5000. There are no API changes. See #16703 for more details

  • Improved the runtime performance of synth_mcx_1_clean_kg24(), synth_mcx_1_dirty_kg24(), synth_mcx_2_clean_kg24(), and synth_mcx_2_dirty_kg24() by migrating the implementation to Rust. Benchmarks show a significant speedup across control qubit counts from 50 to 1000. See #16783 for more details.

  • SparsePauliOp.to_matrix() now allocates dense matrices in a way that is more likely to get OS/kernel-level optimizations, especially for large matrices with few nonzero terms.

  • Improved runtime of synth_mcp_noaux_sp22() synthesis function by migrating implementation to Rust, resulting in approximately 25-34x speedup across circuit sizes (n=50 to n=1000). See #16755 for more details.

  • Improved runtime of synth_mcx_noaux_sp22() synthesis function by migrating implementation to Rust, resulting in approximately 2x-2.6x speedup across circuit sizes (n=50 to n=1000). See #16818 for more details.

  • Improved runtime of synth_mcx_1_clean_b95() synthesis function by migrating implementation to Rust, resulting in approximately 6x speedup across circuit sizes (k=50 to k=1000). See #16710 for more details.

¿Le ha resultado útil esta página?
Informe de un error, de una errata o solicite contenido en GitHub.