Skip to content

Commit dadbc5c

Browse files
Merge branch 'main' into fix-hashbrown-vuln
2 parents d362111 + 55d2da8 commit dadbc5c

21 files changed

+645
-500
lines changed

.github/workflows/wheels-build.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ on:
6969
python-version:
7070
description: "The Python version to use to host the build runner."
7171
type: string
72-
default: "3.10"
72+
default: "3.13"
7373
required: false
7474

7575
pgo:
@@ -127,7 +127,7 @@ jobs:
127127
env:
128128
PGO_WORK_DIR: ${{ github.workspace }}/pgo-data
129129
PGO_OUT_PATH: ${{ github.workspace }}/merged.profdata
130-
- uses: pypa/cibuildwheel@v2.21.3
130+
- uses: pypa/cibuildwheel@v2.22.0
131131
- uses: actions/upload-artifact@v4
132132
with:
133133
path: ./wheelhouse/*.whl
@@ -152,7 +152,7 @@ jobs:
152152
with:
153153
components: llvm-tools-preview
154154
- name: Build wheels
155-
uses: pypa/cibuildwheel@v2.21.3
155+
uses: pypa/cibuildwheel@v2.22.0
156156
env:
157157
CIBW_SKIP: 'pp* cp36-* cp37-* cp38-* *musllinux* *amd64 *x86_64'
158158
- uses: actions/upload-artifact@v4
@@ -174,7 +174,7 @@ jobs:
174174
- uses: docker/setup-qemu-action@v3
175175
with:
176176
platforms: all
177-
- uses: pypa/cibuildwheel@v2.21.3
177+
- uses: pypa/cibuildwheel@v2.22.0
178178
env:
179179
CIBW_ARCHS_LINUX: s390x
180180
CIBW_TEST_SKIP: "cp*"
@@ -197,7 +197,7 @@ jobs:
197197
- uses: docker/setup-qemu-action@v3
198198
with:
199199
platforms: all
200-
- uses: pypa/cibuildwheel@v2.21.3
200+
- uses: pypa/cibuildwheel@v2.22.0
201201
env:
202202
CIBW_ARCHS_LINUX: ppc64le
203203
CIBW_TEST_SKIP: "cp*"
@@ -219,7 +219,7 @@ jobs:
219219
- uses: docker/setup-qemu-action@v3
220220
with:
221221
platforms: all
222-
- uses: pypa/cibuildwheel@v2.21.3
222+
- uses: pypa/cibuildwheel@v2.22.0
223223
env:
224224
CIBW_ARCHS_LINUX: aarch64
225225
CIBW_TEST_COMMAND: cp -r {project}/test . && QISKIT_PARALLEL=FALSE stestr --test-path test/python run --abbreviate -n test.python.compiler.test_transpiler

crates/accelerate/src/commutation_checker.rs

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,24 +28,29 @@ use qiskit_circuit::circuit_instruction::{ExtraInstructionAttributes, OperationF
2828
use qiskit_circuit::dag_node::DAGOpNode;
2929
use qiskit_circuit::imports::QI_OPERATOR;
3030
use qiskit_circuit::operations::OperationRef::{Gate as PyGateType, Operation as PyOperationType};
31-
use qiskit_circuit::operations::{Operation, OperationRef, Param, StandardGate};
31+
use qiskit_circuit::operations::{
32+
get_standard_gate_names, Operation, OperationRef, Param, StandardGate,
33+
};
3234
use qiskit_circuit::{BitType, Clbit, Qubit};
3335

3436
use crate::unitary_compose;
3537
use crate::QiskitError;
3638

39+
const TWOPI: f64 = 2.0 * std::f64::consts::PI;
40+
41+
// These gates do not commute with other gates, we do not check them.
3742
static SKIPPED_NAMES: [&str; 4] = ["measure", "reset", "delay", "initialize"];
38-
static NO_CACHE_NAMES: [&str; 2] = ["annotated", "linear_function"];
43+
44+
// We keep a hash-set of operations eligible for commutation checking. This is because checking
45+
// eligibility is not for free.
3946
static SUPPORTED_OP: Lazy<HashSet<&str>> = Lazy::new(|| {
4047
HashSet::from([
4148
"rxx", "ryy", "rzz", "rzx", "h", "x", "y", "z", "sx", "sxdg", "t", "tdg", "s", "sdg", "cx",
4249
"cy", "cz", "swap", "iswap", "ecr", "ccx", "cswap",
4350
])
4451
});
4552

46-
const TWOPI: f64 = 2.0 * std::f64::consts::PI;
47-
48-
// map rotation gates to their generators, or to ``None`` if we cannot currently efficiently
53+
// Map rotation gates to their generators, or to ``None`` if we cannot currently efficiently
4954
// represent the generator in Rust and store the commutation relation in the commutation dictionary
5055
static SUPPORTED_ROTATIONS: Lazy<HashMap<&str, Option<OperationRef>>> = Lazy::new(|| {
5156
HashMap::from([
@@ -322,15 +327,17 @@ impl CommutationChecker {
322327
(qargs1, qargs2)
323328
};
324329

325-
let skip_cache: bool = NO_CACHE_NAMES.contains(&first_op.name()) ||
326-
NO_CACHE_NAMES.contains(&second_op.name()) ||
327-
// Skip params that do not evaluate to floats for caching and commutation library
328-
first_params.iter().any(|p| !matches!(p, Param::Float(_))) ||
329-
second_params.iter().any(|p| !matches!(p, Param::Float(_)))
330-
&& !SUPPORTED_OP.contains(op1.name())
331-
&& !SUPPORTED_OP.contains(op2.name());
332-
333-
if skip_cache {
330+
// For our cache to work correctly, we require the gate's definition to only depend on the
331+
// ``params`` attribute. This cannot be guaranteed for custom gates, so we only check
332+
// the cache for our standard gates, which we know are defined by the ``params`` AND
333+
// that the ``params`` are float-only at this point.
334+
let whitelist = get_standard_gate_names();
335+
let check_cache = whitelist.contains(&first_op.name())
336+
&& whitelist.contains(&second_op.name())
337+
&& first_params.iter().all(|p| matches!(p, Param::Float(_)))
338+
&& second_params.iter().all(|p| matches!(p, Param::Float(_)));
339+
340+
if !check_cache {
334341
return self.commute_matmul(
335342
py,
336343
first_op,
@@ -630,21 +637,24 @@ fn map_rotation<'a>(
630637
) -> (&'a OperationRef<'a>, &'a [Param], bool) {
631638
let name = op.name();
632639
if let Some(generator) = SUPPORTED_ROTATIONS.get(name) {
633-
// if the rotation angle is below the tolerance, the gate is assumed to
640+
// If the rotation angle is below the tolerance, the gate is assumed to
634641
// commute with everything, and we simply return the operation with the flag that
635-
// it commutes trivially
642+
// it commutes trivially.
636643
if let Param::Float(angle) = params[0] {
637644
if (angle % TWOPI).abs() < tol {
638645
return (op, params, true);
639646
};
640647
};
641648

642-
// otherwise, we check if a generator is given -- if not, we'll just return the operation
643-
// itself (e.g. RXX does not have a generator and is just stored in the commutations
644-
// dictionary)
649+
// Otherwise we need to cover two cases -- either a generator is given, in which case
650+
// we return it, or we don't have a generator yet, but we know we have the operation
651+
// stored in the commutation library. For example, RXX does not have a generator in Rust
652+
// yet (PauliGate is not in Rust currently), but it is stored in the library, so we
653+
// can strip the parameters and just return the gate.
645654
if let Some(gate) = generator {
646655
return (gate, &[], false);
647656
};
657+
return (op, &[], false);
648658
}
649659
(op, params, false)
650660
}

crates/circuit/src/operations.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,11 @@ static STANDARD_GATE_NAME: [&str; STANDARD_GATE_SIZE] = [
431431
"rcccx", // 51 ("rc3x")
432432
];
433433

434+
/// Get a slice of all standard gate names.
435+
pub fn get_standard_gate_names() -> &'static [&'static str] {
436+
&STANDARD_GATE_NAME
437+
}
438+
434439
impl StandardGate {
435440
pub fn create_py_op(
436441
&self,

qiskit/circuit/library/standard_gates/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
from .y import YGate, CYGate
4444
from .z import ZGate, CZGate, CCZGate
4545
from .global_phase import GlobalPhaseGate
46-
from .multi_control_rotation_gates import mcrx, mcry, mcrz
4746

4847

4948
def get_standard_gate_name_mapping():

0 commit comments

Comments
 (0)