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

Support bit_not for Bool type #2076

Merged
merged 5 commits into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions releasenotes/notes/add_bit_not_for_bool-2aa62305e62a4f34.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
features:
- |
``bit_not`` is defined for ``Uint`` values. However, in other language,
depending hardware, ``Bool`` values can be applied as ``logical_not``
(``False`` is ``0`` and ``True`` is ``1``). This PR supports such implicit
operations for only "``bit_not``".
36 changes: 17 additions & 19 deletions src/framework/operations.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,30 +222,28 @@ class BoolValue : public ValueExpr {
class UnaryExpr : public CExpr {
public:
UnaryExpr(const UnaryOp op_, const std::shared_ptr<CExpr> operand_)
: CExpr(CExprType::Unary, operand_->type), op(op_), operand(operand_) {
if (op == UnaryOp::LogicNot && operand_->type->type != ValueType::Bool)
throw std::invalid_argument(
R"(LogicNot unary expression must has Bool expression as its operand.)");

if (op == UnaryOp::BitNot && operand_->type->type != ValueType::Uint)
throw std::invalid_argument(
R"(BitNot unary expression must has Uint expression as its operand.)");
}
: CExpr(CExprType::Unary, operand_->type), op(op_), operand(operand_) {}

virtual bool eval_bool(const std::string &memory) {
if (op == UnaryOp::BitNot)
throw std::invalid_argument(
R"(eval_bool is called for BitNot unary expression.)");
else // LogicNot
return !operand->eval_bool(memory);
if (op == UnaryOp::LogicNot || op == UnaryOp::BitNot) {
if (operand->type->type == ValueType::Bool) {
return !operand->eval_bool(memory);
} else if (operand->type->type == ValueType::Uint) {
return truncate(~operand->eval_uint(memory), type->width) != 0Ul;
}
}
throw std::invalid_argument(R"(should not reach here.)");
}

virtual uint_t eval_uint(const std::string &memory) {
if (op == UnaryOp::BitNot)
return truncate(~operand->eval_uint(memory), type->width);
else // LogicNot
throw std::invalid_argument(
R"(eval_uint is called for LogicNot unary expression.)");
if (op == UnaryOp::LogicNot || op == UnaryOp::BitNot) {
if (operand->type->type == ValueType::Bool) {
return operand->eval_bool(memory) ? 1UL : 0UL;
} else if (operand->type->type == ValueType::Uint) {
return truncate(~operand->eval_uint(memory), type->width);
}
}
throw std::invalid_argument(R"(should not reach here.)");
}

public:
Expand Down
104 changes: 98 additions & 6 deletions test/terra/backends/aer_simulator/test_control_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -1162,25 +1162,117 @@ def test_bit_or_operation(self, method):
@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)
qr = QuantumRegister(8)
cr = ClassicalRegister(8)
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
b01 = expr.bit_xor(cr[0], cr[1]) # (bool) 1 & (bool) 0 -> (bool) 1
with qc.if_test(b01):
qc.x(4) # q4 -> 1

b02 = expr.bit_xor(cr[0], cr[2]) # 1 & 1 -> 0
b02 = expr.bit_xor(cr[0], cr[2]) # (bool) 1 & (bool) 1 -> (bool) 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):
b03 = expr.bit_xor(cr[1], cr[3]) # (bool) 0 & (bool) 0 -> (bool) 0
with qc.if_test(b03):
qc.x(6) # q6 -> 0

b04 = expr.bit_xor(
expr.Value(True, types.Bool()), expr.Value(False, types.Bool())
) # (bool) 1 & (bool) 0 -> (bool) 1
with qc.if_test(b04):
qc.x(7) # q7 -> 1

qc.measure(range(8), range(8)) # 10010101

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

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()
try:
b04 = expr.bit_xor(
expr.Var(cr, types.Uint(cr.size)), expr.Var(cr, types.Uint(cr.size))
) # (bool) 1 ^ (uint) 0101 -> error
self.fail("do not reach here")
except Exception:
pass

qr = QuantumRegister(7)
cr = ClassicalRegister(7)
cr0 = ClassicalRegister(7)
qc = QuantumCircuit(qr, cr, cr0)
qc.x(0)
qc.x(1)
qc.x(2)
qc.x(3)
qc.measure(range(4), range(4)) # 1111
qc.barrier()
b05 = expr.bit_xor(
expr.Var(cr, types.Uint(cr.size)), expr.Var(cr, types.Uint(cr.size))
) # (uint) 1111 ^ (uint) 1111 -> (uint) 0000
with qc.if_test(expr.equal(b05, 0b0000000)):
qc.x(4) # q4 -> 1
b06 = expr.bit_xor(
expr.Var(cr0, types.Uint(cr0.size)), expr.Var(cr, types.Uint(cr.size))
) # (uint) 0000 ^ (uint) 0101 -> (uint) 1111
with qc.if_test(expr.equal(b06, 0b0001111)):
qc.x(5) # q5 -> 1

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

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

@data("statevector", "density_matrix", "matrix_product_state", "stabilizer")
def test_bit_not_operation(self, method):
"""test bit-not 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_not(cr[0]) # !1 -> 0
with qc.if_test(b01):
qc.x(4) # q4 -> 0

b02 = expr.bit_not(cr[1]) # !0 -> 1
with qc.if_test(b02):
qc.x(5) # q5 -> 1

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)

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_not(expr.Var(cr, types.Uint(cr.size))) # 0b0000101 -> 0b1111010
with qc.if_test(expr.equal(b01, 0b1111010)):
qc.x(4) # q4 -> 1

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

backend = self.backend(method=method)
Expand Down
Loading