Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a secure internal path for custom prefixes in registers. #14005

Merged
merged 6 commits into from
Mar 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions crates/circuit/src/bit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -771,6 +771,25 @@ macro_rules! create_bit_object {
})
}

/// Allows for the creation of a new register with a temporary prefix and the
/// same instance counter.
#[pyo3(signature=(size=None, name=None, bits=None))]
#[staticmethod]
fn _new_with_prefix(
py: Python,
size: Option<isize>,
name: Option<String>,
bits: Option<Vec<$bit_struct>>,
) -> PyResult<Py<Self>> {
let name =
format!(
"{}{}",
name.unwrap_or(Self::prefix().to_string()),
$reg_struct::anonymous_instance_count().fetch_add(1, Ordering::Relaxed)
);
Py::new(py, Self::py_new(size, Some(name), bits)?)
}

#[classattr]
fn prefix() -> &'static str {
$pyreg_prefix
Expand Down
4 changes: 2 additions & 2 deletions qiskit/circuit/quantumcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -3889,15 +3889,15 @@ def clear(self) -> None:
def _create_creg(self, length: int, name: str) -> ClassicalRegister:
"""Creates a creg, checking if ClassicalRegister with same name exists"""
if name in [creg.name for creg in self.cregs]:
new_creg = ClassicalRegister(length, name=f"{name}{ClassicalRegister.instance_count}")
new_creg = ClassicalRegister._new_with_prefix(length, name)
else:
new_creg = ClassicalRegister(length, name)
return new_creg

def _create_qreg(self, length: int, name: str) -> QuantumRegister:
"""Creates a qreg, checking if QuantumRegister with same name exists"""
if name in [qreg.name for qreg in self.qregs]:
new_qreg = QuantumRegister(length, name=f"{name}{QuantumRegister.instance_count}")
new_qreg = QuantumRegister._new_with_prefix(length, name)
else:
new_qreg = QuantumRegister(length, name)
return new_qreg
Expand Down
5 changes: 2 additions & 3 deletions qiskit/transpiler/passes/layout/full_ancilla_allocation.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,8 @@ def run(self, dag):

if idle_physical_qubits:
if self.ancilla_name in dag.qregs:
qreg = QuantumRegister(
len(idle_physical_qubits),
name=f"{self.ancilla_name}{QuantumRegister.instances_count + 1}",
qreg = QuantumRegister._new_with_prefix(
len(idle_physical_qubits), self.ancilla_name
)
else:
qreg = QuantumRegister(len(idle_physical_qubits), name=self.ancilla_name)
Expand Down
26 changes: 26 additions & 0 deletions test/python/circuit/test_circuit_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,32 @@ def test_measure_all_repetition(self):
self.assertEqual(len(circuit.cregs[0]), 2) # Both length 2
self.assertEqual(len(circuit.cregs[1]), 2)

def test_measure_all_with_multiple_regs_creation(self):
"""Test measure_all in a circuit where the method is called
multiple times consecutively and checks that a register of
a different name is created on each call."""

circuit = QuantumCircuit(1)

# First call should create a new register
circuit.measure_all()
self.assertEqual(len(circuit.cregs), 1) # One creg
self.assertEqual(len(circuit.cregs[0]), 1) # Of length 1

# Second call should also create a new register
circuit.measure_all()
self.assertEqual(len(circuit.cregs), 2) # Now two cregs
self.assertTrue(all(len(reg) == 1 for reg in circuit.cregs)) # All of length 1
# Check that no name is the same
self.assertEqual(len({reg.name for reg in circuit.cregs}), 2)

# Third call should also create a new register
circuit.measure_all()
self.assertEqual(len(circuit.cregs), 3) # Now three cregs
self.assertTrue(all(len(reg) == 1 for reg in circuit.cregs)) # All of length 1
# Check that no name is the same
self.assertEqual(len({reg.name for reg in circuit.cregs}), 3)

def test_remove_final_measurements(self):
"""Test remove_final_measurements
Removes all measurements at end of circuit.
Expand Down