instruction.repeat (#2901)

* from unittest.mock import patch

* .

* moving from a different branch to master

* clean up import

* style
This commit is contained in:
Luciano 2019-08-06 11:46:28 -04:00 committed by Kevin Krsulich
parent fa72ba6640
commit b970a21796
3 changed files with 260 additions and 0 deletions

View File

@ -42,6 +42,10 @@ class Gate(Instruction):
"""
raise QiskitError("to_matrix not defined for this {}".format(type(self)))
def _return_repeat(self, exponent):
return Gate(name="%s*%s" % (self.name, exponent), num_qubits=self.num_qubits,
params=self.params)
def assemble(self):
"""Assemble a QasmQobjInstruction"""
instruction = super().assemble()

View File

@ -39,6 +39,7 @@ import numpy
from qiskit.qasm.node import node
from qiskit.exceptions import QiskitError
from qiskit.circuit.quantumregister import QuantumRegister
from qiskit.circuit.classicalregister import ClassicalRegister
from qiskit.circuit.parameter import Parameter
from qiskit.qobj.models.qasm import QasmQobjInstruction
@ -311,3 +312,31 @@ class Instruction:
flat_qargs = [qarg for sublist in qargs for qarg in sublist]
flat_cargs = [carg for sublist in cargs for carg in sublist]
yield flat_qargs, flat_cargs
def _return_repeat(self, exponent):
return Instruction(name="%s*%s" % (self.name, exponent), num_qubits=self.num_qubits,
num_clbits=self.num_clbits, params=self.params)
def repeat(self, n):
"""Creates an instruction with `gate` repeated `n` amount of times.
Args:
n (int): Number of times to repeat the instruction
Returns:
Instruction: Containing the definition.
Raises:
QiskitError: If n < 1.
"""
if int(n) != n or n < 1:
raise QiskitError("Repeat can only be called with strictly positive integer.")
n = int(n)
instruction = self._return_repeat(n)
qargs = [] if self.num_qubits == 0 else QuantumRegister(self.num_qubits, 'q')
cargs = [] if self.num_clbits == 0 else ClassicalRegister(self.num_clbits, 'c')
instruction.definition = [(self, qargs[:], cargs[:])] * n
return instruction

View File

@ -0,0 +1,227 @@
# -*- coding: utf-8 -*-
# This code is part of Qiskit.
#
# (C) Copyright IBM 2019.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
"""Test Qiskit's repeat instruction operation."""
import unittest
from numpy import pi
from qiskit.transpiler import PassManager
from qiskit import QuantumRegister, QuantumCircuit, ClassicalRegister
from qiskit.test import QiskitTestCase
from qiskit.extensions import SGate, U3Gate, UnitaryGate, CnotGate
from qiskit.circuit import Instruction, Measure, Gate
from qiskit.transpiler.passes import Unroller
from qiskit.exceptions import QiskitError
class TestRepeatInt1Q(QiskitTestCase):
"""Test gate_q1.repeat() with integer"""
def test_standard_1Q_two(self):
"""Test standard gate.repeat(2) method.
"""
qr = QuantumRegister(1, 'qr')
expected_circ = QuantumCircuit(qr)
expected_circ.append(SGate(), [qr[0]])
expected_circ.append(SGate(), [qr[0]])
expected = expected_circ.to_instruction()
result = SGate().repeat(2)
self.assertEqual(result.name, 's*2')
self.assertEqual(result.definition, expected.definition)
self.assertIsInstance(result, Gate)
def test_standard_1Q_one(self):
"""Test standard gate.repeat(1) method.
"""
qr = QuantumRegister(1, 'qr')
expected_circ = QuantumCircuit(qr)
expected_circ.append(SGate(), [qr[0]])
expected = expected_circ.to_instruction()
result = SGate().repeat(1)
self.assertEqual(result.name, 's*1')
self.assertEqual(result.definition, expected.definition)
self.assertIsInstance(result, Gate)
class TestRepeatInt2Q(QiskitTestCase):
"""Test gate_q2.repeat() with integer"""
def test_standard_2Q_two(self):
"""Test standard 2Q gate.repeat(2) method.
"""
qr = QuantumRegister(2, 'qr')
expected_circ = QuantumCircuit(qr)
expected_circ.append(CnotGate(), [qr[0], qr[1]])
expected_circ.append(CnotGate(), [qr[0], qr[1]])
expected = expected_circ.to_instruction()
result = CnotGate().repeat(2)
self.assertEqual(result.name, 'cx*2')
self.assertEqual(result.definition, expected.definition)
self.assertIsInstance(result, Gate)
def test_standard_2Q_one(self):
"""Test standard 2Q gate.repeat(1) method.
"""
qr = QuantumRegister(2, 'qr')
expected_circ = QuantumCircuit(qr)
expected_circ.append(CnotGate(), [qr[0], qr[1]])
expected = expected_circ.to_instruction()
result = CnotGate().repeat(1)
self.assertEqual(result.name, 'cx*1')
self.assertEqual(result.definition, expected.definition)
self.assertIsInstance(result, Gate)
class TestRepeatIntMeasure(QiskitTestCase):
"""Test Measure.repeat() with integer"""
def test_measure_two(self):
"""Test Measure.repeat(2) method.
"""
qr = QuantumRegister(1, 'qr')
cr = ClassicalRegister(1, 'cr')
expected_circ = QuantumCircuit(qr, cr)
expected_circ.append(Measure(), [qr[0]], [cr[0]])
expected_circ.append(Measure(), [qr[0]], [cr[0]])
expected = expected_circ.to_instruction()
result = Measure().repeat(2)
self.assertEqual(result.name, 'measure*2')
self.assertEqual(result.definition, expected.definition)
self.assertIsInstance(result, Instruction)
self.assertNotIsInstance(result, Gate)
def test_measure_one(self):
"""Test Measure.repeat(1) method.
"""
qr = QuantumRegister(1, 'qr')
cr = ClassicalRegister(1, 'cr')
expected_circ = QuantumCircuit(qr, cr)
expected_circ.append(Measure(), [qr[0]], [cr[0]])
expected = expected_circ.to_instruction()
result = Measure().repeat(1)
self.assertEqual(result.name, 'measure*1')
self.assertEqual(result.definition, expected.definition)
self.assertIsInstance(result, Instruction)
self.assertNotIsInstance(result, Gate)
class TestRepeatUnroller(QiskitTestCase):
"""Test unrolling Gate.repeat"""
def test_unroller_two(self):
"""Test unrolling gate.repeat(2).
"""
qr = QuantumRegister(1, 'qr')
circuit = QuantumCircuit(qr)
circuit.append(SGate().repeat(2), [qr[0]])
result = PassManager(Unroller('u3')).run(circuit)
expected = QuantumCircuit(qr)
expected.append(U3Gate(0, 0, pi / 2), [qr[0]])
expected.append(U3Gate(0, 0, pi / 2), [qr[0]])
self.assertEqual(result, expected)
def test_unroller_one(self):
"""Test unrolling gate.repeat(1).
"""
qr = QuantumRegister(1, 'qr')
circuit = QuantumCircuit(qr)
circuit.append(SGate().repeat(1), [qr[0]])
result = PassManager(Unroller('u3')).run(circuit)
expected = QuantumCircuit(qr)
expected.append(U3Gate(0, 0, pi / 2), [qr[0]])
self.assertEqual(result, expected)
class TestRepeatErrors(QiskitTestCase):
"""Test when Gate.repeat() should raise."""
def test_unitary_no_int(self):
"""Test UnitaryGate.repeat(2/3) method. Raises, since n is not int.
"""
with self.assertRaises(QiskitError) as context:
_ = UnitaryGate([[0, 1j], [-1j, 0]]).repeat(2 / 3)
self.assertIn('strictly positive integer', str(context.exception))
def test_starndard_no_int(self):
"""Test standard Gate.repeat(2/3) method. Raises, since n is not int.
"""
with self.assertRaises(QiskitError) as context:
_ = SGate().repeat(2 / 3)
self.assertIn('strictly positive integer', str(context.exception))
def test_measure_zero(self):
"""Test Measure.repeat(0) method. Raises, since n<1
"""
with self.assertRaises(QiskitError) as context:
_ = Measure().repeat(0)
self.assertIn('strictly positive integer', str(context.exception))
def test_standard_1Q_zero(self):
"""Test standard 2Q gate.repeat(0) method. Raises, since n<1.
"""
with self.assertRaises(QiskitError) as context:
_ = SGate().repeat(0)
self.assertIn('strictly positive integer', str(context.exception))
def test_standard_1Q_minus_one(self):
"""Test standard 2Q gate.repeat(-1) method. Raises, since n<1.
"""
with self.assertRaises(QiskitError) as context:
_ = SGate().repeat(-1)
self.assertIn('strictly positive integer', str(context.exception))
def test_standard_2Q_minus_one(self):
"""Test standard 2Q gate.repeat(-1) method. Raises, since n<1.
"""
with self.assertRaises(QiskitError) as context:
_ = CnotGate().repeat(-1)
self.assertIn('strictly positive integer', str(context.exception))
def test_measure_minus_one(self):
"""Test Measure.repeat(-1) method. Raises, since n<1
"""
with self.assertRaises(QiskitError) as context:
_ = Measure().repeat(-1)
self.assertIn('strictly positive integer', str(context.exception))
def test_standard_2Q_zero(self):
"""Test standard 2Q gate.repeat(0) method. Raises, since n<1.
"""
with self.assertRaises(QiskitError) as context:
_ = CnotGate().repeat(0)
self.assertIn('strictly positive integer', str(context.exception))
if __name__ == '__main__':
unittest.main()