mirror of https://github.com/Qiskit/qiskit.git
247 lines
10 KiB
Python
247 lines
10 KiB
Python
# This code is part of Qiskit.
|
|
#
|
|
# (C) Copyright IBM 2023.
|
|
#
|
|
# 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.
|
|
|
|
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring
|
|
|
|
from test import QiskitTestCase
|
|
|
|
from qiskit.circuit import Store, Clbit, CircuitError, QuantumCircuit, ClassicalRegister
|
|
from qiskit.circuit.classical import expr, types
|
|
|
|
|
|
class TestStoreInstruction(QiskitTestCase):
|
|
"""Tests of the properties of the ``Store`` instruction itself."""
|
|
|
|
def test_happy_path_construction(self):
|
|
lvalue = expr.Var.new("a", types.Bool())
|
|
rvalue = expr.lift(Clbit())
|
|
constructed = Store(lvalue, rvalue)
|
|
self.assertIsInstance(constructed, Store)
|
|
self.assertEqual(constructed.lvalue, lvalue)
|
|
self.assertEqual(constructed.rvalue, rvalue)
|
|
|
|
def test_store_to_index(self):
|
|
lvalue = expr.index(expr.Var.new("a", types.Uint(8)), 3)
|
|
rvalue = expr.lift(False)
|
|
constructed = Store(lvalue, rvalue)
|
|
self.assertIsInstance(constructed, Store)
|
|
self.assertEqual(constructed.lvalue, lvalue)
|
|
self.assertEqual(constructed.rvalue, rvalue)
|
|
|
|
def test_implicit_cast(self):
|
|
lvalue = expr.Var.new("a", types.Bool())
|
|
rvalue = expr.Var.new("b", types.Uint(8))
|
|
constructed = Store(lvalue, rvalue)
|
|
self.assertIsInstance(constructed, Store)
|
|
self.assertEqual(constructed.lvalue, lvalue)
|
|
self.assertEqual(constructed.rvalue, expr.Cast(rvalue, types.Bool(), implicit=True))
|
|
|
|
def test_rejects_non_lvalue(self):
|
|
not_an_lvalue = expr.logic_and(
|
|
expr.Var.new("a", types.Bool()), expr.Var.new("b", types.Bool())
|
|
)
|
|
rvalue = expr.lift(False)
|
|
with self.assertRaisesRegex(CircuitError, "not an l-value"):
|
|
Store(not_an_lvalue, rvalue)
|
|
|
|
not_an_lvalue = expr.index(expr.shift_right(expr.Var.new("a", types.Uint(8)), 1), 2)
|
|
rvalue = expr.lift(True)
|
|
with self.assertRaisesRegex(CircuitError, "not an l-value"):
|
|
Store(not_an_lvalue, rvalue)
|
|
|
|
def test_rejects_explicit_cast(self):
|
|
lvalue = expr.Var.new("a", types.Uint(16))
|
|
rvalue = expr.Var.new("b", types.Uint(8))
|
|
with self.assertRaisesRegex(CircuitError, "an explicit cast is required"):
|
|
Store(lvalue, rvalue)
|
|
|
|
def test_rejects_dangerous_cast(self):
|
|
lvalue = expr.Var.new("a", types.Uint(8))
|
|
rvalue = expr.Var.new("b", types.Uint(16))
|
|
with self.assertRaisesRegex(CircuitError, "an explicit cast is required.*may be lossy"):
|
|
Store(lvalue, rvalue)
|
|
|
|
def test_rejects_c_if(self):
|
|
instruction = Store(expr.Var.new("a", types.Bool()), expr.Var.new("b", types.Bool()))
|
|
with self.assertRaises(NotImplementedError):
|
|
with self.assertWarns(DeprecationWarning):
|
|
instruction.c_if(Clbit(), False)
|
|
|
|
|
|
class TestStoreCircuit(QiskitTestCase):
|
|
"""Tests of the `QuantumCircuit.store` method and appends of `Store`."""
|
|
|
|
def test_produces_expected_operation(self):
|
|
a = expr.Var.new("a", types.Bool())
|
|
value = expr.Value(True, types.Bool())
|
|
|
|
qc = QuantumCircuit(inputs=[a])
|
|
qc.store(a, value)
|
|
self.assertEqual(qc.data[-1].operation, Store(a, value))
|
|
|
|
qc = QuantumCircuit(captures=[a])
|
|
qc.store(a, value)
|
|
self.assertEqual(qc.data[-1].operation, Store(a, value))
|
|
|
|
qc = QuantumCircuit(declarations=[(a, expr.lift(False))])
|
|
qc.store(a, value)
|
|
self.assertEqual(qc.data[-1].operation, Store(a, value))
|
|
|
|
def test_allows_stores_with_clbits(self):
|
|
clbits = [Clbit(), Clbit()]
|
|
a = expr.Var.new("a", types.Bool())
|
|
qc = QuantumCircuit(clbits, inputs=[a])
|
|
qc.store(clbits[0], True)
|
|
qc.store(expr.Var(clbits[1], types.Bool()), a)
|
|
qc.store(clbits[0], clbits[1])
|
|
qc.store(expr.lift(clbits[0]), expr.lift(clbits[1]))
|
|
qc.store(a, expr.lift(clbits[1]))
|
|
|
|
expected = [
|
|
Store(expr.lift(clbits[0]), expr.lift(True)),
|
|
Store(expr.lift(clbits[1]), a),
|
|
Store(expr.lift(clbits[0]), expr.lift(clbits[1])),
|
|
Store(expr.lift(clbits[0]), expr.lift(clbits[1])),
|
|
Store(a, expr.lift(clbits[1])),
|
|
]
|
|
actual = [instruction.operation for instruction in qc.data]
|
|
self.assertEqual(actual, expected)
|
|
|
|
def test_allows_stores_with_cregs(self):
|
|
cregs = [ClassicalRegister(8, "cr1"), ClassicalRegister(8, "cr2")]
|
|
a = expr.Var.new("a", types.Uint(8))
|
|
qc = QuantumCircuit(*cregs, captures=[a])
|
|
qc.store(cregs[0], 0xFF)
|
|
qc.store(expr.Var(cregs[1], types.Uint(8)), a)
|
|
qc.store(cregs[0], cregs[1])
|
|
qc.store(expr.lift(cregs[0]), expr.lift(cregs[1]))
|
|
qc.store(a, cregs[1])
|
|
|
|
expected = [
|
|
Store(expr.lift(cregs[0]), expr.lift(0xFF)),
|
|
Store(expr.lift(cregs[1]), a),
|
|
Store(expr.lift(cregs[0]), expr.lift(cregs[1])),
|
|
Store(expr.lift(cregs[0]), expr.lift(cregs[1])),
|
|
Store(a, expr.lift(cregs[1])),
|
|
]
|
|
actual = [instruction.operation for instruction in qc.data]
|
|
self.assertEqual(actual, expected)
|
|
|
|
def test_allows_stores_with_index(self):
|
|
cr = ClassicalRegister(8, "cr")
|
|
a = expr.Var.new("a", types.Uint(3))
|
|
qc = QuantumCircuit(cr, inputs=[a])
|
|
qc.store(expr.index(cr, 0), False)
|
|
qc.store(expr.index(a, 3), True)
|
|
qc.store(expr.index(cr, a), expr.index(cr, 0))
|
|
expected = [
|
|
Store(expr.index(cr, 0), expr.lift(False)),
|
|
Store(expr.index(a, 3), expr.lift(True)),
|
|
Store(expr.index(cr, a), expr.index(cr, 0)),
|
|
]
|
|
actual = [instruction.operation for instruction in qc.data]
|
|
self.assertEqual(actual, expected)
|
|
|
|
def test_lifts_values(self):
|
|
a = expr.Var.new("a", types.Bool())
|
|
qc = QuantumCircuit(captures=[a])
|
|
qc.store(a, True)
|
|
self.assertEqual(qc.data[-1].operation, Store(a, expr.lift(True)))
|
|
|
|
b = expr.Var.new("b", types.Uint(16))
|
|
qc.add_capture(b)
|
|
qc.store(b, 0xFFFF)
|
|
self.assertEqual(qc.data[-1].operation, Store(b, expr.lift(0xFFFF)))
|
|
|
|
def test_lifts_integer_literals_to_full_width(self):
|
|
a = expr.Var.new("a", types.Uint(8))
|
|
qc = QuantumCircuit(inputs=[a])
|
|
qc.store(a, 1)
|
|
self.assertEqual(qc.data[-1].operation, Store(a, expr.Value(1, a.type)))
|
|
qc.store(a, 255)
|
|
self.assertEqual(qc.data[-1].operation, Store(a, expr.Value(255, a.type)))
|
|
|
|
def test_does_not_widen_bool_literal(self):
|
|
# `bool` is a subclass of `int` in Python (except some arithmetic operations have different
|
|
# semantics...). It's not in Qiskit's value type system, though.
|
|
a = expr.Var.new("a", types.Uint(8))
|
|
qc = QuantumCircuit(captures=[a])
|
|
with self.assertRaisesRegex(CircuitError, "explicit cast is required"):
|
|
qc.store(a, True)
|
|
|
|
def test_rejects_vars_not_in_circuit(self):
|
|
a = expr.Var.new("a", types.Bool())
|
|
b = expr.Var.new("b", types.Bool())
|
|
|
|
qc = QuantumCircuit()
|
|
with self.assertRaisesRegex(CircuitError, "'a'.*not present"):
|
|
qc.store(expr.Var.new("a", types.Bool()), True)
|
|
|
|
# Not the same 'a'
|
|
qc.add_input(a)
|
|
with self.assertRaisesRegex(CircuitError, "'a'.*not present"):
|
|
qc.store(expr.Var.new("a", types.Bool()), True)
|
|
with self.assertRaisesRegex(CircuitError, "'b'.*not present"):
|
|
qc.store(a, b)
|
|
|
|
def test_rejects_bits_not_in_circuit(self):
|
|
a = expr.Var.new("a", types.Bool())
|
|
clbit = Clbit()
|
|
qc = QuantumCircuit(captures=[a])
|
|
with self.assertRaisesRegex(CircuitError, "not present"):
|
|
qc.store(clbit, False)
|
|
with self.assertRaisesRegex(CircuitError, "not present"):
|
|
qc.store(clbit, a)
|
|
with self.assertRaisesRegex(CircuitError, "not present"):
|
|
qc.store(a, clbit)
|
|
|
|
def test_rejects_cregs_not_in_circuit(self):
|
|
a = expr.Var.new("a", types.Uint(8))
|
|
creg = ClassicalRegister(8, "cr1")
|
|
qc = QuantumCircuit(captures=[a])
|
|
with self.assertRaisesRegex(CircuitError, "not present"):
|
|
qc.store(creg, 0xFF)
|
|
with self.assertRaisesRegex(CircuitError, "not present"):
|
|
qc.store(creg, a)
|
|
with self.assertRaisesRegex(CircuitError, "not present"):
|
|
qc.store(a, creg)
|
|
|
|
def test_rejects_non_lvalue(self):
|
|
a = expr.Var.new("a", types.Bool())
|
|
b = expr.Var.new("b", types.Bool())
|
|
qc = QuantumCircuit(inputs=[a, b])
|
|
not_an_lvalue = expr.logic_and(a, b)
|
|
with self.assertRaisesRegex(CircuitError, "not an l-value"):
|
|
qc.store(not_an_lvalue, expr.lift(False))
|
|
|
|
def test_rejects_explicit_cast(self):
|
|
lvalue = expr.Var.new("a", types.Uint(16))
|
|
rvalue = expr.Var.new("b", types.Uint(8))
|
|
qc = QuantumCircuit(inputs=[lvalue, rvalue])
|
|
with self.assertRaisesRegex(CircuitError, "an explicit cast is required"):
|
|
qc.store(lvalue, rvalue)
|
|
|
|
def test_rejects_dangerous_cast(self):
|
|
lvalue = expr.Var.new("a", types.Uint(8))
|
|
rvalue = expr.Var.new("b", types.Uint(16))
|
|
qc = QuantumCircuit(inputs=[lvalue, rvalue])
|
|
with self.assertRaisesRegex(CircuitError, "an explicit cast is required.*may be lossy"):
|
|
qc.store(lvalue, rvalue)
|
|
|
|
def test_rejects_c_if(self):
|
|
a = expr.Var.new("a", types.Bool())
|
|
qc = QuantumCircuit([Clbit()], inputs=[a])
|
|
instruction_set = qc.store(a, True)
|
|
with self.assertRaises(NotImplementedError):
|
|
with self.assertWarns(DeprecationWarning):
|
|
instruction_set.c_if(qc.clbits[0], False)
|