Skip to content

Commit

Permalink
add QuantumCircuit.from_instructions (#9006)
Browse files Browse the repository at this point in the history
* add QuantumCircuit.from_instructions

* simplify loop

* handle both cases in just one method

* delete stray import

* fix type annotation

* address comments

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
kevinsung and mergify[bot] authored Oct 28, 2022
1 parent 351da44 commit 8b58a8f
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 8 deletions.
40 changes: 40 additions & 0 deletions qiskit/circuit/quantumcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

"""Quantum circuit object."""

from __future__ import annotations
import copy
import itertools
import functools
Expand Down Expand Up @@ -285,6 +286,45 @@ def __init__(
raise TypeError("Only a dictionary or None is accepted for circuit metadata")
self._metadata = metadata

@staticmethod
def from_instructions(
instructions: Iterable[
CircuitInstruction
| tuple[qiskit.circuit.Instruction]
| tuple[qiskit.circuit.Instruction, Iterable[Qubit]]
| tuple[qiskit.circuit.Instruction, Iterable[Qubit], Iterable[Clbit]]
],
*,
name: Optional[str] = None,
global_phase: ParameterValueType = 0,
metadata: Optional[dict] = None,
) -> "QuantumCircuit":
"""Construct a circuit from an iterable of CircuitInstructions.
Args:
instructions: The instructions to add to the circuit.
name: The name of the circuit.
global_phase: The global phase of the circuit in radians.
metadata: Arbitrary key value metadata to associate with the circuit.
Returns:
The quantum circuit.
"""
circuit = QuantumCircuit(name=name, global_phase=global_phase, metadata=metadata)
added_qubits = set()
added_clbits = set()
for instruction in instructions:
if not isinstance(instruction, CircuitInstruction):
instruction = CircuitInstruction(*instruction)
qubits = [qubit for qubit in instruction.qubits if qubit not in added_qubits]
clbits = [clbit for clbit in instruction.clbits if clbit not in added_clbits]
circuit.add_bits(qubits)
circuit.add_bits(clbits)
added_qubits.update(qubits)
added_clbits.update(clbits)
circuit._append(instruction)
return circuit

@property
def data(self) -> QuantumCircuitData:
"""Return the circuit data (instructions and context).
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
features:
- |
Added the method :meth:`.QuantumCircuit.from_instructions`
for constructing a quantum circuit from an iterable of instructions.
83 changes: 75 additions & 8 deletions test/python/circuit/test_circuit_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,23 @@

"""Test Qiskit's QuantumCircuit class."""

from ddt import ddt, data
import numpy as np
from qiskit import BasicAer
from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit
from qiskit import execute
from qiskit.circuit import Gate, Instruction, Parameter, Measure
from ddt import data, ddt

from qiskit import BasicAer, ClassicalRegister, QuantumCircuit, QuantumRegister, execute
from qiskit.circuit import Gate, Instruction, Measure, Parameter
from qiskit.circuit.bit import Bit
from qiskit.circuit.classicalregister import Clbit
from qiskit.circuit.exceptions import CircuitError
from qiskit.circuit.controlflow import IfElseOp
from qiskit.circuit.library import CXGate, HGate
from qiskit.circuit.library.standard_gates import SGate
from qiskit.circuit.quantumcircuit import BitLocations
from qiskit.circuit.quantumcircuitdata import CircuitInstruction
from qiskit.circuit.quantumregister import AncillaQubit, AncillaRegister, Qubit
from qiskit.test import QiskitTestCase
from qiskit.circuit.library.standard_gates import SGate
from qiskit.pulse import DriveChannel, Gaussian, Play, Schedule
from qiskit.quantum_info import Operator
from qiskit.pulse import Schedule, Play, Gaussian, DriveChannel
from qiskit.test import QiskitTestCase


@ddt
Expand Down Expand Up @@ -1262,6 +1264,71 @@ def test_deprecated_reset_function(self):

self.assertEqual(test, expected)

def test_from_instructions(self):
"""Test from_instructions method."""

qreg = QuantumRegister(4)
creg = ClassicalRegister(3)

a, b, c, d = qreg
x, y, z = creg

circuit_1 = QuantumCircuit(2)
circuit_1.x(0)
circuit_2 = QuantumCircuit(2)
circuit_2.y(0)

def instructions():
yield CircuitInstruction(HGate(), [a], [])
yield CircuitInstruction(CXGate(), [a, b], [])
yield CircuitInstruction(Measure(), [a], [x])
yield CircuitInstruction(Measure(), [b], [y])
yield CircuitInstruction(IfElseOp((z, 1), circuit_1, circuit_2), [c, d], [z])

def instruction_tuples():
yield HGate(), [a], []
yield CXGate(), [a, b], []
yield CircuitInstruction(Measure(), [a], [x])
yield Measure(), [b], [y]
yield IfElseOp((z, 1), circuit_1, circuit_2), [c, d], [z]

def instruction_tuples_partial():
yield HGate(), [a]
yield CXGate(), [a, b], []
yield CircuitInstruction(Measure(), [a], [x])
yield Measure(), [b], [y]
yield IfElseOp((z, 1), circuit_1, circuit_2), [c, d], [z]

circuit = QuantumCircuit.from_instructions(instructions())
circuit_tuples = QuantumCircuit.from_instructions(instruction_tuples())
circuit_tuples_partial = QuantumCircuit.from_instructions(instruction_tuples_partial())

expected = QuantumCircuit([a, b, c, d], [x, y, z])
for instruction in instructions():
expected.append(*instruction)

self.assertEqual(circuit, expected)
self.assertEqual(circuit_tuples, expected)
self.assertEqual(circuit_tuples_partial, expected)

def test_from_instructions_metadata(self):
"""Test from_instructions method passes metadata."""
qreg = QuantumRegister(2)
a, b = qreg

def instructions():
yield CircuitInstruction(HGate(), [a], [])
yield CircuitInstruction(CXGate(), [a, b], [])

circuit = QuantumCircuit.from_instructions(instructions(), name="test", global_phase=0.1)

expected = QuantumCircuit([a, b], global_phase=0.1)
for instruction in instructions():
expected.append(*instruction)

self.assertEqual(circuit, expected)
self.assertEqual(circuit.name, "test")


class TestCircuitPrivateOperations(QiskitTestCase):
"""Direct tests of some of the private methods of QuantumCircuit. These do not represent
Expand Down

0 comments on commit 8b58a8f

Please sign in to comment.