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

Deprecate circuit.combine and circuit.extend #4208

Merged
merged 50 commits into from
Mar 20, 2021
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
227c6d8
add circuit.compose() method
ajavadia Apr 20, 2020
428b3bd
add inplace arg
ajavadia Apr 21, 2020
40655a8
add tests
ajavadia Apr 21, 2020
84de420
add release note
ajavadia Apr 21, 2020
bd1fc50
missing tests
ajavadia Apr 21, 2020
57a65b6
deprecate circuit.combine() and circuit.extend()
ajavadia Apr 22, 2020
5ad5b7d
fix tests
ajavadia Apr 22, 2020
faad0bb
add release note
ajavadia Apr 22, 2020
f671608
Merge branch 'master' into deprecate-circuit-combine-extend
ajavadia May 1, 2020
70af910
Merge branch 'master' into deprecate-circuit-combine-extend
kdk Jun 30, 2020
ad1f4ae
merge
Jul 12, 2020
2b95850
Merge branch 'master' into deprecate-circuit-combine-extend
Jul 15, 2020
37059d3
unused import
Jul 15, 2020
0b92f7e
Merge branch 'deprecate-circuit-combine-extend' of github.com:ajavadi…
Jul 15, 2020
d42d4e9
Merge branch 'master' into deprecate-circuit-combine-extend
Jul 16, 2020
9a44069
remove repeated method
Jul 16, 2020
a2521ba
inplace
Jul 20, 2020
02a7bd6
Merge branch 'master' into deprecate-circuit-combine-extend
Jul 20, 2020
dd5194d
combine is not inplace
Jul 20, 2020
faade35
Merge branch 'deprecate-circuit-combine-extend' of github.com:ajavadi…
Jul 20, 2020
6a79241
when inplace=True, returns None
Jul 23, 2020
ef99be4
Merge branch 'master' into deprecate-circuit-combine-extend
Jul 23, 2020
dab0e92
Merge branch 'master' into deprecate-circuit-combine-extend
Jul 28, 2020
6ea936a
Merge branch 'master' into deprecate-circuit-combine-extend
Jul 30, 2020
1a96bc0
Update qiskit/circuit/quantumcircuit.py
Aug 4, 2020
eb3fe9b
Update qiskit/circuit/quantumcircuit.py
Aug 4, 2020
8c53b82
Update qiskit/circuit/quantumcircuit.py
Aug 4, 2020
42845b6
Merge branch 'master' of github.com:Qiskit/qiskit-terra into deprecat…
Aug 4, 2020
0df4169
add and iadd
Aug 4, 2020
167febd
Update test/python/circuit/test_circuit_operations.py
Aug 4, 2020
fe1dd45
Update test/python/circuit/test_circuit_operations.py
Aug 4, 2020
5db52f1
reno
Aug 4, 2020
0c447c4
Merge branch 'master' of github.com:Qiskit/qiskit-terra into deprecat…
Aug 11, 2020
7226f51
unused import
Aug 11, 2020
48e8a76
Merge branch 'master' into deprecate-circuit-combine-extend
Cryoris Aug 21, 2020
541fec9
Merge branch 'master' into deprecate-circuit-combine-extend
Cryoris Oct 28, 2020
b738d7e
keep extend functionality as before
Cryoris Oct 28, 2020
60ca072
Merge branch 'master' into deprecate-circuit-combine-extend
Cryoris Nov 4, 2020
58bbbad
update nlocal and deprecate += / + separately
Cryoris Nov 13, 2020
bb1cf0c
Merge branch 'master' into deprecate-circuit-combine-extend
Cryoris Nov 13, 2020
ff1d038
use deprecate_function
Cryoris Nov 13, 2020
51ded6f
Merge branch 'master' into deprecate-circuit-combine-extend
Cryoris Feb 17, 2021
4fe23b1
rm deprecated usage in more tests
Cryoris Feb 19, 2021
443c15b
Merge branch 'deprecate-circuit-combine-extend' of github.com:ajavadi…
Cryoris Feb 19, 2021
abc6c6e
rm trailing reno file
Cryoris Feb 19, 2021
d73c504
Merge branch 'master' into deprecate-circuit-combine-extend
Cryoris Mar 2, 2021
4b40541
rm duplicate import
Cryoris Mar 2, 2021
6408027
Merge branch 'master' into deprecate-circuit-combine-extend
Cryoris Mar 16, 2021
64fb2df
update reno
Cryoris Mar 19, 2021
0545444
Merge branch 'master' into deprecate-circuit-combine-extend
kdk Mar 19, 2021
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
85 changes: 49 additions & 36 deletions qiskit/circuit/quantumcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ def inverse(self):
return inverse_circ

def combine(self, rhs):
"""Append rhs to self if self contains compatible registers.
"""DEPRECATED - Append rhs to self if self contains compatible registers.

Two circuits are compatible if they contain the same registers
or if they contain different registers with unique names. The
Expand All @@ -299,23 +299,13 @@ def combine(self, rhs):
# Check registers in LHS are compatible with RHS
self._check_compatible_regs(rhs)

# Make new circuit with combined registers
combined_qregs = copy.deepcopy(self.qregs)
combined_cregs = copy.deepcopy(self.cregs)

for element in rhs.qregs:
if element not in self.qregs:
combined_qregs.append(element)
for element in rhs.cregs:
if element not in self.cregs:
combined_cregs.append(element)
circuit = QuantumCircuit(*combined_qregs, *combined_cregs)
for instruction_context in itertools.chain(self.data, rhs.data):
circuit._append(*instruction_context)
return circuit
warnings.warn("The QuantumCircuit.combine() method is being deprecated."
"Use the compose() method which is more flexible w.r.t "
"circuit register compatibility.", DeprecationWarning)
1ucian0 marked this conversation as resolved.
Show resolved Hide resolved
return self.compose(rhs)

def extend(self, rhs):
"""Append QuantumCircuit to the right hand side if it contains compatible registers.
"""DEPRECATED - Append QuantumCircuit to the RHS if it contains compatible registers.

Two circuits are compatible if they contain the same registers
or if they contain different registers with unique names. The
Expand All @@ -336,22 +326,44 @@ def extend(self, rhs):
# Check registers in LHS are compatible with RHS
self._check_compatible_regs(rhs)

# Add new registers
for element in rhs.qregs:
if element not in self.qregs:
self.qregs.append(element)
for element in rhs.cregs:
if element not in self.cregs:
self.cregs.append(element)

# Copy the circuit data if rhs and self are the same, otherwise the data of rhs is
# appended to both self and rhs resulting in an infinite loop
data = rhs.data.copy() if rhs is self else rhs.data

# Add new gates
for instruction_context in data:
self._append(*instruction_context)
return self
warnings.warn("The QuantumCircuit.extend() method is being deprecated."
"Use the compose() method which is more flexible w.r.t "
1ucian0 marked this conversation as resolved.
Show resolved Hide resolved
"circuit register compatibility.", DeprecationWarning)
1ucian0 marked this conversation as resolved.
Show resolved Hide resolved
return self.compose(rhs)
1ucian0 marked this conversation as resolved.
Show resolved Hide resolved

def compose(self, other, qubits=None, clbits=None, front=False, inplace=False):
1ucian0 marked this conversation as resolved.
Show resolved Hide resolved
"""Compose circuit with ``other`` circuit, optionally permuting wires.

``other`` can be narrower or of equal width to ``self``.

Args:
other (QuantumCircuit): circuit to compose with self.
qubits (list[Qubit|int]): qubits of self to compose onto.
clbits (list[Clbit|int]): clbits of self to compose onto.
front (bool): If True, front composition will be performed (not implemented yet).
inplace (bool): If True, modify the object. Otherwise return composed circuit.

Returns:
QuantumCircuit: the composed circuit (returns None if inplace==True).

Raises:
CircuitError: if composing on the front.
QiskitError: if ``other`` is wider or there are duplicate edge mappings.
"""
from qiskit.converters.circuit_to_dag import circuit_to_dag
from qiskit.converters.dag_to_circuit import dag_to_circuit
if front:
raise CircuitError("Front composition of QuantumCircuit not supported yet.")

dag_self = circuit_to_dag(self)
dag_other = circuit_to_dag(other)
dag_self.compose(dag_other, qubits=qubits, clbits=clbits, front=front)
composed_circuit = dag_to_circuit(dag_self)
if inplace: # FIXME: this is just a hack for inplace to work. Still copies.
self.__dict__.update(composed_circuit.__dict__)
return None
else:
return dag_to_circuit(dag_self)

def compose(self, other, qubits=None, clbits=None, front=False, inplace=False):
"""Compose circuit with ``other`` circuit or instruction, optionally permuting wires.
Expand Down Expand Up @@ -436,12 +448,13 @@ def clbits(self):
return [cbit for creg in self.cregs for cbit in creg]

def __add__(self, rhs):
"""Overload + to implement self.combine."""
return self.combine(rhs)
"""Overload + to compose two circuits and return resulting circuit."""
return self.compose(rhs, inplace=False)

def __iadd__(self, rhs):
"""Overload += to implement self.extend."""
return self.extend(rhs)
"""Overload += to compose with another circuit inplace."""
self.compose(rhs, inplace=True)
return self

def __len__(self):
"""Return number of operations in circuit."""
Expand Down
1 change: 1 addition & 0 deletions qiskit/dagcircuit/dagcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,7 @@ def compose(self, other, edge_map=None, qubits=None, clbits=None, front=False, i
"Use qubits and clbits args to specify a list of "
"self edges to compose onto.", DeprecationWarning,
stacklevel=2)

if qubits is None:
qubits = []
if clbits is None:
Expand Down
13 changes: 13 additions & 0 deletions releasenotes/notes/circuit-compose-c320c4057cd2bb8f.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
features:
- |
A new ``compose`` method is added to ``QuantumCircuit``. It allows
composition of two quantum circuits without having to turn one into
a gate or instruction. It also allows permutations of qubits/clbits
at the point of composition, as well as optional inplace modification.
deprecations:
- |
The ``DAGCircuit.compose()`` method now takes a list of qubits/clbits
that specify the positional order of bits to compose onto. The
dictionary-based method of mapping using ``edge_map`` arg is
deprecated.
1ucian0 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
deprecations:
- |
Two ``QuantumCircuit`` methods ``combine()`` and ``extend()`` are deprecated,
in favor of ``QuantumCircuit.compose()``. The latter allows more flexibility
in composing two circuits that do not have matching registers. It does not,
however, automatically add qubits/clbits unlike the deprecated methods.
kdk marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 1 addition & 1 deletion test/python/basicaer/test_multi_registers_convention.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def test_circuit_multi(self):
creg0 = ClassicalRegister(2, 'c0')
qreg1 = QuantumRegister(2, 'q1')
creg1 = ClassicalRegister(2, 'c1')
circ = QuantumCircuit(qreg0, qreg1)
circ = QuantumCircuit(qreg0, qreg1, creg0, creg1)
circ.x(qreg0[1])
circ.x(qreg1[0])

Expand Down
4 changes: 3 additions & 1 deletion test/python/circuit/test_circuit_multi_registers.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def test_circuit_multi(self):
creg0 = ClassicalRegister(2, 'c0')
qreg1 = QuantumRegister(2, 'q1')
creg1 = ClassicalRegister(2, 'c1')
circ = QuantumCircuit(qreg0, qreg1)
circ = QuantumCircuit(qreg0, qreg1, creg0, creg1)
circ.x(qreg0[1])
circ.x(qreg1[0])

Expand All @@ -43,6 +43,8 @@ def test_circuit_multi(self):
circ2 = QuantumCircuit()
circ2.add_register(qreg0)
circ2.add_register(qreg1)
circ2.add_register(creg0)
circ2.add_register(creg1)
circ2.x(qreg0[1])
circ2.x(qreg1[0])

Expand Down
45 changes: 5 additions & 40 deletions test/python/circuit/test_circuit_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from qiskit import BasicAer
from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit
from qiskit import execute
from qiskit import QiskitError
from qiskit.circuit.exceptions import CircuitError
from qiskit.test import QiskitTestCase

Expand Down Expand Up @@ -60,24 +61,6 @@ def test_combine_circuit_common(self):
threshold = 0.04 * shots
self.assertDictAlmostEqual(counts, target, threshold)

def test_combine_circuit_different(self):
"""Test combining two circuits with different registers.
"""
qr = QuantumRegister(2)
cr = ClassicalRegister(2)
qc1 = QuantumCircuit(qr)
qc1.x(qr)
qc2 = QuantumCircuit(qr, cr)
qc2.measure(qr, cr)
new_circuit = qc1 + qc2
backend = BasicAer.get_backend('qasm_simulator')
shots = 1024
result = execute(new_circuit, backend=backend, shots=shots,
seed_simulator=78).result()
counts = result.get_counts()
target = {'11': shots}
self.assertEqual(counts, target)

def test_combine_circuit_fail(self):
"""Test combining two circuits fails if registers incompatible.

Expand All @@ -91,8 +74,8 @@ def test_combine_circuit_fail(self):
qc2 = QuantumCircuit(qr2)
qcr3 = QuantumCircuit(cr1)

self.assertRaises(CircuitError, qc1.__add__, qc2)
self.assertRaises(CircuitError, qc1.__add__, qcr3)
self.assertRaises(QiskitError, qc1.__add__, qc2)
self.assertRaises(QiskitError, qc1.__add__, qcr3)
1ucian0 marked this conversation as resolved.
Show resolved Hide resolved

def test_extend_circuit(self):
"""Test extending a circuit with same registers.
Expand All @@ -114,24 +97,6 @@ def test_extend_circuit(self):
threshold = 0.04 * shots
self.assertDictAlmostEqual(counts, target, threshold)

def test_extend_circuit_different_registers(self):
"""Test extending a circuit with different registers.
"""
qr = QuantumRegister(2)
cr = ClassicalRegister(2)
qc1 = QuantumCircuit(qr)
qc1.x(qr)
qc2 = QuantumCircuit(qr, cr)
qc2.measure(qr, cr)
qc1 += qc2
backend = BasicAer.get_backend('qasm_simulator')
shots = 1024
result = execute(qc1, backend=backend, shots=shots,
seed_simulator=78).result()
counts = result.get_counts()
target = {'11': shots}
self.assertEqual(counts, target)

def test_extend_circuit_fail(self):
"""Test extending a circuits fails if registers incompatible.

Expand All @@ -145,8 +110,8 @@ def test_extend_circuit_fail(self):
qc2 = QuantumCircuit(qr2)
qcr3 = QuantumCircuit(cr1)

self.assertRaises(CircuitError, qc1.__iadd__, qc2)
self.assertRaises(CircuitError, qc1.__iadd__, qcr3)
self.assertRaises(QiskitError, qc1.__iadd__, qc2)
self.assertRaises(QiskitError, qc1.__iadd__, qcr3)
1ucian0 marked this conversation as resolved.
Show resolved Hide resolved

def test_measure_args_type_cohesion(self):
"""Test for proper args types for measure function.
Expand Down
2 changes: 1 addition & 1 deletion test/python/circuit/test_parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ def test_circuit_composition(self):
theta = Parameter('θ')
qr = QuantumRegister(1)
cr = ClassicalRegister(1)
qc1 = QuantumCircuit(qr)
qc1 = QuantumCircuit(qr, cr)
qc1.rx(theta, qr)

phi = Parameter('phi')
Expand Down