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

BarrierOp and Circuit._add_conditional_barrier #988

Merged
merged 43 commits into from
Sep 6, 2023
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
e1c85b7
Add new `BarrierOp`
sjdilkes Aug 23, 2023
58d7f55
Add Circuit::add_conditional_gate
sjdilkes Aug 23, 2023
6ee6d09
Add tests to confirm DAG is wired suitably for conditional barrier gates
sjdilkes Aug 24, 2023
cbd62a1
Add tests and case handling for conditional barrier over different ci…
sjdilkes Aug 25, 2023
6a682c3
add `_add_conditonal_barrier` method to Circuit class
sjdilkes Aug 29, 2023
a7b7d4c
bump
sjdilkes Aug 29, 2023
a5e4a09
black format
sjdilkes Aug 29, 2023
847a425
Update test_Circ.cpp
sjdilkes Aug 30, 2023
e5a9e8a
Update add_op.cpp
sjdilkes Aug 30, 2023
94e28fb
Merge branch 'develop' into conditional-barrier
sjdilkes Aug 30, 2023
bc570fc
bump
sjdilkes Aug 30, 2023
431ddbf
Update add_op.cpp
sjdilkes Aug 30, 2023
394ee56
Merge branch 'develop' into conditional-barrier
sjdilkes Aug 30, 2023
175d69b
Expose BarrierOp to python
sjdilkes Aug 31, 2023
65994f2
Make `barr` signature accurately reflect internal UnitID, add test
sjdilkes Aug 31, 2023
fe39c11
reformat tests
sjdilkes Aug 31, 2023
016ae57
Merge branch 'develop' into conditional-barrier
sjdilkes Aug 31, 2023
5f86354
Update main.cpp
sjdilkes Aug 31, 2023
4f02bd5
Merge branch 'develop' into conditional-barrier
sjdilkes Aug 31, 2023
0ae0af9
Update qasm.py
sjdilkes Aug 31, 2023
9c1119f
Update circuit.pyi
sjdilkes Aug 31, 2023
7e2349a
Update test_Circ.cpp
sjdilkes Aug 31, 2023
d792bf6
requested changes from review
sjdilkes Sep 4, 2023
89551b4
Merge branch 'develop' into conditional-barrier
sjdilkes Sep 4, 2023
66f826f
fix types
sjdilkes Sep 4, 2023
3c03668
Update basic_circ_manip.cpp
sjdilkes Sep 4, 2023
3a06eaa
Update basic_circ_manip.cpp
sjdilkes Sep 4, 2023
04c0c9f
Update qasm_test.py
sjdilkes Sep 4, 2023
c1f1828
Update qasm_test.py
sjdilkes Sep 4, 2023
1b94d6f
Update circuit.pyi
sjdilkes Sep 4, 2023
ed13e99
Add symbolic substituion test for barrier op
sjdilkes Sep 5, 2023
a6a491b
Update serialization/deserialization for MetaOp/BarrierOp
sjdilkes Sep 5, 2023
2cbebb8
Merge branch 'develop' into conditional-barrier
sjdilkes Sep 5, 2023
312b7f1
add MetaOp::is_equal
sjdilkes Sep 5, 2023
c3bfbdd
Add back data type
sjdilkes Sep 5, 2023
011b7e7
Update add_op.cpp
sjdilkes Sep 5, 2023
7fcfefa
bump
sjdilkes Sep 5, 2023
ddd64a3
Merge branch 'develop' into conditional-barrier
sjdilkes Sep 5, 2023
1456359
bump
sjdilkes Sep 5, 2023
bd908d2
Merge branch 'develop' into conditional-barrier
sjdilkes Sep 6, 2023
6deb21d
bump
sjdilkes Sep 6, 2023
ef91614
update with requested changes
sjdilkes Sep 6, 2023
d26666c
Merge branch 'develop' into conditional-barrier
sjdilkes Sep 6, 2023
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
21 changes: 9 additions & 12 deletions pytket/binders/circuit/Circuit/add_op.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ void init_circuit_add_op(py::class_<Circuit, std::shared_ptr<Circuit>> &c) {
"\n:return: the new :py:class:`Circuit`",
py::arg("qubits"), py::arg("bits") = no_bits, py::arg("data") = "")
.def(
"_add_conditional_barrier",
"add_conditional_barrier",
[](Circuit *circ, const std::vector<unsigned> &barrier_qubits,
const std::vector<unsigned> &barrier_bits,
const std::vector<unsigned> &condition_bits, unsigned value,
Expand All @@ -187,12 +187,11 @@ void init_circuit_add_op(py::class_<Circuit, std::shared_ptr<Circuit>> &c) {
"barrier bits, conditioned on the given condition bits."
"\n\n:param barrier_qubits: Qubit in Barrier operation."
"\n:param barrier_bits: Bit in Barrier operation."
"\n:param condition_bits: Bit covering classical control "
"condition "
"\n:param condition_bits: Bit covering classical control condition "
"of barrier operation."
"\n:param value: Value that classical condition must have to "
"hold."
"\n: param data: Additional data stored in Barrier operation."
"hold (little-endian)."
"\n:param data: Additional data stored in Barrier operation."
"\n:return: the new :py:class:`Circuit`",
py::arg("barrier_qubits"), py::arg("barrier_bits"),
py::arg("condition_bits"), py::arg("value"), py::arg("data") = "")
Expand Down Expand Up @@ -438,11 +437,10 @@ void init_circuit_add_op(py::class_<Circuit, std::shared_ptr<Circuit>> &c) {
"\n\n:param data: additional data stored in the barrier"
"\n:return: the new :py:class:`Circuit`",
py::arg("units"), py::arg("data") = "")

.def(
"_add_conditional_barrier",
"add_conditional_barrier",
[](Circuit *circ, const unit_vector_t &barrier_args,
const unit_vector_t &condition_bits, unsigned value,
const bit_vector_t &condition_bits, unsigned value,
const std::string &_data) {
circ->add_conditional_barrier(
barrier_args, condition_bits, value, _data);
Expand All @@ -452,11 +450,10 @@ void init_circuit_add_op(py::class_<Circuit, std::shared_ptr<Circuit>> &c) {
"barrier bits, conditioned on the given condition bits."
"\n\n:param barrier_args: Qubit and Bit in Barrier operation."
"\n:param condition_bits: Bit covering classical control "
"condition "
"of barrier operation."
" condition of barrier operation."
"\n:param value: Value that classical condition must have to "
"hold."
"\n: param data: Additional data stored in Barrier operation."
" hold (little-endian)."
cqc-alec marked this conversation as resolved.
Show resolved Hide resolved
"\n:param data: Additional data stored in Barrier operation."
"\n:return: the new :py:class:`Circuit`",
py::arg("barrier_args"), py::arg("condition_bits"), py::arg("value"),
py::arg("data") = "")
Expand Down
2 changes: 1 addition & 1 deletion pytket/conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def package(self):
cmake.install()

def requirements(self):
self.requires("tket/1.2.38@tket/stable")
self.requires("tket/1.2.40@tket/stable")
self.requires("tklog/0.3.3@tket/stable")
self.requires("tkrng/0.3.3@tket/stable")
self.requires("tkassert/0.3.3@tket/stable")
Expand Down
8 changes: 4 additions & 4 deletions pytket/pytket/_tket/circuit.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -268,10 +268,6 @@ class Circuit:
def ZZPhase(self, angle: Union[sympy.Expr,float], qubit0: int, qubit1: int, **kwargs: Any) -> Circuit: ...
@overload
def ZZPhase(self, angle: Union[sympy.Expr,float], qubit0: pytket._tket.unit_id.Qubit, qubit1: pytket._tket.unit_id.Qubit, **kwargs: Any) -> Circuit: ...
@overload
def _add_conditional_barrier(self, barrier_qubits: List[int], barrier_bits: List[int], condition_bits: List[int], value: int, data: str = ...) -> Circuit: ...
@overload
def _add_conditional_barrier(self, barrier_args: List[pytket._tket.unit_id.UnitID], condition_bits: List[pytket._tket.unit_id.UnitID], value: int, data: str = ...) -> Circuit: ...
def _add_w_register(self, size: int) -> None: ...
@overload
def _add_wasm(self, funcname: str, wasm_uid: str, width_i_parameter: List[int], width_o_parameter: List[int], args: List[int], wasm_wire_args: List[int], **kwargs: Any) -> Circuit: ...
Expand Down Expand Up @@ -357,6 +353,10 @@ class Circuit:
def add_classicalexpbox_bit(self, expression: object, target: List[pytket._tket.unit_id.Bit], **kwargs: Any) -> Circuit: ...
def add_classicalexpbox_register(self, expression: object, target: List[pytket._tket.unit_id.Bit], **kwargs: Any) -> Circuit: ...
@overload
def add_conditional_barrier(self, barrier_qubits: List[int], barrier_bits: List[int], condition_bits: List[int], value: int, data: str = ...) -> Circuit: ...
@overload
def add_conditional_barrier(self, barrier_args: List[pytket._tket.unit_id.UnitID], condition_bits: List[pytket._tket.unit_id.Bit], value: int, data: str = ...) -> Circuit: ...
@overload
def add_conjugation_box(self, box: ConjugationBox, args: List[pytket._tket.unit_id.UnitID], **kwargs: Any) -> Circuit: ...
@overload
def add_conjugation_box(self, box: ConjugationBox, args: List[int], **kwargs: Any) -> Circuit: ...
Expand Down
2 changes: 1 addition & 1 deletion pytket/pytket/qasm/qasm.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ def barr(self, tree: List[Arg]) -> Iterable[CommandDict]:
signature.append("Q")
else:
raise QASMParseError(
cqc-alec marked this conversation as resolved.
Show resolved Hide resolved
"UnitID", arg, "in Barrier arguments is not declared."
"UnitID " + arg + " in Barrier arguments is not declared."
cqc-alec marked this conversation as resolved.
Show resolved Hide resolved
)
yield {
"args": args,
Expand Down
7 changes: 4 additions & 3 deletions pytket/tests/qasm_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ def test_conditional_gates() -> None:
circ.Measure(0, 0)
circ.Measure(1, 1)
circ.Z(0, condition_bits=[0, 1], condition_value=2)
circ._add_conditional_barrier([0, 1], [], [0, 1], 1, data="cond_barrier")
circ.add_conditional_barrier([0, 1], [], [0, 1], 1)
circ.Measure(0, 0, condition_bits=[0, 1], condition_value=1)
qasm_out = str(curr_file_path / "qasm_test_files/testout5.qasm")
circuit_to_qasm(circ, qasm_out)
Expand All @@ -228,14 +228,15 @@ def test_named_conditional_barrier() -> None:
circ = Circuit(2, 2)
circ.add_bit(Bit("test", 3))
circ.Z(0, condition_bits=[0, 1], condition_value=2)
circ._add_conditional_barrier(
circ.add_conditional_barrier(
[Qubit("q", 0), Bit("test", 3)],
[Bit("c", 0), Bit("c", 1)],
0,
data="cond_barrier",
)
qs_str: str = circuit_to_qasm_str(circ)
assert qs_str == circuit_to_qasm_str(circuit_from_qasm_str(qs_str))
c_from_qs: Circuit = circuit_from_qasm_str(qs_str)
assert qs_str == circuit_to_qasm_str(c_from_qs)


def test_hqs_conditional() -> None:
Expand Down
2 changes: 1 addition & 1 deletion tket/conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

class TketConan(ConanFile):
name = "tket"
version = "1.2.38"
version = "1.2.40"
package_type = "library"
license = "Apache 2"
homepage = "https://github.com/CQCL/tket"
Expand Down
4 changes: 2 additions & 2 deletions tket/include/tket/Circuit/Circuit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -906,7 +906,7 @@ class Circuit {
}
if (is_barrier_type(type)) {
throw CircuitInvalidity(
"Please use '_add_conditional_barrier' to add a conditional barrier "
"Please use 'add_conditional_barrier' to add a conditional barrier "
"gate.");
}
Op_ptr cond = std::make_shared<Conditional>(
Expand All @@ -931,7 +931,7 @@ class Circuit {
std::optional<std::string> opgroup = std::nullopt);

Vertex add_conditional_barrier(
const unit_vector_t &barrier_args, const unit_vector_t &condition_bits,
const unit_vector_t &barrier_args, const bit_vector_t &condition_bits,
unsigned value, const std::string &_data,
std::optional<std::string> opgroup = std::nullopt);

Expand Down
3 changes: 1 addition & 2 deletions tket/include/tket/Ops/BarrierOp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,7 @@ class BarrierOp : public Op {
static Op_ptr deserialize(const nlohmann::json &j);

private:
op_signature_t
signature_; /**< Types of inputs, when not deducible from op type */
op_signature_t signature_; /**< Types of inputs */
/**
* additional data given by the user, can be passed on to backend
*/
Expand Down
11 changes: 0 additions & 11 deletions tket/include/tket/Ops/MetaOp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ class MetaOp : public Op {

SymSet free_symbols() const override;

unsigned n_qubits() const override;
cqc-alec marked this conversation as resolved.
Show resolved Hide resolved

op_signature_t get_signature() const override;

std::string get_data() const { return data_; }
Expand All @@ -40,15 +38,6 @@ class MetaOp : public Op {

~MetaOp() override;

/**
* Equality check between two MetaOp instances
*/
bool is_equal(const Op &other) const override;

nlohmann::json serialize() const override;

static Op_ptr deserialize(const nlohmann::json &j);

private:
op_signature_t
signature_; /**< Types of inputs, when not deducible from op type */
Expand Down
4 changes: 1 addition & 3 deletions tket/src/Circuit/OpJson.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@ namespace tket {

void from_json(const nlohmann::json& j, Op_ptr& op) {
OpType optype = j.at("type").get<OpType>();
if (is_metaop_type(optype)) {
op = MetaOp::deserialize(j);
} else if (is_barrier_type(optype)) {
if (is_barrier_type(optype)) {
op = BarrierOp::deserialize(j);
} else if (is_box_type(optype)) {
op = Box::deserialize(j);
Expand Down
6 changes: 4 additions & 2 deletions tket/src/Circuit/basic_circ_manip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,18 +161,20 @@ Vertex Circuit::add_conditional_barrier(
}

Vertex Circuit::add_conditional_barrier(
const unit_vector_t& barrier_args, const unit_vector_t& condition_bits,
const unit_vector_t& barrier_args, const bit_vector_t& condition_bits,
unsigned value, const std::string& _data,
std::optional<std::string> opgroup) {
op_signature_t sig;
for (const UnitID& arg : barrier_args) {
if (arg.type() == UnitType::Qubit) {
sig.push_back(EdgeType::Quantum);
} else {
TKET_ASSERT(arg.type() == UnitType::Bit);
sig.push_back(EdgeType::Classical);
cqc-alec marked this conversation as resolved.
Show resolved Hide resolved
}
}
unit_vector_t args = condition_bits;
unit_vector_t args;
args.insert(args.end(), condition_bits.begin(), condition_bits.end());
args.insert(args.end(), barrier_args.begin(), barrier_args.end());
return add_op(
std::make_shared<Conditional>(
Expand Down
19 changes: 5 additions & 14 deletions tket/src/Ops/BarrierOp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,10 @@ Op_ptr BarrierOp::symbol_substitution(const SymEngine::map_basic_basic&) const {
SymSet BarrierOp::free_symbols() const { return {}; }

unsigned BarrierOp::n_qubits() const {
OptUInt n = desc_.n_qubits();
if (n == any) {
return std::count(signature_.begin(), signature_.end(), EdgeType::Quantum);
} else {
return n.value();
}
return std::count(signature_.begin(), signature_.end(), EdgeType::Quantum);
}

op_signature_t BarrierOp::get_signature() const {
std::optional<op_signature_t> sig = desc_.signature();
if (sig)
return *sig;
else
return signature_;
}
op_signature_t BarrierOp::get_signature() const { return signature_; }

nlohmann::json BarrierOp::serialize() const {
nlohmann::json j;
Expand All @@ -73,7 +62,9 @@ BarrierOp::~BarrierOp() {}

bool BarrierOp::is_equal(const Op& op_other) const {
const BarrierOp& other = dynamic_cast<const BarrierOp&>(op_other);
return (get_signature() == other.get_signature());
return (
get_signature() == other.get_signature() &&
get_data() == other.get_data());
}

} // namespace tket
34 changes: 0 additions & 34 deletions tket/src/Ops/MetaOp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,6 @@ Op_ptr MetaOp::symbol_substitution(const SymEngine::map_basic_basic&) const {

SymSet MetaOp::free_symbols() const { return {}; }

unsigned MetaOp::n_qubits() const {
OptUInt n = desc_.n_qubits();
if (n == any) {
return std::count(signature_.begin(), signature_.end(), EdgeType::Quantum);
} else {
return n.value();
}
}

op_signature_t MetaOp::get_signature() const {
std::optional<op_signature_t> sig = desc_.signature();
if (sig)
Expand All @@ -51,33 +42,8 @@ op_signature_t MetaOp::get_signature() const {
return signature_;
}

nlohmann::json MetaOp::serialize() const {
nlohmann::json j;
j["type"] = get_type();
j["signature"] = get_signature();
j["data"] = get_data();
return j;
}

Op_ptr MetaOp::deserialize(const nlohmann::json& j) {
OpType optype = j.at("type").get<OpType>();
op_signature_t sig = j.at("signature").get<op_signature_t>();
std::string data;
try {
data = j.at("data").get<std::string>();
} catch (const nlohmann::json::out_of_range& e) {
data = "";
}
return std::make_shared<MetaOp>(optype, sig, data);
}

bool MetaOp::is_clifford() const { return true; }

MetaOp::~MetaOp() {}

bool MetaOp::is_equal(const Op& op_other) const {
const MetaOp& other = dynamic_cast<const MetaOp&>(op_other);
return (get_signature() == other.get_signature());
}

} // namespace tket
20 changes: 20 additions & 0 deletions tket/test/src/Circuit/test_Circ.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1240,6 +1240,26 @@ SCENARIO("Functions with symbolic ops") {
REQUIRE(op3->get_type() == OpType::PhaseGadget);
REQUIRE(test_equiv_val(op3->get_params()[0], 0.6));
}
GIVEN("A simple circuit with symbolics to instantiate, and a Barrier gate.") {
Circuit circ(2);
Sym a = SymEngine::symbol("alpha");
Expr alpha(a);
circ.add_op<unsigned>(OpType::Rx, alpha, {0});
circ.add_barrier({0, 1});
REQUIRE(circ.is_symbolic());
SymSet symbols = circ.free_symbols();
REQUIRE(symbols.size() == 1);
REQUIRE(symbols.find(a) != symbols.end());
symbol_map_t symbol_map;
symbol_map[a] = Expr(0.2);
circ.symbol_substitution(symbol_map);
VertexVec vertices = circ.vertices_in_order();
Op_ptr op2 = circ.get_Op_ptr_from_Vertex(vertices[2]);
Op_ptr op3 = circ.get_Op_ptr_from_Vertex(vertices[3]);
REQUIRE(op2->get_type() == OpType::Rx);
REQUIRE(test_equiv_val(op2->get_params()[0], 0.2));
REQUIRE(op3->get_type() == OpType::Barrier);
}
}

SCENARIO("Test depth_by_type method") {
Expand Down
1 change: 1 addition & 0 deletions tket/test/src/test_json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ SCENARIO("Test Circuit serialization") {
c.add_conditional_gate<unsigned>(OpType::CX, {}, {0, 1}, {0, 1}, 1);
c.add_conditional_gate<unsigned>(OpType::Measure, {}, {0, 2}, {0, 1}, 1);
c.add_conditional_barrier({0, 1}, {1, 2}, {0}, 0, "");
c.add_conditional_barrier({0}, {2}, {0, 1}, 1, "test");

nlohmann::json j_box = c;
const Circuit new_c = j_box.get<Circuit>();
Expand Down
Loading