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
-
Various C-API functions that return strings (either directly or as error messages) will no longer panic if the backing string contains interior nul bytes.
-
Fixed an issue on Linux systems when using Qiskit with other Python packages that dynamically load shared libraries (such as Qiskit Aer or scikit-learn) that also were using thread local storage and in some cases could fill the available static TLS space from glibc. This would result in an
ImportErrorwith an error message likecannot allocate memory in static TLS block. This was fixed by changing how Qiskit build’s mimalloc to use a different TLS model that doesn’t use the static TLS. See #17213. -
Fixed an issue where
CPhaseGate.power(),CSGate.power(), andCSdgGate.power()dropped thectrl_stateattribute of the gate, causing open-controlled gates (ctrl_state=0) to lose their control state and fall back to the default control state:1.Fixed #17222.
-
Fixed
TwoQubitBasisDecomposer.decomp0(),TwoQubitBasisDecomposer.decomp1(),TwoQubitBasisDecomposer.decomp2_supercontrolled(), andTwoQubitBasisDecomposer.decomp3_supercontrolled()so they correctly acceptTwoQubitWeylDecompositionarguments.
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
LoweringPassManagerclass 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
Operationtypes 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
-
Custom operations can now be defined via the C API using
QkCustomOp. Any implementors should refer to the documentation defined in QkCustomOp for further information. -
Add
qk_circuit_custom_operation()andqk_dag_apply_custom_operation()to add custom operations defined in C to a circuit. -
Added ability to add
Delayin terms ofDtto aQkCircuit(viaqk_circuit_delay_dt()). -
Add
qk_circuit_delay_unit()to retrieve the unit type of aDelayinstruction in the C API. -
Add
qk_param_kind()to obtain an enumeration (QkParamKind) describing the kind of anyQkParaminstance before using functions such asqk_param_as_real()orqk_param_as_int()to obtain its bound value. -
Add
qk_param_as_int()to obtain the integer value of a parameter that can only be represented by an integer. -
qk_circuit_barrier()can now accept a null pointer as thequbitsargument, in which casenum_qubitsis ignored, and the barrier is applied to all qubits. -
Two new functions,
qk_circuit_view_instruction()andqk_dag_view_instruction(), were added as mirrors toqk_circuit_get_instruction()andqk_dag_get_instruction(), respectively, writing out a newQkCircuitInstructionViewobject.These
viewfunctions produce direct views into the internal data without any allocations, which is more performant, but requires some special handling to use the non-idiomatic data formats from C; see the documentation ofQkCircuitInstructionView. -
Added
qk_param_stride(), which returns the runtime size in bytes needed to offsetQkParam *pointers that point to contiguous arrays. -
The C API now has a pass manager framework for writing and executing compiler passes. The new
QkPassManagermanages the execution; it can be populated withQkPassobjects viaqk_passmanager_push_pass()and be executed usingqk_passmanager_run_simple(). The pass manager and passes can report errors throughQkCompilationError.Passes are defined through a vtable,
QkPassVtable, and declare their input and output IR with anQkIrHandle, which can describe either a dynamically defined C IR or a built-in Qiskit IR. The pass manager uses these handles to verify the pipeline, enabling type-checked cross-language compiler pipelines.The functionality included in this release is limited and we expect to expand the C pass manager framework in a backward-compatible manner, for example, with additional execution modes of the pass manager, callbacks, and pass context handling.
-
Added C API functions to construct n-local circuits:
qk_circuit_library_n_local(): Constructs an n-local variational circuit.qk_circuit_library_n_local_settings_default(): Generates default options forqk_circuit_library_n_local().
The following helper structs were also added:
QkNLocalSettings: Holds settings needed to build the n-local circuit.QkEntanglementStrategy: Enum representing all the strategies that can be used for the circuit entanglement blocks.
-
Added
qk_obs_with_capacity()for constructing emptyQkObsinstances with a pre-allocated capacity for terms. -
Added QPY serialization and deserialization to the C API. Multiple
QkCircuitobjects can now be serialized into a single QPY stream in the latest QPY version, either to a buffer withqk_qpy_dump_buffer()or saved to a file withqk_qpy_dump_file(). Both functions have an alternative*_with_versionvariant that allows specifying the QPY version used for serialization.These dump functions operate on native circuits without interacting with Python. If you’re using the C API in a Python extension you should use the Python functions:
qpy.dump()andqpy.load()as the C API functions will return an error if Python is required to create or load a QPY payload from the circuit.All circuits in a QPY stream can be deserialized from a buffer or file with
qk_qpy_load_buffer()andqk_qpy_load_file()(the version is handled automatically; no need for variants).To free the buffer returned by
qk_qpy_dump_buffer()andqk_qpy_dump_buffer_with_version(), callqk_qpy_free_buffer(). Circuit arrays returned byqk_qpy_load_buffer()andqk_qpy_load_file()must be released withqk_qpy_free_circuits().Each function that can fail accepts a nullable output pointer for a diagnostic error string. When populated, the string contains details from the underlying QPY error and must be released with
qk_str_free().Also added
qk_qpy_read_min_version()andqk_qpy_write_min_version(), which return the oldest QPY format versions the loaded library can read and write, respectively.The new functions are:
-
The C circuit drawer now renders
Barrierlabels, matching the behavior of the Python text drawer. The label is drawn above the top-most wire of the barrier and is truncated, with"..."appended, when it is longer than the configured number of characters (16 by default). -
QkCircuitDrawerConfighas a newbarrier_label_lenfield, which controls the number of characters to display for barrier labels. Longer labels are truncated at that length and"..."is appended. Setting the field to0applies the default truncation length of 16 characters, so existing initializers that omit the field keep the default behavior.
Circuits Features
-
The type that backs
QuantumCircuit._datais now nameable asqiskit.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_dataattribute. -
Conversions between
DAGCircuitandQuantumCircuitnow shallow-copy anymetadataif thecopy_operations=Trueargument is set incircuit_to_dag(),dag_to_circuit(),QuantumCircuit.to_dag()orDAGCircuit.to_circuit(). This transitively affects compilation functions such asPassManager.run()andtranspile(). -
Added support for passing an iterable of operation types to
DAGCircuit.op_nodes(), for exampledag.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 ofMCPhaseGate, 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()andMCXGatewith no ancilla qubits. -
Added a compact exact decomposition for a singly-controlled
RCCXGate. CallingRCCXGate.control()with one control now usesRC3XGateandCSdgGate, 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
labelargument to single-gate instruction methods onQuantumCircuitthat 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
labelargument to theRVGateconstructor. -
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 asa + b - a - bto zero.
OpenQASM Features
- The OpenQASM 2 importer (
qasm2.load()andqasm2.loads()) can now handle arbitrarily deep classical expressions. They no longer issueRecursionErrorbased on the system recursion limit (sys.getrecursionlimit()).
QPY Features
- QPY format version 18 significantly decreases the data size for most
ClassicalRegisterandQuantumRegisterobjects in aQuantumCircuit. 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
SparseObservablehas a new methodto_matrix(). This method returns the dense matrix representation of the observable. Its reduced time complexity is where 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 ancillas for larger gates. -
The clean-ancilla
synth_mcx_n_clean_m15()implementation now also uses ancillas instead of , without changing its T or CX counts. Thus,QuantumCircuit.mcry()withmode=Nonecan automatically selectbasicmode when at least clean ancillas are available. -
Added a new plugin,
PauliEvolutionSynthesisMcts, for synthesizingPauliEvolutionGateobjects. 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,PauliEvolutionSynthesisMctstypically requires more runtime but often produces higher-quality circuits. It is also significantly faster thanPauliEvolutionSynthesisRustiqwhile generally achieving better synthesis results.The quality of the generated circuits can be further improved by increasing the
num_simulationsoption, 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 thansynth_mcx_noaux_v24(). Note that although this synthesis method grows quadratically in the number of controls, while the method insynth_mcx_noaux_hp24()grows linearly in the number of controls, it still yields better CX counts where .
Transpiler Features
-
Added an
approximation_degreeparameter to theCommutativeCancellationtranspiler pass. The parameter accepts a floating-point value between0and1(with a default1.0). This parameter is forwarded to the underlying commutation analysis for identifying gates that can be cancelled. The preset pass managers passpass_manager_config.approximation_degreetoCommutativeCancellation, using1.0when the config value isNone. -
Added the
mcx.n_dirty_m15high-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 usingHLSConfig, for example asHLSConfig(mcx=["n_dirty_m15"]). The plugin requires clean or dirty ancillas for , and one ancilla for . -
Added a new high-level synthesis plugin
MCXSynthesisNoAuxSP22for the synthesis ofMCXGatewith no ancilla qubits. -
Added a new
optimization_levelargument to theHighLevelSynthesistranspiler pass. This allows the pass to select synthesis methods that can produce more optimized circuits at the expense of increased runtime. -
Added the
PauliEvolutionSynthesisMctsplugin to the default synthesis plugin forPauliEvolutionGate. The plugin may be selected whenoptimization_level >= 2and 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 aTargetinstance as the second positional argument (thebackendparameter). When aTargetis passed this way, it is treated as if it had been passed via thetargetkeyword argument, consistent with the existing behaviour ofgenerate_preset_pass_manager(). This allows users to write:tqc = transpile(circuit, target)instead of:
tqc = transpile(circuit, target=target)A
TypeErroris raised if aTargetis passed positionally andtargetis also specified as a keyword argument. Fixed #15066.
Visualization Features
-
pi_checkand circuit visualization now print rotation angles as π fractions with higher integers, up to 100 (for example3π/35or17πinstead of decimal approximations).See #16356.
C API Upgrade Notes
-
Added variants
QkDelayUnit_DT,QkDelayUnit_EXPR, andQkDelayUnit_Unknownto theQkDelayUnitenumeration. The C compiler may warn you about any switch statement that usesQkDelayUnitand misses the cases for the new variants. -
When adding a delay to a
QkCircuitusingqk_circuit_delay()with units ofQkDelayUnit_DT,QkDelayUnit_EXPR, orQkDelayUnit_Unknown, the operation will fail with an exit code. For more detail check the updated documentation forqk_circuit_delay().
Circuits Upgrade Notes
-
The
Delayinstruction in circuits now has an upper bound of2**63 - 1ondtdurations. This is a consequence of the backing data model moving to Rust. -
The metadata attributes of
DAGCircuit.metadataandDAGCircuit.nameare no longer guaranteed to be preserved for any nested instance ofControlFlowOpwhen they contain circuit blocks of typeDAGCircuit. 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/lnof a non-positive argument,^with a negative base and non-integer exponent, and division by zero now all raiseQASM2ParseError, where they previously raisedValueError,CircuitErrorandZeroDivisionErrorrespectively. They are still raised lazily, when the gate’sdefinitionis 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 theversionargument of the onqpy.dump(). For more information about the format changes see the QPY Version 18 docs.
Miscellaneous Upgrade Notes
- The use of
multiprocessingwithparallel_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 useparallel_map()such astranspile()andPassManager.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 asqiskit-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 withparallel_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"usingmultiprocessing.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 variableQISKIT_PARALLEL=TRUE, or setparalleltoTruein your user configuration file.
Build System Changes
-
The minimum version of the build dependency
setuptools-rustwas bumped to 1.13, to use the newExtension(generated_files=...)argument. -
The minimum supported Rust version (MSRV) to build Qiskit from source is now 1.89.
-
SparsePauliOp.simplify()no longer requires the optionalsympydependency when simplifying operators withParameterExpressioncoefficients. It instead relies on Qiskit’s internal symbolic engine.
Bug Fixes
-
Fixed
CommutativeCancellationincorrectly shifting the global phase by when accumulating a rotation using aPhaseGateorU1Gate. 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()anddumps_experimental()incorrectly outputting aussuffix for delays specified inms. -
Fixed the conversion to
nsinqasm3.dump_experimental()anddumps_experimental()when outputting delays specified inps. -
qk_control_flow_instruction_free()now safely accepts null pointers, consistent with the rest of the C API. See #17049. -
Fixed a bug in
CommutationCheckerwhen checking commutativity of parameterized gates, such asRXGate, when thegatesargument is specified. Fixed #16407. -
Fixed a bug in
CommutationCheckerwhere passing an emptygatesset now returnsFalseinstead of behaving like no filter was specified. -
The
qargsparameter is now correctly marked asconst(const uint32_t *) in bothqk_target_entry_add_property()andqk_target_update_property(). -
CouplingMapno longer stores parallel edges. A coupling given more than once, whether to the constructor or toadd_edge(), now collapses onto the existing edge instead of being stored twice. Fixed #16987. -
Fixed a bug where
CouplingMap.is_symmetriccould falsely reportTruewhen an edge was duplicated. -
Fixed a bug in
Optimize1qGatesDecompositionwhere the choice among the possible Euler bases for a resynthesized run ignored the error rates of thetargetand 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 thetarget, as it did before the pass was ported to Rust. When notargetis given (or it has no error rates), the selection still minimizes the gate count. Fixed #16460. -
BitArray.from_counts()andBitArray.from_samples()now raise aValueErrorwith a descriptive message, instead of an obscureOverflowError(int too big to convert), when a value does not fit in the requestednum_bits. -
Fixed a deadlock in
CommutationAnalysisandCommutativeCancellationwhen running multithreaded and the commutation of custom Python-defined gates had to be computed from their matrices. Fixed #16937. -
Fixed parameter loss in
Commuting2qBlockwhere theparamsattribute 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 inParameterExpressionobjects. Fixed #16456. -
Fixed an inconsistency in
ConsolidateBlocks, which removed identity-equivalent sequences differently from howRemoveIdentityEquivalentand Qiskit’s other transpiler passes do. This has been fixed andConsolidateBlocksnow 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
ConsolidateBlocksincorrectly removing non-identity gates wider than 2 qubits with two unit roots present at the beginning of their main diagonal. Fixed #16852. -
UnitarySynthesisno 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
ParameterExpressionequality so that mathematically equivalent expressions built via division and negative exponentiation (for example,1 / xandx ** -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. -
OneQubitEulerDecomposerwith 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 onphi + lam, but the two angles were checked separately, so a case likeU(0, -pi, -pi)was not recognised as an identity. This also removes the redundant one-qubit gates thatTwoQubitBasisDecomposerproduced with those bases, for example when decomposingCXGatein theCXbasis. Fixes #9315. -
Fixed an issue with
qpy.load()not respecting themin_qpy_versionuser 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 aQpyErrorwhich 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
OptimizeSwapBeforeMeasurethat 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 aQpyErrorinstead. -
Fixed a bug in QPY serialization where
ParameterExpressionobjects 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,eulerand their Unicode letter aliasesπ,τ) were exported without renaming. The resulting programs could not be re-parsed withqasm3.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, aParameternamedpiis exported aspi_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
SparseObservabledata. Fixed #16722. -
Fixed a panic in
qs_decomposition()(and therefore inUnitaryGate.definition) when called on a unitary, that is, a unitary acting on zero qubits. The function now returns a zero-qubitQuantumCircuitwhose 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 returnscomplexvalues when the input coefficients are complex, andfloatvalues otherwise. Fixed #11393. -
Fix a correctness bug in
TwoQubitBasisDecomposerthat 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 instead of . -
Fixed a stack overflow when destructing very deeply nested trees of
ParameterExpression. -
PassManager.run()no longer clobbers theoriginal_qubit_indicesornum_input_qubitskeys if they are set in a givenproperty_setargument. See #8622.
Performance Improvements
-
qk_circuit_barrier()no longer re-allocates a temporary buffer to view thequbitsarray. -
Improves runtime performance of the
add_register()method onQuantumCircuit. Consequently, this change improves performance when creatingQuantumCircuitas well. Generally, the time complexity of checking register name presence was reduced to from . 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()andPauliList.evolve()are faster in many cases whereotheris aCliffordandframeis'h'(Heisenberg). -
The methods
Pauli.evolve()andPauliList.evolve()are now significantly faster at Schrödinger-frame evolution by aCliffordwhen the Paulis have few non-identity terms. See #16835. -
QPY version 18 now stores each
ParameterVectoronce per circuit payload, in a newPARAMETER_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_OBSERVABLEpayload fromuint16_ttouint8_t, reducing the representation forSparseObservableinstances 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(), andsynth_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.