Skip to content

Commit

Permalink
enable bit operations for boolean types (Qiskit#2024)
Browse files Browse the repository at this point in the history
Co-authored-by: Jun Doi <doichan@jp.ibm.com>
  • Loading branch information
hhorii and doichanj committed Jan 17, 2024
1 parent 58045c9 commit 8641d1d
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 7 deletions.
17 changes: 12 additions & 5 deletions src/framework/operations.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -270,9 +270,6 @@ class BinaryExpr : public CExpr {
case BinaryOp::BitAnd:
case BinaryOp::BitOr:
case BinaryOp::BitXor:
if (left->type->type != ValueType::Uint)
throw std::invalid_argument(
R"(bit operation allows only for uint expressions.)");
break;
case BinaryOp::LogicAnd:
case BinaryOp::LogicOr:
Expand All @@ -299,10 +296,20 @@ class BinaryExpr : public CExpr {
virtual bool eval_bool(const std::string &memory) {
switch (op) {
case BinaryOp::BitAnd:
if (left->type->type == ValueType::Uint)
return eval_uint(memory) != 0;
else
return left->eval_bool(memory) && right->eval_bool(memory);
case BinaryOp::BitOr:
if (left->type->type == ValueType::Uint)
return eval_uint(memory) != 0;
else
return left->eval_bool(memory) || right->eval_bool(memory);
case BinaryOp::BitXor:
throw std::invalid_argument(
R"(eval_bool is called for Bit* binary expression.)");
if (left->type->type == ValueType::Uint)
return eval_uint(memory) != 0;
else
return left->eval_bool(memory) ^ right->eval_bool(memory);
case BinaryOp::LogicAnd:
return left->eval_bool(memory) && right->eval_bool(memory);
case BinaryOp::LogicOr:
Expand Down
87 changes: 87 additions & 0 deletions test/terra/backends/aer_simulator/test_control_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -1100,3 +1100,90 @@ def test_while_expr_loop_break(self, method):
counts = result.get_counts()
self.assertEqual(len(counts), 1)
self.assertIn("1 1", counts)

@data("statevector", "density_matrix", "matrix_product_state", "stabilizer")
def test_bit_and_operation(self, method):
"""test bit-and operation"""
qr = QuantumRegister(7)
cr = ClassicalRegister(7)
qc = QuantumCircuit(qr, cr)
qc.x(0)
qc.x(2)
qc.measure(range(4), range(4)) # 0101
qc.barrier()
b01 = expr.bit_and(cr[0], cr[1]) # 1 & 0 -> 0
with qc.if_test(b01):
qc.x(4) # q4 -> 0

b02 = expr.bit_and(cr[0], cr[2]) # 1 & 1 -> 1
with qc.if_test(b02):
qc.x(5) # q5 -> 0

b13 = expr.bit_and(cr[1], cr[3]) # 0 & 0 -> 0
with qc.if_test(b13):
qc.x(6) # q6 -> 0

qc.measure(range(7), range(7)) # 0100101

backend = self.backend(method=method)
counts = backend.run(qc).result().get_counts()
self.assertEqual(len(counts), 1)
self.assertIn("0100101", counts)

@data("statevector", "density_matrix", "matrix_product_state", "stabilizer")
def test_bit_or_operation(self, method):
"""test bit-or operation"""
qr = QuantumRegister(7)
cr = ClassicalRegister(7)
qc = QuantumCircuit(qr, cr)
qc.x(0)
qc.x(2)
qc.measure(range(4), range(4)) # 0101
qc.barrier()
b01 = expr.bit_or(cr[0], cr[1]) # 1 & 0 -> 1
with qc.if_test(b01):
qc.x(4) # q4 -> 1

b02 = expr.bit_or(cr[0], cr[2]) # 1 & 1 -> 1
with qc.if_test(b02):
qc.x(5) # q5 -> 0

b13 = expr.bit_or(cr[1], cr[3]) # 0 & 0 -> 0
with qc.if_test(b13):
qc.x(6) # q6 -> 0

qc.measure(range(7), range(7)) # 0110101

backend = self.backend(method=method)
counts = backend.run(qc).result().get_counts()
self.assertEqual(len(counts), 1)
self.assertIn("0110101", counts)

@data("statevector", "density_matrix", "matrix_product_state", "stabilizer")
def test_bit_xor_operation(self, method):
"""test bit-or operation"""
qr = QuantumRegister(7)
cr = ClassicalRegister(7)
qc = QuantumCircuit(qr, cr)
qc.x(0)
qc.x(2)
qc.measure(range(4), range(4)) # 0101
qc.barrier()
b01 = expr.bit_xor(cr[0], cr[1]) # 1 & 0 -> 1
with qc.if_test(b01):
qc.x(4) # q4 -> 1

b02 = expr.bit_xor(cr[0], cr[2]) # 1 & 1 -> 0
with qc.if_test(b02):
qc.x(5) # q5 -> 0

b13 = expr.bit_xor(cr[1], cr[3]) # 0 & 0 -> 0
with qc.if_test(b13):
qc.x(6) # q6 -> 0

qc.measure(range(7), range(7)) # 0010101

backend = self.backend(method=method)
counts = backend.run(qc).result().get_counts()
self.assertEqual(len(counts), 1)
self.assertIn("0010101", counts)
11 changes: 9 additions & 2 deletions test/terra/expression/test_classical_expressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,12 +353,19 @@ def test_binary_expression(self):
True,
)

# (False & True): error
# (False & True): Uint -> error
try:
AerBinaryExpr(AerBinaryOp.BitAnd, AerBoolValue(False), AerBoolValue(True))
AerBinaryExpr(AerBinaryOp.BitAnd, AerBoolValue(False), AerBoolValue(True)).eval_uint("")
self.fail("do not reach here")
except Exception:
pass
# (False & True) = False
self.assertEqual(
AerBinaryExpr(AerBinaryOp.BitAnd, AerBoolValue(False), AerBoolValue(True)).eval_bool(
""
),
False,
)
# (0b001 & 0b001) = 0b001
self.assertEqual(
AerBinaryExpr(
Expand Down

0 comments on commit 8641d1d

Please sign in to comment.