From e1c85b734b268755b150fd9e2ed526e42a02d8c5 Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Wed, 23 Aug 2023 14:45:27 +0100 Subject: [PATCH 01/34] Add new `BarrierOp` Remove `OpType::Barrier` from `MetaOp` --- pytket/binders/circuit/Circuit/add_op.cpp | 19 +++++ pytket/binders/circuit/main.cpp | 2 +- pytket/binders/include/add_gate.hpp | 7 +- pytket/pytket/circuit/decompose_classical.py | 2 +- tket/CMakeLists.txt | 2 + tket/include/tket/Circuit/Circuit.hpp | 21 ++++- tket/include/tket/Gate/OpPtrFunctions.hpp | 8 +- tket/include/tket/OpType/OpDesc.hpp | 5 +- tket/include/tket/OpType/OpTypeFunctions.hpp | 5 +- tket/include/tket/Ops/BarrierOp.hpp | 64 +++++++++++++++ .../Characterisation/FrameRandomisation.cpp | 4 +- tket/src/Circuit/OpJson.cpp | 3 + tket/src/Circuit/basic_circ_manip.cpp | 23 +++++- tket/src/Converters/PhasePoly.cpp | 1 - tket/src/Gate/OpPtrFunctions.cpp | 3 + tket/src/OpType/OpDesc.cpp | 3 + tket/src/OpType/OpTypeFunctions.cpp | 7 +- tket/src/Ops/BarrierOp.cpp | 81 +++++++++++++++++++ tket/test/src/test_Synthesis.cpp | 6 +- tket/test/src/test_json.cpp | 10 +-- 20 files changed, 247 insertions(+), 29 deletions(-) create mode 100644 tket/include/tket/Ops/BarrierOp.hpp create mode 100644 tket/src/Ops/BarrierOp.cpp diff --git a/pytket/binders/circuit/Circuit/add_op.cpp b/pytket/binders/circuit/Circuit/add_op.cpp index 0ce0420af8..da05b3dd26 100644 --- a/pytket/binders/circuit/Circuit/add_op.cpp +++ b/pytket/binders/circuit/Circuit/add_op.cpp @@ -176,6 +176,25 @@ void init_circuit_add_op(py::class_> &c) { "\n\n:param data: additional data stored in the barrier" "\n:return: the new :py:class:`Circuit`", py::arg("qubits"), py::arg("bits") = no_bits, py::arg("data") = "") + .def( + "_add_conditional_barrier", + []( + (Circuit *circ, const std::vector ¶ms, + const std::vector &qubits, + std::vector &barrier_bits const std::vector + &condition_bits, + unsigned value) { + std::vector barrier_args; + for (const unsig) + circ->add_conditional_barrier(params, args, bits, value); + return circ; + }, + "Append a Conditional Barrier on the given units, conditioned on " + "the givne Bit." + "\n\n:param data: additional data stored in the barrier" + "\n:return: the new :py:class:`Circuit`", + py::arg("qubits"), py::arg("bits") = no_bits, + py::arg("data") = "")) .def( "add_circbox", [](Circuit *circ, const CircBox &box, diff --git a/pytket/binders/circuit/main.cpp b/pytket/binders/circuit/main.cpp index 5796fb0a8b..a77f894767 100644 --- a/pytket/binders/circuit/main.cpp +++ b/pytket/binders/circuit/main.cpp @@ -602,7 +602,7 @@ PYBIND11_MODULE(circuit, m) { ":return: set of symbolic parameters for the command"); py::class_, Op>( - m, "MetaOp", "Meta operation, for example used as barrier") + m, "MetaOp", "Meta operation, such as input or output vertices.") .def( py::init(), "Construct MetaOp with optype, signature and additional data string" diff --git a/pytket/binders/include/add_gate.hpp b/pytket/binders/include/add_gate.hpp index e8ef12b85c..1131d4cdc3 100644 --- a/pytket/binders/include/add_gate.hpp +++ b/pytket/binders/include/add_gate.hpp @@ -27,9 +27,12 @@ static Circuit *add_gate_method( Circuit *circ, const Op_ptr &op, const std::vector &args, const py::kwargs &kwargs) { if (op->get_desc().is_meta()) { + throw CircuitInvalidity("Cannot add metaop to a circuit."); + } + if (op->get_desc().is_barrier()) { throw CircuitInvalidity( - "Cannot add metaop. Please use `add_barrier` to add a " - "barrier."); + "Please use `add_barrier` to add a " + "barrier to a circuit."); } static const std::set allowed_kwargs = { "opgroup", "condition", "condition_bits", "condition_value"}; diff --git a/pytket/pytket/circuit/decompose_classical.py b/pytket/pytket/circuit/decompose_classical.py index fbd5fba908..c38635254b 100644 --- a/pytket/pytket/circuit/decompose_classical.py +++ b/pytket/pytket/circuit/decompose_classical.py @@ -337,7 +337,7 @@ def _decompose_expressions(circ: Circuit) -> Tuple[Circuit, bool]: modified = True continue if optype == OpType.Barrier: - # add_gate doesn't work for metaops like barrier + # add_gate doesn't work for metaops newcirc.add_barrier(args) else: newcirc.add_gate(op, args, **kwargs) diff --git a/tket/CMakeLists.txt b/tket/CMakeLists.txt index 1649df5ccb..d045a635fc 100644 --- a/tket/CMakeLists.txt +++ b/tket/CMakeLists.txt @@ -111,6 +111,7 @@ target_sources(tket src/Clifford/ChoiMixTableau.cpp src/Clifford/SymplecticTableau.cpp src/Clifford/UnitaryTableau.cpp + src/Ops/BarrierOp.cpp src/Ops/FlowOp.cpp src/Ops/MetaOp.cpp src/Ops/Op.cpp @@ -277,6 +278,7 @@ target_sources(tket include/tket/Clifford/SymplecticTableau.hpp include/tket/Clifford/UnitaryTableau.hpp include/tket/Ops/ClassicalOps.hpp + include/tket/Ops/BarrierOp.hpp include/tket/Ops/FlowOp.hpp include/tket/Ops/MetaOp.hpp include/tket/Ops/Op.hpp diff --git a/tket/include/tket/Circuit/Circuit.hpp b/tket/include/tket/Circuit/Circuit.hpp index 95fcf6822d..089d433da0 100644 --- a/tket/include/tket/Circuit/Circuit.hpp +++ b/tket/include/tket/Circuit/Circuit.hpp @@ -836,9 +836,9 @@ class Circuit { Vertex add_op( OpType type, const std::vector ¶ms, const std::vector &args, std::optional opgroup = std::nullopt) { - if (is_metaop_type(type)) { + if (is_metaop_type(type) || is_barrier_type(type)) { throw CircuitInvalidity( - "Cannot add metaop. Please use `add_barrier` to add a " + "Cannot add metaop or barrier. Please use `add_barrier` to add a " "barrier."); } return add_op(get_op_ptr(type, params, args.size()), args, opgroup); @@ -904,6 +904,11 @@ class Circuit { if (is_metaop_type(type)) { throw CircuitInvalidity("Cannot add a conditional metaop."); } + if (is_barrier_type(type)) { + throw CircuitInvalidity( + "Please use '_add_conditional_barrier' to add a conditional barrier " + "gate."); + } Op_ptr cond = std::make_shared( get_op_ptr(type, params, (unsigned)args.size()), (unsigned)bits.size(), value); @@ -918,6 +923,18 @@ class Circuit { Vertex add_barrier(const unit_vector_t &args, const std::string &_data = ""); + Vertex add_conditional_barrier( + const std::vector ¶ms, + const std::vector &barrier_qubits, + const std::vector &barrier_bits, + const std::vector &condition_bits, unsigned value, + std::optional opgroup = std::nullopt); + + Vertex add_conditional_barrier( + const std::vector ¶ms, const unit_vector_t &barrier_uids, + const unit_vector_t &condition_bits, unsigned value, + std::optional opgroup = std::nullopt); + /** * Add a postfix to a classical register name if the register exists * Example: tket_c results in tket_c_2 if tket_c and tket_c_1 both exist diff --git a/tket/include/tket/Gate/OpPtrFunctions.hpp b/tket/include/tket/Gate/OpPtrFunctions.hpp index 68759ff96b..5d6cbc72eb 100644 --- a/tket/include/tket/Gate/OpPtrFunctions.hpp +++ b/tket/include/tket/Gate/OpPtrFunctions.hpp @@ -25,8 +25,8 @@ namespace tket { * * @param chosen_type operation type * @param param operation parameter - * @param n_qubits number of qubits (only necessary for gates and metaops - * with variable quantum arity) + * @param n_qubits number of qubits (only necessary for gates, barrier + * and metaops with variable quantum arity) */ Op_ptr get_op_ptr(OpType chosen_type, const Expr ¶m, unsigned n_qubits = 0); @@ -35,8 +35,8 @@ Op_ptr get_op_ptr(OpType chosen_type, const Expr ¶m, unsigned n_qubits = 0); * * @param chosen_type operation type * @param params operation parameters - * @param n_qubits number of qubits (only necessary for gates and metaops - * with variable quantum arity) + * @param n_qubits number of qubits (only necessary for gates, barrier + * and metaops with variable quantum arity) */ Op_ptr get_op_ptr( OpType chosen_type, const std::vector ¶ms = {}, diff --git a/tket/include/tket/OpType/OpDesc.hpp b/tket/include/tket/OpType/OpDesc.hpp index 420f0813e7..c56e738db9 100644 --- a/tket/include/tket/OpType/OpDesc.hpp +++ b/tket/include/tket/OpType/OpDesc.hpp @@ -61,9 +61,12 @@ class OpDesc { /** Number of classical bits written to */ OptUInt n_classical() const; - /** Whether the 'operation' is actually an input or output or barrier */ + /** Whether the 'operation' is actually an input or output */ bool is_meta() const; + /** Whether the operation is a Barrier */ + bool is_barrier() const; + /** Whether the operation is a box of some kind */ bool is_box() const; diff --git a/tket/include/tket/OpType/OpTypeFunctions.hpp b/tket/include/tket/OpType/OpTypeFunctions.hpp index 5f65258bb2..1556ba2dbc 100644 --- a/tket/include/tket/OpType/OpTypeFunctions.hpp +++ b/tket/include/tket/OpType/OpTypeFunctions.hpp @@ -48,9 +48,12 @@ const OpTypeSet &all_controlled_gate_types(); /** Set of all classical gates */ const OpTypeSet &all_classical_types(); -/** Test for initial, final and barrier "ops" */ +/** Test for initial and final "ops" */ bool is_metaop_type(OpType optype); +/** Test for Barrier "ops" */ +bool is_barrier_type(OpType optype); + /** Test for input or creation quantum "ops" */ bool is_initial_q_type(OpType optype); diff --git a/tket/include/tket/Ops/BarrierOp.hpp b/tket/include/tket/Ops/BarrierOp.hpp new file mode 100644 index 0000000000..0e64d670e1 --- /dev/null +++ b/tket/include/tket/Ops/BarrierOp.hpp @@ -0,0 +1,64 @@ +// Copyright 2019-2023 Cambridge Quantum Computing +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "Op.hpp" +#include "tket/Utils/Json.hpp" + +namespace tket { + +class BarrierOp : public Op { + public: + explicit BarrierOp( + op_signature_t signature = {}, + const std::string &_data = ""); + + Op_ptr symbol_substitution( + const SymEngine::map_basic_basic &sub_map) const override; + + SymSet free_symbols() const override; + + unsigned n_qubits() const override; + + op_signature_t get_signature() const override; + + std::string get_data() const { return data_; } + + bool is_clifford() const override; + + ~BarrierOp() override; + + /** + * Equality check between two BarrierOp instances + */ + bool is_equal(const Op &other) const override; + + nlohmann::json serialize() const override; + + static Op_ptr deserialize(const nlohmann::json &j); + + protected: + BarrierOp(); + + private: + op_signature_t + signature_; /**< Types of inputs, when not deducible from op type */ + /** + * additional data given by the user, can be passed on to backend + */ + const std::string data_; +}; + +} // namespace tket diff --git a/tket/src/Characterisation/FrameRandomisation.cpp b/tket/src/Characterisation/FrameRandomisation.cpp index 5cddd3903c..92bd53a401 100644 --- a/tket/src/Characterisation/FrameRandomisation.cpp +++ b/tket/src/Characterisation/FrameRandomisation.cpp @@ -16,7 +16,7 @@ #include -#include "tket/Ops/MetaOp.hpp" +#include "tket/Ops/BarrierOp.hpp" #include "tket/PauliGraph/ConjugatePauliFunctions.hpp" #include "tket/Utils/PauliStrings.hpp" @@ -97,7 +97,7 @@ void add_noop_frames(std::vector& cycles, Circuit& circ) { full_cycle.add_vertex_pair({input_noop_vert, output_noop_vert}); } std::vector sig(barrier_ins.size(), EdgeType::Quantum); - Op_ptr o_ptr = std::make_shared(OpType::Barrier, sig); + Op_ptr o_ptr = std::make_shared(sig); Vertex input_barrier_vert = circ.add_vertex(o_ptr); Vertex output_barrier_vert = circ.add_vertex(o_ptr); circ.rewire(input_barrier_vert, barrier_ins, sig); diff --git a/tket/src/Circuit/OpJson.cpp b/tket/src/Circuit/OpJson.cpp index 5611585538..6ff8f7a13f 100644 --- a/tket/src/Circuit/OpJson.cpp +++ b/tket/src/Circuit/OpJson.cpp @@ -17,6 +17,7 @@ #include "tket/Gate/Gate.hpp" #include "tket/OpType/OpType.hpp" #include "tket/OpType/OpTypeFunctions.hpp" +#include "tket/Ops/BarrierOp.hpp" #include "tket/Ops/ClassicalOps.hpp" #include "tket/Ops/MetaOp.hpp" #include "tket/Ops/OpPtr.hpp" @@ -28,6 +29,8 @@ void from_json(const nlohmann::json& j, Op_ptr& op) { OpType optype = j.at("type").get(); if (is_metaop_type(optype)) { op = MetaOp::deserialize(j); + } else if (if_barrier_type(optype)) { + op = BarrierOp::deserialize(j); } else if (is_box_type(optype)) { op = Box::deserialize(j); } else if (optype == OpType::Conditional) { diff --git a/tket/src/Circuit/basic_circ_manip.cpp b/tket/src/Circuit/basic_circ_manip.cpp index 03214dd5d3..42512b5668 100644 --- a/tket/src/Circuit/basic_circ_manip.cpp +++ b/tket/src/Circuit/basic_circ_manip.cpp @@ -24,6 +24,7 @@ #include "tket/Circuit/Boxes.hpp" #include "tket/Circuit/Circuit.hpp" +#include "tket/Ops/BarrierOp.hpp" #include "tket/Ops/MetaOp.hpp" namespace tket { @@ -125,12 +126,11 @@ Vertex Circuit::add_barrier( sig.insert(sig.end(), cl_sig.begin(), cl_sig.end()); std::vector args = qubits; args.insert(args.end(), bits.begin(), bits.end()); - return add_op(std::make_shared(OpType::Barrier, sig, _data), args); + return add_op(std::make_shared(sig, _data), args); } Vertex Circuit::add_barrier( const unit_vector_t& args, const std::string& _data) { - op_signature_t sig; for (const UnitID& arg : args) { if (arg.type() == UnitType::Qubit) { sig.push_back(EdgeType::Quantum); @@ -138,9 +138,26 @@ Vertex Circuit::add_barrier( sig.push_back(EdgeType::Classical); } } - return add_op(std::make_shared(OpType::Barrier, sig, _data), args); + return add_op(std::make_shared(sig, _data), args); } +Vertex Circuit::add_conditional_barrier( + const std::vector& barrier_qubits, + const std::vector& barrier_bits, + const std::vector& condition_bits, unsigned value, + const std::string& _data) { + op_signature_t sig(barrier_qubits.size(), EdgeType::Quantum); + sig.insert(sig.end(), barrier_bits.size(), EdgeType::Classical); + + return add_op(std::make_shared( + std::make_shared(sig, _data), (unsigned)condition_bits.size(), + value)) +} + +Vertex Circuit::add_conditional_barrier( + const unit_vector_t& barrier_uids, const unit_vector_t& condition_bits, + unsigned value, std::optional opgroup = std::nullopt); + std::string Circuit::get_next_c_reg_name(const std::string& reg_name) { if (!get_reg_info(reg_name)) { return reg_name; diff --git a/tket/src/Converters/PhasePoly.cpp b/tket/src/Converters/PhasePoly.cpp index 579ff634f0..20f6cf36b7 100644 --- a/tket/src/Converters/PhasePoly.cpp +++ b/tket/src/Converters/PhasePoly.cpp @@ -24,7 +24,6 @@ #include "tket/Circuit/Circuit.hpp" #include "tket/Converters/Gauss.hpp" #include "tket/OpType/OpType.hpp" -#include "tket/Ops/MetaOp.hpp" #include "tket/Ops/OpJsonFactory.hpp" #include "tket/Ops/OpPtr.hpp" #include "tket/Utils/GraphHeaders.hpp" diff --git a/tket/src/Gate/OpPtrFunctions.cpp b/tket/src/Gate/OpPtrFunctions.cpp index e96423c91c..29fea23f5c 100644 --- a/tket/src/Gate/OpPtrFunctions.cpp +++ b/tket/src/Gate/OpPtrFunctions.cpp @@ -16,6 +16,7 @@ #include "tket/Gate/Gate.hpp" #include "tket/Gate/SymTable.hpp" +#include "tket/Ops/BarrierOp.hpp" #include "tket/Ops/MetaOp.hpp" namespace tket { @@ -29,6 +30,8 @@ Op_ptr get_op_ptr( if (is_gate_type(chosen_type)) { SymTable::register_symbols(expr_free_symbols(params)); return std::make_shared(chosen_type, params, n_qubits); + } else if (is_barrier_type(chosen_type)) { + return std::make_shared(); } else { return std::make_shared(chosen_type); } diff --git a/tket/src/OpType/OpDesc.cpp b/tket/src/OpType/OpDesc.cpp index 27723f8ff0..f2ea0ab4fb 100644 --- a/tket/src/OpType/OpDesc.cpp +++ b/tket/src/OpType/OpDesc.cpp @@ -24,6 +24,7 @@ OpDesc::OpDesc(OpType type) : type_(type), info_(optypeinfo().at(type)), is_meta_(is_metaop_type(type)), + is_barrier_(is_barrier_type(type)), is_box_(is_box_type(type)), is_gate_(is_gate_type(type)), is_flowop_(is_flowop_type(type)), @@ -75,6 +76,8 @@ OptUInt OpDesc::n_classical() const { bool OpDesc::is_meta() const { return is_meta_; } +bool OpDesc::is_barrier() const { return is_barrier_; } + bool OpDesc::is_box() const { return is_box_; } bool OpDesc::is_gate() const { return is_gate_; } diff --git a/tket/src/OpType/OpTypeFunctions.cpp b/tket/src/OpType/OpTypeFunctions.cpp index 0d52c9c76d..1aa17c1cbf 100644 --- a/tket/src/OpType/OpTypeFunctions.cpp +++ b/tket/src/OpType/OpTypeFunctions.cpp @@ -126,12 +126,13 @@ const OpTypeSet& all_controlled_gate_types() { bool is_metaop_type(OpType optype) { static const OpTypeSet metaops = { - OpType::Input, OpType::Output, OpType::ClInput, - OpType::ClOutput, OpType::WASMInput, OpType::WASMOutput, - OpType::Barrier, OpType::Create, OpType::Discard}; + OpType::Input, OpType::Output, OpType::ClInput, OpType::ClOutput, + OpType::WASMInput, OpType::WASMOutput, OpType::Create, OpType::Discard}; return find_in_set(optype, metaops); } +bool is_barrier_type(OpType optype) { return optype == OpType::Barrier; } + bool is_initial_q_type(OpType optype) { return optype == OpType::Input || optype == OpType::Create; } diff --git a/tket/src/Ops/BarrierOp.cpp b/tket/src/Ops/BarrierOp.cpp new file mode 100644 index 0000000000..402275a98d --- /dev/null +++ b/tket/src/Ops/BarrierOp.cpp @@ -0,0 +1,81 @@ +// Copyright 2019-2023 Cambridge Quantum Computing +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tket/Ops/BarrierOp.hpp" + +#include + +#include "tket/OpType/EdgeType.hpp" +#include "tket/OpType/OpType.hpp" +#include "tket/Utils/Json.hpp" + +namespace tket { + +BarrierOp::BarrierOp(op_signature_t signature, const std::string& _data) + : Op(OpType::Barrier), signature_(signature), data_(_data); + +Op_ptr BarrierOp::symbol_substitution(const SymEngine::map_basic_basic&) const { + return Op_ptr(); +} + +SymSet BarrieraOp::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(); + } +} + +op_signature_t BarrierOp::get_signature() const { + std::optional sig = desc_.signature(); + if (sig) + return *sig; + else + return signature_; +} + +nlohmann::json BarrierOp::serialize() const { + nlohmann::json j; + j["type"] = get_type(); + j["signature"] = get_signature(); + j["data"] = get_data(); + return j; +} + +Op_ptr BarrierOp::deserialize(const nlohmann::json& j) { + op_signature_t sig = j.at("signature").get(); + std::string data; + try { + data = j.at("data").get(); + } catch (const nlohmann::json::out_of_range& e) { + data = ""; + } + return std::make_shared(sig, data); +} + +bool BarrierOp::is_clifford() const { return true; } + +BarrierOp::~BarrierOp() {} + +bool BarrierOp::is_equal(const Op& op_other) const { + const BarrierOp& other = dynamic_cast(op_other); + return (get_signature() == other.get_signature()); +} + +BarrierOp::BarrierOp() : Op(OpType::Barrier) {} + +} // namespace tket diff --git a/tket/test/src/test_Synthesis.cpp b/tket/test/src/test_Synthesis.cpp index da5652503b..a095e2191f 100644 --- a/tket/test/src/test_Synthesis.cpp +++ b/tket/test/src/test_Synthesis.cpp @@ -26,7 +26,7 @@ #include "tket/Gate/Rotation.hpp" #include "tket/OpType/OpType.hpp" #include "tket/OpType/OpTypeFunctions.hpp" -#include "tket/Ops/MetaOp.hpp" +#include "tket/Ops/BarrierOp.hpp" #include "tket/Predicates/CompilationUnit.hpp" #include "tket/Predicates/CompilerPass.hpp" #include "tket/Predicates/PassLibrary.hpp" @@ -1754,8 +1754,8 @@ SCENARIO("Test barrier blocks transforms successfully") { REQUIRE(circ.depth_by_type(OpType::Barrier) == 1); REQUIRE(circ.n_gates() == 3); // both CXs removed Circuit rep(4); - const Op_ptr bar = std::make_shared( - OpType::Barrier, op_signature_t(4, EdgeType::Quantum)); + const Op_ptr bar = + std::make_shared(op_signature_t(4, EdgeType::Quantum)); REQUIRE(circ.substitute_all(rep, bar)); REQUIRE(Transforms::remove_redundancies().apply(circ)); REQUIRE(verify_n_qubits_for_ops(circ)); diff --git a/tket/test/src/test_json.cpp b/tket/test/src/test_json.cpp index 60796e60b1..0d68828ae7 100644 --- a/tket/test/src/test_json.cpp +++ b/tket/test/src/test_json.cpp @@ -70,10 +70,10 @@ bool check_circuit(const Circuit& c) { SCENARIO("Test Op serialization") { GIVEN("OpType") { - const OpTypeSet metaops = {OpType::Input, OpType::Output, - OpType::ClInput, OpType::ClOutput, - OpType::WASMInput, OpType::WASMOutput, - OpType::Barrier}; + const OpTypeSet meta_barrier_ops = {OpType::Input, OpType::Output, + OpType::ClInput, OpType::ClOutput, + OpType::WASMInput, OpType::WASMOutput, + OpType::Barrier}; const OpTypeSet boxes = { OpType::CircBox, OpType::Unitary1qBox, OpType::Unitary2qBox, OpType::Unitary3qBox, @@ -85,7 +85,7 @@ SCENARIO("Test Op serialization") { std::set type_names; for (auto type : - boost::join(all_gate_types(), boost::join(metaops, boxes))) { + boost::join(all_gate_types(), boost::join(meta_barrier_ops, boxes))) { bool success_insert = type_names.insert(optypeinfo().at(type).name).second; // check all optype names are unique From 58d7f557b5eea3da02c609dd77282a3c405cc48d Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Wed, 23 Aug 2023 17:44:18 +0100 Subject: [PATCH 02/34] Add Circuit::add_conditional_gate unsigned and UnitID constructors --- tket/include/tket/Circuit/Circuit.hpp | 6 ++--- tket/include/tket/OpType/OpDesc.hpp | 1 + tket/include/tket/Ops/BarrierOp.hpp | 6 +---- tket/include/tket/Ops/MetaOp.hpp | 3 --- tket/src/Circuit/OpJson.cpp | 2 +- tket/src/Circuit/basic_circ_manip.cpp | 37 ++++++++++++++++++++++----- tket/src/Ops/BarrierOp.cpp | 6 ++--- tket/src/Ops/MetaOp.cpp | 2 -- 8 files changed, 39 insertions(+), 24 deletions(-) diff --git a/tket/include/tket/Circuit/Circuit.hpp b/tket/include/tket/Circuit/Circuit.hpp index 089d433da0..a309d69feb 100644 --- a/tket/include/tket/Circuit/Circuit.hpp +++ b/tket/include/tket/Circuit/Circuit.hpp @@ -924,15 +924,15 @@ class Circuit { Vertex add_barrier(const unit_vector_t &args, const std::string &_data = ""); Vertex add_conditional_barrier( - const std::vector ¶ms, const std::vector &barrier_qubits, const std::vector &barrier_bits, const std::vector &condition_bits, unsigned value, + const std::string &_data, std::optional opgroup = std::nullopt); Vertex add_conditional_barrier( - const std::vector ¶ms, const unit_vector_t &barrier_uids, - const unit_vector_t &condition_bits, unsigned value, + const unit_vector_t &barrier_args, const unit_vector_t &condition_bits, + unsigned value, const std::string &_data, std::optional opgroup = std::nullopt); /** diff --git a/tket/include/tket/OpType/OpDesc.hpp b/tket/include/tket/OpType/OpDesc.hpp index c56e738db9..fa3c34aa61 100644 --- a/tket/include/tket/OpType/OpDesc.hpp +++ b/tket/include/tket/OpType/OpDesc.hpp @@ -114,6 +114,7 @@ class OpDesc { const OpType type_; const OpTypeInfo info_; const bool is_meta_; + const bool is_barrier_; const bool is_box_; const bool is_gate_; const bool is_flowop_; diff --git a/tket/include/tket/Ops/BarrierOp.hpp b/tket/include/tket/Ops/BarrierOp.hpp index 0e64d670e1..f889b3a265 100644 --- a/tket/include/tket/Ops/BarrierOp.hpp +++ b/tket/include/tket/Ops/BarrierOp.hpp @@ -22,8 +22,7 @@ namespace tket { class BarrierOp : public Op { public: explicit BarrierOp( - op_signature_t signature = {}, - const std::string &_data = ""); + op_signature_t signature = {}, const std::string &_data = ""); Op_ptr symbol_substitution( const SymEngine::map_basic_basic &sub_map) const override; @@ -49,9 +48,6 @@ class BarrierOp : public Op { static Op_ptr deserialize(const nlohmann::json &j); - protected: - BarrierOp(); - private: op_signature_t signature_; /**< Types of inputs, when not deducible from op type */ diff --git a/tket/include/tket/Ops/MetaOp.hpp b/tket/include/tket/Ops/MetaOp.hpp index 14b89398c9..e3b6cf45d6 100644 --- a/tket/include/tket/Ops/MetaOp.hpp +++ b/tket/include/tket/Ops/MetaOp.hpp @@ -49,9 +49,6 @@ class MetaOp : public Op { static Op_ptr deserialize(const nlohmann::json &j); - protected: - MetaOp(); - private: op_signature_t signature_; /**< Types of inputs, when not deducible from op type */ diff --git a/tket/src/Circuit/OpJson.cpp b/tket/src/Circuit/OpJson.cpp index 6ff8f7a13f..9aba5c5ab2 100644 --- a/tket/src/Circuit/OpJson.cpp +++ b/tket/src/Circuit/OpJson.cpp @@ -29,7 +29,7 @@ void from_json(const nlohmann::json& j, Op_ptr& op) { OpType optype = j.at("type").get(); if (is_metaop_type(optype)) { op = MetaOp::deserialize(j); - } else if (if_barrier_type(optype)) { + } else if (is_barrier_type(optype)) { op = BarrierOp::deserialize(j); } else if (is_box_type(optype)) { op = Box::deserialize(j); diff --git a/tket/src/Circuit/basic_circ_manip.cpp b/tket/src/Circuit/basic_circ_manip.cpp index 42512b5668..301ae36d04 100644 --- a/tket/src/Circuit/basic_circ_manip.cpp +++ b/tket/src/Circuit/basic_circ_manip.cpp @@ -131,6 +131,7 @@ Vertex Circuit::add_barrier( Vertex Circuit::add_barrier( const unit_vector_t& args, const std::string& _data) { + op_signature_t sig; for (const UnitID& arg : args) { if (arg.type() == UnitType::Qubit) { sig.push_back(EdgeType::Quantum); @@ -145,18 +146,42 @@ Vertex Circuit::add_conditional_barrier( const std::vector& barrier_qubits, const std::vector& barrier_bits, const std::vector& condition_bits, unsigned value, - const std::string& _data) { + const std::string& _data, std::optional opgroup) { + // TODO: check no overlapping elements between barrier and condition bits op_signature_t sig(barrier_qubits.size(), EdgeType::Quantum); sig.insert(sig.end(), barrier_bits.size(), EdgeType::Classical); - return add_op(std::make_shared( - std::make_shared(sig, _data), (unsigned)condition_bits.size(), - value)) + std::vector args = condition_bits; + args.insert(args.end(), barrier_qubits.begin(), barrier_qubits.end()); + args.insert(args.end(), barrier_bits.begin(), barrier_bits.end()); + return add_op( + std::make_shared( + std::make_shared(sig, _data), + (unsigned)condition_bits.size(), value), + args, opgroup); } Vertex Circuit::add_conditional_barrier( - const unit_vector_t& barrier_uids, const unit_vector_t& condition_bits, - unsigned value, std::optional opgroup = std::nullopt); + const unit_vector_t& barrier_args, const unit_vector_t& condition_bits, + unsigned value, const std::string& _data, + std::optional opgroup) { + // TODO: check no overlapping elements between barrier and condition bits + op_signature_t sig; + for (const UnitID& arg : barrier_args) { + if (arg.type() == UnitType::Qubit) { + sig.push_back(EdgeType::Quantum); + } else { + sig.push_back(EdgeType::Classical); + } + } + unit_vector_t args = condition_bits; + args.insert(args.end(), barrier_args.begin(), barrier_args.end()); + return add_op( + std::make_shared( + std::make_shared(sig, _data), + (unsigned)condition_bits.size(), value), + args, opgroup); +} std::string Circuit::get_next_c_reg_name(const std::string& reg_name) { if (!get_reg_info(reg_name)) { diff --git a/tket/src/Ops/BarrierOp.cpp b/tket/src/Ops/BarrierOp.cpp index 402275a98d..f8011362e3 100644 --- a/tket/src/Ops/BarrierOp.cpp +++ b/tket/src/Ops/BarrierOp.cpp @@ -23,13 +23,13 @@ namespace tket { BarrierOp::BarrierOp(op_signature_t signature, const std::string& _data) - : Op(OpType::Barrier), signature_(signature), data_(_data); + : Op(OpType::Barrier), signature_(signature), data_(_data) {} Op_ptr BarrierOp::symbol_substitution(const SymEngine::map_basic_basic&) const { return Op_ptr(); } -SymSet BarrieraOp::free_symbols() const { return {}; } +SymSet BarrierOp::free_symbols() const { return {}; } unsigned BarrierOp::n_qubits() const { OptUInt n = desc_.n_qubits(); @@ -76,6 +76,4 @@ bool BarrierOp::is_equal(const Op& op_other) const { return (get_signature() == other.get_signature()); } -BarrierOp::BarrierOp() : Op(OpType::Barrier) {} - } // namespace tket diff --git a/tket/src/Ops/MetaOp.cpp b/tket/src/Ops/MetaOp.cpp index b3f8bc5218..e2013e4ee8 100644 --- a/tket/src/Ops/MetaOp.cpp +++ b/tket/src/Ops/MetaOp.cpp @@ -79,6 +79,4 @@ bool MetaOp::is_equal(const Op& op_other) const { return (get_signature() == other.get_signature()); } -MetaOp::MetaOp() : Op(OpType::Barrier) {} - } // namespace tket From 6ee6d0924dc1a68e6833dbcf48e83cf7171ef9d7 Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Thu, 24 Aug 2023 15:04:48 +0100 Subject: [PATCH 03/34] Add tests to confirm DAG is wired suitably for conditional barrier gates --- tket/src/Circuit/basic_circ_manip.cpp | 2 - tket/test/src/Circuit/test_Circ.cpp | 168 ++++++++++++++++++++++++++ 2 files changed, 168 insertions(+), 2 deletions(-) diff --git a/tket/src/Circuit/basic_circ_manip.cpp b/tket/src/Circuit/basic_circ_manip.cpp index 301ae36d04..eb0daa880b 100644 --- a/tket/src/Circuit/basic_circ_manip.cpp +++ b/tket/src/Circuit/basic_circ_manip.cpp @@ -147,7 +147,6 @@ Vertex Circuit::add_conditional_barrier( const std::vector& barrier_bits, const std::vector& condition_bits, unsigned value, const std::string& _data, std::optional opgroup) { - // TODO: check no overlapping elements between barrier and condition bits op_signature_t sig(barrier_qubits.size(), EdgeType::Quantum); sig.insert(sig.end(), barrier_bits.size(), EdgeType::Classical); @@ -165,7 +164,6 @@ Vertex Circuit::add_conditional_barrier( const unit_vector_t& barrier_args, const unit_vector_t& condition_bits, unsigned value, const std::string& _data, std::optional opgroup) { - // TODO: check no overlapping elements between barrier and condition bits op_signature_t sig; for (const UnitID& arg : barrier_args) { if (arg.type() == UnitType::Qubit) { diff --git a/tket/test/src/Circuit/test_Circ.cpp b/tket/test/src/Circuit/test_Circ.cpp index bfa242003f..32cab51d2b 100644 --- a/tket/test/src/Circuit/test_Circ.cpp +++ b/tket/test/src/Circuit/test_Circ.cpp @@ -3117,6 +3117,174 @@ SCENARIO("check edge type in rewire function") { REQUIRE_THROWS_AS(c.rewire(v, ins, types), CircuitInvalidity); } } +void check_conditional_circuit(Circuit& c) { + // Confirm that the DAG is constructed appropriately by checking + // in and out edges of all vertices + std::vector vertices = c.all_vertices(); + // First check Quantum and Classical input and output vertices + // have expected number of out edges in interesting cases + REQUIRE(c.n_out_edges_of_type(vertices[8], EdgeType::Classical) == 1); + REQUIRE(c.n_out_edges_of_type(vertices[8], EdgeType::Boolean) == 1); + REQUIRE(c.n_out_edges_of_type(vertices[10], EdgeType::Classical) == 1); + REQUIRE(c.n_out_edges_of_type(vertices[10], EdgeType::Boolean) == 2); + REQUIRE(c.n_out_edges_of_type(vertices[12], EdgeType::Classical) == 1); + REQUIRE(c.n_out_edges_of_type(vertices[12], EdgeType::Boolean) == 2); + REQUIRE(c.n_out_edges_of_type(vertices[14], EdgeType::Classical) == 1); + REQUIRE(c.n_out_edges_of_type(vertices[14], EdgeType::Boolean) == 2); + + // Conditional gate 0 + REQUIRE(c.n_in_edges_of_type(vertices[18], EdgeType::Quantum) == 1); + REQUIRE(c.n_in_edges_of_type(vertices[18], EdgeType::Classical) == 0); + REQUIRE(c.n_in_edges_of_type(vertices[18], EdgeType::Boolean) == 1); + REQUIRE(c.n_out_edges_of_type(vertices[18], EdgeType::Quantum) == 1); + REQUIRE(c.n_out_edges_of_type(vertices[18], EdgeType::Classical) == 0); + REQUIRE(c.n_out_edges_of_type(vertices[18], EdgeType::Boolean) == 0); + Op_ptr op_0 = c.get_Op_ptr_from_Vertex(vertices[18]); + const Conditional& con_0 = static_cast(*op_0); + REQUIRE(con_0.get_type() == OpType::Conditional); + Op_ptr barrier_0 = con_0.get_op(); + REQUIRE(barrier_0->get_type() == OpType::Barrier); + op_signature_t sig_0 = {EdgeType::Quantum}; + REQUIRE(barrier_0->get_signature() == sig_0); + + // Conditional gate 1 + REQUIRE(c.n_in_edges_of_type(vertices[19], EdgeType::Quantum) == 2); + REQUIRE(c.n_in_edges_of_type(vertices[19], EdgeType::Classical) == 1); + REQUIRE(c.n_in_edges_of_type(vertices[19], EdgeType::Boolean) == 2); + REQUIRE(c.n_out_edges_of_type(vertices[19], EdgeType::Quantum) == 2); + REQUIRE(c.n_out_edges_of_type(vertices[19], EdgeType::Classical) == 1); + REQUIRE(c.n_out_edges_of_type(vertices[19], EdgeType::Boolean) == 0); + Op_ptr op_1 = c.get_Op_ptr_from_Vertex(vertices[19]); + const Conditional& con_1 = static_cast(*op_1); + REQUIRE(con_1.get_type() == OpType::Conditional); + Op_ptr barrier_1 = con_1.get_op(); + REQUIRE(barrier_1->get_type() == OpType::Barrier); + op_signature_t sig_1 = { + EdgeType::Quantum, EdgeType::Quantum, EdgeType::Classical}; + REQUIRE(barrier_1->get_signature() == sig_1); + + // Conditional gate 2 + REQUIRE(c.n_in_edges_of_type(vertices[20], EdgeType::Quantum) == 1); + REQUIRE(c.n_in_edges_of_type(vertices[20], EdgeType::Classical) == 1); + REQUIRE(c.n_in_edges_of_type(vertices[20], EdgeType::Boolean) == 2); + REQUIRE(c.n_out_edges_of_type(vertices[20], EdgeType::Quantum) == 1); + REQUIRE(c.n_out_edges_of_type(vertices[20], EdgeType::Classical) == 1); + REQUIRE(c.n_out_edges_of_type(vertices[20], EdgeType::Boolean) == 0); + Op_ptr op_2 = c.get_Op_ptr_from_Vertex(vertices[20]); + const Conditional& con_2 = static_cast(*op_2); + REQUIRE(con_2.get_type() == OpType::Conditional); + Op_ptr barrier_2 = con_2.get_op(); + REQUIRE(barrier_2->get_type() == OpType::Barrier); + op_signature_t sig_2 = {EdgeType::Quantum, EdgeType::Classical}; + REQUIRE(barrier_2->get_signature() == sig_2); + + // Conditional gate 3 + REQUIRE(c.n_in_edges_of_type(vertices[21], EdgeType::Quantum) == 2); + REQUIRE(c.n_in_edges_of_type(vertices[21], EdgeType::Classical) == 3); + REQUIRE(c.n_in_edges_of_type(vertices[21], EdgeType::Boolean) == 1); + REQUIRE(c.n_out_edges_of_type(vertices[21], EdgeType::Quantum) == 2); + REQUIRE(c.n_out_edges_of_type(vertices[21], EdgeType::Classical) == 3); + REQUIRE(c.n_out_edges_of_type(vertices[21], EdgeType::Boolean) == 2); + Op_ptr op_3 = c.get_Op_ptr_from_Vertex(vertices[21]); + const Conditional& con_3 = static_cast(*op_3); + REQUIRE(con_3.get_type() == OpType::Conditional); + Op_ptr barrier_3 = con_3.get_op(); + REQUIRE(barrier_3->get_type() == OpType::Barrier); + op_signature_t sig_3 = { + EdgeType::Quantum, EdgeType::Quantum, EdgeType::Classical, + EdgeType::Classical, EdgeType::Classical}; + REQUIRE(barrier_3->get_signature() == sig_3); + + // Conditional gate 4 + REQUIRE(c.n_in_edges_of_type(vertices[22], EdgeType::Quantum) == 2); + REQUIRE(c.n_in_edges_of_type(vertices[22], EdgeType::Classical) == 1); + REQUIRE(c.n_in_edges_of_type(vertices[22], EdgeType::Boolean) == 2); + REQUIRE(c.n_out_edges_of_type(vertices[22], EdgeType::Quantum) == 2); + REQUIRE(c.n_out_edges_of_type(vertices[22], EdgeType::Classical) == 1); + REQUIRE(c.n_out_edges_of_type(vertices[22], EdgeType::Boolean) == 0); + Op_ptr op_4 = c.get_Op_ptr_from_Vertex(vertices[22]); + const Conditional& con_4 = static_cast(*op_4); + REQUIRE(con_4.get_type() == OpType::Conditional); + Op_ptr barrier_4 = con_4.get_op(); + REQUIRE(barrier_4->get_type() == OpType::Barrier); + op_signature_t sig_4 = { + EdgeType::Quantum, EdgeType::Quantum, EdgeType::Classical}; + REQUIRE(barrier_4->get_signature() == sig_4); + + // Conditional gate 5 + REQUIRE(c.n_in_edges_of_type(vertices[23], EdgeType::Quantum) == 4); + REQUIRE(c.n_in_edges_of_type(vertices[23], EdgeType::Classical) == 3); + REQUIRE(c.n_in_edges_of_type(vertices[23], EdgeType::Boolean) == 1); + REQUIRE(c.n_out_edges_of_type(vertices[23], EdgeType::Quantum) == 4); + REQUIRE(c.n_out_edges_of_type(vertices[23], EdgeType::Classical) == 3); + REQUIRE(c.n_out_edges_of_type(vertices[23], EdgeType::Boolean) == 0); + Op_ptr op_5 = c.get_Op_ptr_from_Vertex(vertices[23]); + const Conditional& con_5 = static_cast(*op_5); + REQUIRE(con_5.get_type() == OpType::Conditional); + Op_ptr barrier_5 = con_5.get_op(); + REQUIRE(barrier_5->get_type() == OpType::Barrier); + op_signature_t sig_5 = {EdgeType::Quantum, EdgeType::Quantum, + EdgeType::Quantum, EdgeType::Quantum, + EdgeType::Classical, EdgeType::Classical, + EdgeType::Classical}; + REQUIRE(barrier_5->get_signature() == sig_5); + + // Conditional gate 6 + REQUIRE(c.n_in_edges_of_type(vertices[25], EdgeType::Quantum) == 4); + REQUIRE(c.n_in_edges_of_type(vertices[25], EdgeType::Classical) == 3); + REQUIRE(c.n_in_edges_of_type(vertices[25], EdgeType::Boolean) == 1); + REQUIRE(c.n_out_edges_of_type(vertices[25], EdgeType::Quantum) == 4); + REQUIRE(c.n_out_edges_of_type(vertices[25], EdgeType::Classical) == 3); + REQUIRE(c.n_out_edges_of_type(vertices[25], EdgeType::Boolean) == 0); + Op_ptr op_6 = c.get_Op_ptr_from_Vertex(vertices[25]); + const Conditional& con_6 = static_cast(*op_6); + REQUIRE(con_6.get_type() == OpType::Conditional); + Op_ptr barrier_6 = con_6.get_op(); + REQUIRE(barrier_6->get_type() == OpType::Barrier); + op_signature_t sig_6 = {EdgeType::Quantum, EdgeType::Quantum, + EdgeType::Quantum, EdgeType::Quantum, + EdgeType::Classical, EdgeType::Classical, + EdgeType::Classical}; + REQUIRE(barrier_6->get_signature() == sig_6); +} + +SCENARIO("Check Circuit::add_conditional_barrier.") { + GIVEN( + "Add various forms of valid conditional barrier using the unsigned " + "constructor.") { + Circuit c(4, 5); + c.add_conditional_barrier({0}, {}, {0}, 0, ""); + c.add_conditional_barrier({0, 1}, {0}, {1, 2}, 1, ""); + c.add_conditional_barrier({0}, {0}, {1, 2}, 1, ""); + c.add_conditional_barrier({1, 3}, {0, 1, 2}, {3}, 0, "test"); + c.add_conditional_barrier({0, 2}, {0}, {1, 2}, 1, "test1"); + c.add_conditional_barrier({0, 1, 2, 3}, {0, 1, 2}, {3}, 0, "test1"); + c.add_measure(3, 4); + c.add_conditional_barrier({0, 1, 2, 3}, {0, 1, 2}, {4}, 0, "test2"); + check_conditional_circuit(c); + } + GIVEN( + "Add various forms of valid conditional barrier using the unitid " + "constructor.") { + Circuit c(4, 5); + c.add_conditional_barrier({Qubit(0)}, {Bit(0)}, 0, ""); + c.add_conditional_barrier( + {Qubit(0), Qubit(1), Bit(0)}, {Bit(1), Bit(2)}, 1, ""); + c.add_conditional_barrier({Qubit(0), Bit(0)}, {Bit(1), Bit(2)}, 1, ""); + c.add_conditional_barrier( + {Qubit(1), Qubit(3), Bit(0), Bit(1), Bit(2)}, {Bit(3)}, 0, "test"); + c.add_conditional_barrier( + {Qubit(0), Qubit(2), Bit(0)}, {Bit(1), Bit(2)}, 1, "test1"); + c.add_conditional_barrier( + {Qubit(0), Qubit(1), Qubit(2), Qubit(3), Bit(0), Bit(1), Bit(2)}, + {Bit(3)}, 0, "test1"); + c.add_measure(Qubit(3), Bit(4)); + c.add_conditional_barrier( + {Qubit(0), Qubit(1), Qubit(2), Qubit(3), Bit(0), Bit(1), Bit(2)}, + {Bit(4)}, 0, "test2"); + check_conditional_circuit(c); + } +} } // namespace test_Circ } // namespace tket From cbd62a102eb45c9146793e2a4b6477794e78fff3 Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Fri, 25 Aug 2023 10:22:25 +0100 Subject: [PATCH 04/34] Add tests and case handling for conditional barrier over different circumstances --- tket/src/Converters/ZXConverters.cpp | 5 +++++ tket/src/Mapping/MappingFrontier.cpp | 18 +++++++----------- tket/src/Mapping/Verification.cpp | 2 +- .../src/Circuit/test_ThreeQubitConversion.cpp | 4 +++- tket/test/src/Passes/test_SynthesiseTket.cpp | 3 ++- .../src/Simulation/test_CircuitSimulator.cpp | 7 +++++++ tket/test/src/ZX/test_ZXConverters.cpp | 7 +++++++ tket/test/src/test_CompilerPass.cpp | 5 +++-- tket/test/src/test_LexiRoute.cpp | 3 ++- tket/test/src/test_Rebase.cpp | 2 ++ tket/test/src/test_RoutingPasses.cpp | 2 ++ tket/test/src/test_TwoQubitCanonical.cpp | 3 ++- tket/test/src/test_json.cpp | 1 + 13 files changed, 44 insertions(+), 18 deletions(-) diff --git a/tket/src/Converters/ZXConverters.cpp b/tket/src/Converters/ZXConverters.cpp index 39e8e7c208..3a33eb6c51 100644 --- a/tket/src/Converters/ZXConverters.cpp +++ b/tket/src/Converters/ZXConverters.cpp @@ -311,6 +311,11 @@ BoundaryVertMap circuit_to_zx_recursive( } op = cond.get_op(); } + if (is_barrier_type(op->get_type())) { + throw Unsupported( + "Cannot convert conditional barrier operations to a ZX node. \n"); + } + unsigned port_conditions_size = static_cast(port_conditions.size()); // Convert the underlying op to zx. diff --git a/tket/src/Mapping/MappingFrontier.cpp b/tket/src/Mapping/MappingFrontier.cpp index 1a8f22330e..2d6fa90212 100644 --- a/tket/src/Mapping/MappingFrontier.cpp +++ b/tket/src/Mapping/MappingFrontier.cpp @@ -1011,29 +1011,25 @@ void MappingFrontier::merge_ancilla( bool MappingFrontier::valid_boundary_operation( const ArchitecturePtr& architecture, const Op_ptr& op, const std::vector& uids) const { - // boxes are never allowed OpType ot = op->get_type(); - if (is_box_type(ot)) { - return false; - } if (ot == OpType::Conditional) { Op_ptr cond_op_ptr = static_cast(*op).get_op(); // conditional boxes are never allowed, too - OpType ot = cond_op_ptr->get_type(); + ot = cond_op_ptr->get_type(); while (ot == OpType::Conditional) { cond_op_ptr = static_cast(*op).get_op(); ot = cond_op_ptr->get_type(); - if (is_box_type(ot)) { - return false; - } } } - - // Barriers are allways allowed - if (ot == OpType::Barrier) { + // Barriers are always allowed + if (is_barrier_type(ot)) { return true; } + // boxes are never allowed + if (is_box_type(ot)) { + return false; + } // this currently allows unplaced single qubits gates // this should be changes in the future diff --git a/tket/src/Mapping/Verification.cpp b/tket/src/Mapping/Verification.cpp index 167cf4a4a7..dbb094d624 100644 --- a/tket/src/Mapping/Verification.cpp +++ b/tket/src/Mapping/Verification.cpp @@ -30,12 +30,12 @@ bool respects_connectivity_constraints( if (qb_lookup.find(arg) != qb_lookup.end()) qbs.push_back(arg); } Op_ptr op = com.get_op_ptr(); - if (op->get_type() == OpType::Barrier) continue; if (op->get_type() == OpType::Conditional) { std::shared_ptr cond_ptr = std::dynamic_pointer_cast(op); op = cond_ptr->get_op(); } + if (op->get_type() == OpType::Barrier) continue; if (op->get_type() == OpType::CircBox) { std::shared_ptr box_ptr = std::dynamic_pointer_cast(op); diff --git a/tket/test/src/Circuit/test_ThreeQubitConversion.cpp b/tket/test/src/Circuit/test_ThreeQubitConversion.cpp index beec896801..c0ffb89087 100644 --- a/tket/test/src/Circuit/test_ThreeQubitConversion.cpp +++ b/tket/test/src/Circuit/test_ThreeQubitConversion.cpp @@ -480,6 +480,7 @@ SCENARIO("Three-qubit squash") { c.add_op(OpType::CX, {i % 3, (i + 1) % 3}); c.add_op(OpType::Rz, 0.25, {(i + 1) % 3}); } + c.add_conditional_barrier({0, 1}, {}, {0}, 1, ""); c.add_conditional_gate(OpType::X, {}, {0}, {0}, 1); for (unsigned i = 11; i < 22; i++) { c.add_op(OpType::H, {i % 3}); @@ -489,13 +490,14 @@ SCENARIO("Three-qubit squash") { CHECK_FALSE(Transforms::three_qubit_squash().apply(c)); } GIVEN("A circuit with a barrier") { - Circuit c(3); + Circuit c(3, 1); for (unsigned i = 0; i < 11; i++) { c.add_op(OpType::H, {i % 3}); c.add_op(OpType::CX, {i % 3, (i + 1) % 3}); c.add_op(OpType::Rz, 0.25, {(i + 1) % 3}); } c.add_barrier({0, 1, 2}); + c.add_conditional_barrier({0, 2, 1}, {}, {0}, 1, ""); for (unsigned i = 11; i < 22; i++) { c.add_op(OpType::H, {i % 3}); c.add_op(OpType::CX, {i % 3, (i + 1) % 3}); diff --git a/tket/test/src/Passes/test_SynthesiseTket.cpp b/tket/test/src/Passes/test_SynthesiseTket.cpp index fab5f011e8..07250936da 100644 --- a/tket/test/src/Passes/test_SynthesiseTket.cpp +++ b/tket/test/src/Passes/test_SynthesiseTket.cpp @@ -27,10 +27,11 @@ SCENARIO("SynthesiseTket with conditionals") { c.add_c_register("c", 1); c.add_conditional_gate(OpType::CnRy, {0.25}, {0, 1}, {0}, 0); c.add_conditional_gate(OpType::Ry, {0.125}, {1}, {0}, 0); + c.add_conditional_barrier({0, 1}, {}, {0}, 1, ""); CompilationUnit cu(c); SynthesiseTket()->apply(cu); Circuit c1 = cu.get_circ_ref(); - REQUIRE(c1.n_gates() == 5); + REQUIRE(c1.n_gates() == 6); } } // namespace test_SynthesiseTket diff --git a/tket/test/src/Simulation/test_CircuitSimulator.cpp b/tket/test/src/Simulation/test_CircuitSimulator.cpp index f16820b173..3fc2ef4108 100644 --- a/tket/test/src/Simulation/test_CircuitSimulator.cpp +++ b/tket/test/src/Simulation/test_CircuitSimulator.cpp @@ -176,6 +176,13 @@ SCENARIO("Simulate circuit with unsupported operations") { tket_sim::get_unitary(circ), Unsupported, MessageContains("Unsupported OpType Conditional")); } + GIVEN("Circuit with conditional barrier") { + Circuit circ(2, 2); + circ.add_conditional_barrier({0, 1}, {1}, {0}, 1, ""); + REQUIRE_THROWS_MATCHES( + tket_sim::get_unitary(circ), Unsupported, + MessageContains("Unsupported OpType Conditional")); + } } SCENARIO("Ignored op types don't affect get unitary") { diff --git a/tket/test/src/ZX/test_ZXConverters.cpp b/tket/test/src/ZX/test_ZXConverters.cpp index 23e7a8ff6e..65ce361b04 100644 --- a/tket/test/src/ZX/test_ZXConverters.cpp +++ b/tket/test/src/ZX/test_ZXConverters.cpp @@ -266,6 +266,13 @@ SCENARIO("Check converting gates to spiders") { REQUIRE(zx.n_wires() == 2); REQUIRE_NOTHROW(zx.check_validity()); } + GIVEN("Conditional Barrier") { + Circuit circ(2, 2); + circ.add_conditional_barrier( + std::vector{0, 1}, std::vector{0}, + std::vector{1}, 1, ""); + REQUIRE_THROWS_AS(circuit_to_zx(circ), Unsupported); + } GIVEN("noop") { Circuit circ(1); circ.add_op(OpType::noop, {0}); diff --git a/tket/test/src/test_CompilerPass.cpp b/tket/test/src/test_CompilerPass.cpp index b37e89b86a..80c5f8b957 100644 --- a/tket/test/src/test_CompilerPass.cpp +++ b/tket/test/src/test_CompilerPass.cpp @@ -356,15 +356,16 @@ SCENARIO("Test making (mostly routing) passes using PassGenerators") { circ.add_conditional_gate(OpType::Rz, {0.142}, {0}, {0}, 0); circ.add_conditional_gate(OpType::Rz, {0.143}, {0}, {0}, 0); circ.add_conditional_gate(OpType::Rx, {0.528}, {1}, {0}, 0); + circ.add_conditional_barrier({0, 1}, {}, {0}, 1, ""); CompilationUnit cu(circ); squash->apply(cu); const Circuit& c = cu.get_circ_ref(); c.assert_valid(); - REQUIRE(c.n_gates() == 3); + REQUIRE(c.n_gates() == 4); std::vector expected_optypes{ OpType::Conditional, // qubit 0 before CX OpType::Conditional, // qubit 1 before CX - OpType::CX}; + OpType::CX, OpType::Conditional}; check_command_types(c, expected_optypes); auto cmds = c.get_commands(); diff --git a/tket/test/src/test_LexiRoute.cpp b/tket/test/src/test_LexiRoute.cpp index 83b4442c73..004c2ebf86 100644 --- a/tket/test/src/test_LexiRoute.cpp +++ b/tket/test/src/test_LexiRoute.cpp @@ -459,6 +459,7 @@ SCENARIO("Test LexiRoute::solve and LexiRoute::solve_labelling") { circ.add_op(OpType::Measure, {qubits[1], Bit(0)}); circ.add_op(OpType::CX, {qubits[4], qubits[5]}); circ.add_op(OpType::Measure, {qubits[3], Bit(0)}); + circ.add_conditional_barrier({0, 1, 2}, {}, {0}, 1, ""); // n0 -- n1 -- n2 -- n3 -- n4 // | | // n5 n7 @@ -473,7 +474,7 @@ SCENARIO("Test LexiRoute::solve and LexiRoute::solve_labelling") { lr.solve(4); std::vector commands = mf->circuit_.get_commands(); - REQUIRE(commands.size() == 7); + REQUIRE(commands.size() == 8); Command swap_c = commands[1]; unit_vector_t uids = {nodes[1], nodes[2]}; REQUIRE(swap_c.get_args() == uids); diff --git a/tket/test/src/test_Rebase.cpp b/tket/test/src/test_Rebase.cpp index df0b02987c..e749f0a836 100644 --- a/tket/test/src/test_Rebase.cpp +++ b/tket/test/src/test_Rebase.cpp @@ -290,12 +290,14 @@ SCENARIO("Building rebases with rebase_factory") { Circuit circ(2, 1); circ.add_op(OpType::T, {0}); circ.add_conditional_gate(OpType::H, {}, {1}, {0}, 1); + circ.add_conditional_barrier({0, 1}, {}, {0}, 1, ""); Transforms::rebase_tket().apply(circ); Circuit correct(2, 1); correct.add_op(OpType::TK1, {0, 0, 0.25}, {0}); correct.add_conditional_gate( OpType::TK1, {0.5, 0.5, 0.5}, {1}, {0}, 1); correct.add_conditional_gate(OpType::Phase, {0.5}, {}, {0}, 1); + correct.add_conditional_barrier({0, 1}, {}, {0}, 1, ""); correct.add_phase(0.125); REQUIRE(circ == correct); } diff --git a/tket/test/src/test_RoutingPasses.cpp b/tket/test/src/test_RoutingPasses.cpp index 4148efa1ac..635428220c 100644 --- a/tket/test/src/test_RoutingPasses.cpp +++ b/tket/test/src/test_RoutingPasses.cpp @@ -364,6 +364,7 @@ SCENARIO( circ.add_conditional_gate(OpType::CX, {}, {2, 1}, {0, 1}, 1); circ.add_conditional_gate(OpType::CX, {}, {0, 1}, {0, 1}, 2); circ.add_conditional_gate(OpType::CX, {}, {2, 1}, {1, 0}, 3); + circ.add_conditional_barrier({1, 2}, {1}, {0}, 1, ""); circ.add_conditional_gate(OpType::CX, {}, {0, 2}, {0, 1}, 0); MappingManager mm(std::make_shared(test_arc)); REQUIRE(mm.route_circuit( @@ -382,6 +383,7 @@ SCENARIO( Circuit circ(5, 1); circ.add_conditional_gate(OpType::CX, {}, {0, 1}, {0}, 1); add_2qb_gates(circ, OpType::CX, {{0, 1}, {1, 2}, {1, 3}, {1, 4}, {0, 1}}); + circ.add_conditional_barrier({0, 1, 2}, {}, {0}, 1, ""); MappingManager mm(std::make_shared(arc)); REQUIRE(mm.route_circuit( diff --git a/tket/test/src/test_TwoQubitCanonical.cpp b/tket/test/src/test_TwoQubitCanonical.cpp index e0f3a6aa0e..19ea9b22e6 100644 --- a/tket/test/src/test_TwoQubitCanonical.cpp +++ b/tket/test/src/test_TwoQubitCanonical.cpp @@ -689,8 +689,9 @@ SCENARIO("two_qubit_squash with classical ops") { circ.add_conditional_gate(OpType::CX, {}, {0, 1}, {0}, 1); circ.add_op(tket::OpType::CX, {0, 1}); circ.add_op(tket::OpType::CX, {0, 1}); + circ.add_conditional_barrier({0, 1}, {}, {0}, 1, ""); REQUIRE(Transforms::two_qubit_squash(OpType::CX).apply(circ)); - REQUIRE(circ.n_gates() == 1); + REQUIRE(circ.n_gates() == 2); REQUIRE(circ.get_commands()[0].get_vertex() == v); } GIVEN("Circuit with conditional gates") { diff --git a/tket/test/src/test_json.cpp b/tket/test/src/test_json.cpp index 0d68828ae7..cd49eb9995 100644 --- a/tket/test/src/test_json.cpp +++ b/tket/test/src/test_json.cpp @@ -225,6 +225,7 @@ SCENARIO("Test Circuit serialization") { c.add_conditional_gate(OpType::Ry, {-0.75}, {0}, {0, 1}, 1); c.add_conditional_gate(OpType::CX, {}, {0, 1}, {0, 1}, 1); c.add_conditional_gate(OpType::Measure, {}, {0, 2}, {0, 1}, 1); + c.add_conditional_barrier({0, 1}, {1, 2}, {0}, 0, ""); nlohmann::json j_box = c; const Circuit new_c = j_box.get(); From 6a682c3b94291f7cf2b63fee832a69470d494a90 Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Tue, 29 Aug 2023 09:52:16 +0100 Subject: [PATCH 05/34] add `_add_conditonal_barrier` method to Circuit class --- pytket/binders/circuit/Circuit/add_op.cpp | 53 ++++++++++++++++++----- pytket/tests/qasm_test.py | 1 + 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/pytket/binders/circuit/Circuit/add_op.cpp b/pytket/binders/circuit/Circuit/add_op.cpp index da05b3dd26..33c7612857 100644 --- a/pytket/binders/circuit/Circuit/add_op.cpp +++ b/pytket/binders/circuit/Circuit/add_op.cpp @@ -179,21 +179,27 @@ void init_circuit_add_op(py::class_> &c) { .def( "_add_conditional_barrier", []( - (Circuit *circ, const std::vector ¶ms, - const std::vector &qubits, - std::vector &barrier_bits const std::vector - &condition_bits, - unsigned value) { - std::vector barrier_args; - for (const unsig) - circ->add_conditional_barrier(params, args, bits, value); + (Circuit *circ, const std::vector &barrier_qubits, + const std::vector &barrier_bits, + const std::vector &condition_bits, unsigned value, + const std::string &data) { + circ->add_conditional_barrier( + barrier_qubits, barrier_bits, condition_bits, value, data); return circ; }, - "Append a Conditional Barrier on the given units, conditioned on " - "the givne Bit." - "\n\n:param data: additional data stored in the barrier" + "Append a Conditional Barrier on the given barrier qubits and " + "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 " + "of barrier operation." + "\n:param value: Value that classical condition must have to " + "hold." + "\n: param data: Additional data stored in Barrier operation." "\n:return: the new :py:class:`Circuit`", - py::arg("qubits"), py::arg("bits") = no_bits, + py::arg("barrier_qubits"), py::arg("barrier_bits"), + py::arg("condition_bits"), py::arg("value"), py::arg("data") = "")) .def( "add_circbox", @@ -437,6 +443,29 @@ void init_circuit_add_op(py::class_> &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", + []( + (Circuit *circ, const unit_vector_t &barrier_args, + const unit_vector_t &condition_bits, unsigned value, + const std::string &_data) { + circ->add_conditional_barrier( + barrier_args, condition_bits, value, data); + return circ; + }, + "Append a Conditional Barrier on the given barrier qubits and " + "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." + "\n:param value: Value that classical condition must have to " + "hold." + "\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") = "")) .def( "add_circbox", [](Circuit *circ, const CircBox &box, const unit_vector_t &args, diff --git a/pytket/tests/qasm_test.py b/pytket/tests/qasm_test.py index d1951a0dcf..36b47fac34 100644 --- a/pytket/tests/qasm_test.py +++ b/pytket/tests/qasm_test.py @@ -210,6 +210,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) 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) From a7b7d4cec784c95afa19ad6853fc08a87be24d37 Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Tue, 29 Aug 2023 09:58:26 +0100 Subject: [PATCH 06/34] bump --- pytket/conanfile.py | 2 +- tket/conanfile.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pytket/conanfile.py b/pytket/conanfile.py index 2ea0c10167..6505b08146 100644 --- a/pytket/conanfile.py +++ b/pytket/conanfile.py @@ -32,7 +32,7 @@ def package(self): cmake.install() def requirements(self): - self.requires("tket/1.2.36@tket/stable") + self.requires("tket/1.2.37@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") diff --git a/tket/conanfile.py b/tket/conanfile.py index a68024a074..1a304ebd92 100644 --- a/tket/conanfile.py +++ b/tket/conanfile.py @@ -23,7 +23,7 @@ class TketConan(ConanFile): name = "tket" - version = "1.2.36" + version = "1.2.37" package_type = "library" license = "Apache 2" homepage = "https://github.com/CQCL/tket" From a5e4a090253c2a84b42976b6b5b51776a1254e94 Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Tue, 29 Aug 2023 10:03:40 +0100 Subject: [PATCH 07/34] black format --- pytket/pytket/backends/backend.py | 2 -- pytket/pytket/circuit/decompose_classical.py | 2 +- pytket/tests/classical_test.py | 1 - pytket/tests/qasm_test.py | 2 +- 4 files changed, 2 insertions(+), 5 deletions(-) diff --git a/pytket/pytket/backends/backend.py b/pytket/pytket/backends/backend.py index cb76d6c9ce..cd4699cba2 100644 --- a/pytket/pytket/backends/backend.py +++ b/pytket/pytket/backends/backend.py @@ -107,7 +107,6 @@ def valid_circuit(self, circuit: Circuit) -> bool: def _check_all_circuits( self, circuits: Iterable[Circuit], nomeasure_warn: Optional[bool] = None ) -> bool: - if nomeasure_warn is None: nomeasure_warn = not ( self._supports_state @@ -265,7 +264,6 @@ def process_circuits( valid_check: bool = True, **kwargs: KwargTypes, ) -> List[ResultHandle]: - """ Submit circuits to the backend for running. The results will be stored in the backend's result cache to be retrieved by the corresponding diff --git a/pytket/pytket/circuit/decompose_classical.py b/pytket/pytket/circuit/decompose_classical.py index c38635254b..e0ce34dadd 100644 --- a/pytket/pytket/circuit/decompose_classical.py +++ b/pytket/pytket/circuit/decompose_classical.py @@ -337,7 +337,7 @@ def _decompose_expressions(circ: Circuit) -> Tuple[Circuit, bool]: modified = True continue if optype == OpType.Barrier: - # add_gate doesn't work for metaops + # add_gate doesn't work for metaops newcirc.add_barrier(args) else: newcirc.add_gate(op, args, **kwargs) diff --git a/pytket/tests/classical_test.py b/pytket/tests/classical_test.py index 95e7c162b7..988f9b0704 100644 --- a/pytket/tests/classical_test.py +++ b/pytket/tests/classical_test.py @@ -486,7 +486,6 @@ def qubit_register( index=strategies.integers(min_value=0, max_value=32), ) def test_registers(reg: Union[BitRegister, QubitRegister], index: int) -> None: - unit_type = Qubit if type(reg) is QubitRegister else Bit if index < reg.size: assert reg[index] == unit_type(reg.name, index) diff --git a/pytket/tests/qasm_test.py b/pytket/tests/qasm_test.py index 36b47fac34..ce11817d84 100644 --- a/pytket/tests/qasm_test.py +++ b/pytket/tests/qasm_test.py @@ -210,7 +210,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) + 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) From 847a4255c8f38e74c911339622faabb375a8fe79 Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Wed, 30 Aug 2023 08:10:06 +0100 Subject: [PATCH 08/34] Update test_Circ.cpp --- tket/test/src/Circuit/test_Circ.cpp | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/tket/test/src/Circuit/test_Circ.cpp b/tket/test/src/Circuit/test_Circ.cpp index 32cab51d2b..43d2b68f8f 100644 --- a/tket/test/src/Circuit/test_Circ.cpp +++ b/tket/test/src/Circuit/test_Circ.cpp @@ -3253,12 +3253,24 @@ SCENARIO("Check Circuit::add_conditional_barrier.") { "Add various forms of valid conditional barrier using the unsigned " "constructor.") { Circuit c(4, 5); - c.add_conditional_barrier({0}, {}, {0}, 0, ""); - c.add_conditional_barrier({0, 1}, {0}, {1, 2}, 1, ""); - c.add_conditional_barrier({0}, {0}, {1, 2}, 1, ""); - c.add_conditional_barrier({1, 3}, {0, 1, 2}, {3}, 0, "test"); - c.add_conditional_barrier({0, 2}, {0}, {1, 2}, 1, "test1"); - c.add_conditional_barrier({0, 1, 2, 3}, {0, 1, 2}, {3}, 0, "test1"); + c.add_conditional_barrier( + (std::vector){0}, (std::vector){}, + (std::vector){0}, 0, ""); + c.add_conditional_barrier( + (std::vector){0, 1}, (std::vector){0}, + (std::vector){1, 2}, 1, ""); + c.add_conditional_barrier( + (std::vector){0}, (std::vector){0}, + (std::vector){1, 2}, 1, ""); + c.add_conditional_barrier( + (std::vector){1, 3}, (std::vector){0, 1, 2}, + (std::vector){3}, 0, "test"); + c.add_conditional_barrier( + (std::vector){0, 2}, (std::vector){0}, + (std::vector){1, 2}, 1, "test1"); + c.add_conditional_barrier( + (std::vector){0, 1, 2, 3}, (std::vector){0, 1, 2}, + {3}, 0, "test1"); c.add_measure(3, 4); c.add_conditional_barrier({0, 1, 2, 3}, {0, 1, 2}, {4}, 0, "test2"); check_conditional_circuit(c); From e5a9e8a9d96bbb5be1c5787436d3907bbd21a6c4 Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Wed, 30 Aug 2023 08:12:51 +0100 Subject: [PATCH 09/34] Update add_op.cpp --- pytket/binders/circuit/Circuit/add_op.cpp | 83 +++++++++++------------ 1 file changed, 40 insertions(+), 43 deletions(-) diff --git a/pytket/binders/circuit/Circuit/add_op.cpp b/pytket/binders/circuit/Circuit/add_op.cpp index 33c7612857..6b9345e37c 100644 --- a/pytket/binders/circuit/Circuit/add_op.cpp +++ b/pytket/binders/circuit/Circuit/add_op.cpp @@ -178,29 +178,27 @@ void init_circuit_add_op(py::class_> &c) { py::arg("qubits"), py::arg("bits") = no_bits, py::arg("data") = "") .def( "_add_conditional_barrier", - []( - (Circuit *circ, const std::vector &barrier_qubits, - const std::vector &barrier_bits, - const std::vector &condition_bits, unsigned value, - const std::string &data) { - circ->add_conditional_barrier( - barrier_qubits, barrier_bits, condition_bits, value, data); - return circ; - }, - "Append a Conditional Barrier on the given barrier qubits and " - "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 " - "of barrier operation." - "\n:param value: Value that classical condition must have to " - "hold." - "\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") = "")) + [](Circuit *circ, const std::vector &barrier_qubits, + const std::vector &barrier_bits, + const std::vector &condition_bits, unsigned value, + const std::string &data) { + circ->add_conditional_barrier( + barrier_qubits, barrier_bits, condition_bits, value, data); + return circ; + }, + "Append a Conditional Barrier on the given barrier qubits and " + "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 " + "of barrier operation." + "\n:param value: Value that classical condition must have to " + "hold." + "\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") = "") .def( "add_circbox", [](Circuit *circ, const CircBox &box, @@ -446,26 +444,25 @@ void init_circuit_add_op(py::class_> &c) { .def( "_add_conditional_barrier", - []( - (Circuit *circ, const unit_vector_t &barrier_args, - const unit_vector_t &condition_bits, unsigned value, - const std::string &_data) { - circ->add_conditional_barrier( - barrier_args, condition_bits, value, data); - return circ; - }, - "Append a Conditional Barrier on the given barrier qubits and " - "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." - "\n:param value: Value that classical condition must have to " - "hold." - "\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") = "")) + [](Circuit *circ, const unit_vector_t &barrier_args, + const unit_vector_t &condition_bits, unsigned value, + const std::string &_data) { + circ->add_conditional_barrier( + barrier_args, condition_bits, value, data); + return circ; + }, + "Append a Conditional Barrier on the given barrier qubits and " + "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." + "\n:param value: Value that classical condition must have to " + "hold." + "\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") = "") .def( "add_circbox", [](Circuit *circ, const CircBox &box, const unit_vector_t &args, From bc570fc1e1bfa7749afd05468d467673064b2804 Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Wed, 30 Aug 2023 08:14:37 +0100 Subject: [PATCH 10/34] bump --- pytket/conanfile.py | 2 +- tket/conanfile.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pytket/conanfile.py b/pytket/conanfile.py index 6505b08146..cf3933f698 100644 --- a/pytket/conanfile.py +++ b/pytket/conanfile.py @@ -32,7 +32,7 @@ def package(self): cmake.install() def requirements(self): - self.requires("tket/1.2.37@tket/stable") + self.requires("tket/1.2.38@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") diff --git a/tket/conanfile.py b/tket/conanfile.py index 1a304ebd92..ad73ac168f 100644 --- a/tket/conanfile.py +++ b/tket/conanfile.py @@ -23,7 +23,7 @@ class TketConan(ConanFile): name = "tket" - version = "1.2.37" + version = "1.2.38" package_type = "library" license = "Apache 2" homepage = "https://github.com/CQCL/tket" From 431ddbfbcabbb559e3b75ae5910784ef5b834380 Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Wed, 30 Aug 2023 08:45:57 +0100 Subject: [PATCH 11/34] Update add_op.cpp --- pytket/binders/circuit/Circuit/add_op.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pytket/binders/circuit/Circuit/add_op.cpp b/pytket/binders/circuit/Circuit/add_op.cpp index 01aa013912..16d86ac6ec 100644 --- a/pytket/binders/circuit/Circuit/add_op.cpp +++ b/pytket/binders/circuit/Circuit/add_op.cpp @@ -182,9 +182,9 @@ void init_circuit_add_op(py::class_> &c) { [](Circuit *circ, const std::vector &barrier_qubits, const std::vector &barrier_bits, const std::vector &condition_bits, unsigned value, - const std::string &data) { + const std::string &_data) { circ->add_conditional_barrier( - barrier_qubits, barrier_bits, condition_bits, value, data); + barrier_qubits, barrier_bits, condition_bits, value, _data); return circ; }, "Append a Conditional Barrier on the given barrier qubits and " @@ -449,7 +449,7 @@ void init_circuit_add_op(py::class_> &c) { const unit_vector_t &condition_bits, unsigned value, const std::string &_data) { circ->add_conditional_barrier( - barrier_args, condition_bits, value, data); + barrier_args, condition_bits, value, _data); return circ; }, "Append a Conditional Barrier on the given barrier qubits and " From 175d69b1db2189957e68a79b1467696740ba3cb2 Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Thu, 31 Aug 2023 11:30:04 +0100 Subject: [PATCH 12/34] Expose BarrierOp to python --- pytket/binders/circuit/main.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pytket/binders/circuit/main.cpp b/pytket/binders/circuit/main.cpp index a77f894767..d6a491ef47 100644 --- a/pytket/binders/circuit/main.cpp +++ b/pytket/binders/circuit/main.cpp @@ -24,6 +24,7 @@ #include "tket/Gate/Gate.hpp" #include "tket/Gate/OpPtrFunctions.hpp" #include "tket/Gate/SymTable.hpp" +#include "tket/Ops/BarrierOp.hpp" #include "tket/Ops/ClassicalOps.hpp" #include "tket/Ops/MetaOp.hpp" #include "tket/Ops/Op.hpp" @@ -612,6 +613,16 @@ PYBIND11_MODULE(circuit, m) { py::arg("type"), py::arg("signature"), py::arg("data")) .def_property_readonly("data", &MetaOp::get_data, "Get data from MetaOp"); + py::class_, Op>( + m, "BarrierOp", "Barrier operations.") + .def( + py::init(), + "Construct BarrierOp with signature and additional data string" + "\n:param signature: signature for the op" + "\n:param data: additional string stored in the op", + py::arg("signature"), py::arg("data")) + .def_property_readonly("data", &BarrierOp::get_data, "Get data from BarrierOp"); + init_library(m); init_boxes(m); init_classical(m); From 65994f2c1d88691fee1e17c920f96f8abb27ee8e Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Thu, 31 Aug 2023 11:30:38 +0100 Subject: [PATCH 13/34] Make `barr` signature accurately reflect internal UnitID, add test --- pytket/pytket/qasm/qasm.py | 11 +++++++++-- pytket/tests/qasm_test.py | 17 +++++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/pytket/pytket/qasm/qasm.py b/pytket/pytket/qasm/qasm.py index 4af96cbd07..70e5c310fe 100644 --- a/pytket/pytket/qasm/qasm.py +++ b/pytket/pytket/qasm/qasm.py @@ -350,9 +350,17 @@ def meas(self, tree: List[Token]) -> Iterable[CommandDict]: def barr(self, tree: List[Arg]) -> Iterable[CommandDict]: args = [q for qs in self.unroll_all_args(tree[0]) for q in qs] + signature: List[str] = [] + for arg in args: + if arg[0] in self.c_registers: + signature.append("C") + elif arg[0] in self.q_registers: + signature.append("Q") + else: + raise QASMParseError("UnitID", arg, "in Barrier arguments is not declared.") yield { "args": args, - "op": {"signature": ["Q"] * len(args), "type": "Barrier"}, + "op": {"signature": signature, "type": "Barrier"}, } def reset(self, tree: List[Token]) -> Iterable[CommandDict]: @@ -367,7 +375,6 @@ def mixedcall(self, tree: List) -> Iterator[CommandDict]: optoken = next(child_iter) opstr = optoken.value - next_tree = next(child_iter) try: args = next(child_iter) diff --git a/pytket/tests/qasm_test.py b/pytket/tests/qasm_test.py index ce11817d84..6723c032ef 100644 --- a/pytket/tests/qasm_test.py +++ b/pytket/tests/qasm_test.py @@ -210,13 +210,26 @@ 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) + circ._add_conditional_barrier([0, 1], [], [0, 1], 1, data="cond_barrier") 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) c2 = circuit_from_qasm(qasm_out) assert circ == c2 +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( + [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)) + def test_hqs_conditional() -> None: c = Circuit(1) @@ -268,7 +281,6 @@ def test_barrier() -> None: c.H(0) c.H(2) c.add_barrier([0], [0], "comment") - result = """OPENQASM 2.0;\ninclude "hqslib1_dev.inc";\n\nqreg q[3]; creg c[3];\nh q[0];\nh q[2];\ncomment q[0],c[0];\n""" assert result == circuit_to_qasm_str(c, header="hqslib1_dev") @@ -767,6 +779,7 @@ def test_rxxyyzz_conversion() -> None: test_extended_qasm() test_register_commands() test_conditional_gates() + test_named_conditional_barrier() test_hqs_conditional() test_hqs_conditional_params() test_barrier() From fe39c11ff490bb99cb29bd8867b093cd0cc93f7b Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Thu, 31 Aug 2023 11:31:07 +0100 Subject: [PATCH 14/34] reformat tests --- pytket/pytket/qasm/qasm.py | 4 +++- pytket/tests/qasm_test.py | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/pytket/pytket/qasm/qasm.py b/pytket/pytket/qasm/qasm.py index 70e5c310fe..f5ea6e40b5 100644 --- a/pytket/pytket/qasm/qasm.py +++ b/pytket/pytket/qasm/qasm.py @@ -357,7 +357,9 @@ def barr(self, tree: List[Arg]) -> Iterable[CommandDict]: elif arg[0] in self.q_registers: signature.append("Q") else: - raise QASMParseError("UnitID", arg, "in Barrier arguments is not declared.") + raise QASMParseError( + "UnitID", arg, "in Barrier arguments is not declared." + ) yield { "args": args, "op": {"signature": signature, "type": "Barrier"}, diff --git a/pytket/tests/qasm_test.py b/pytket/tests/qasm_test.py index 6723c032ef..a892805146 100644 --- a/pytket/tests/qasm_test.py +++ b/pytket/tests/qasm_test.py @@ -217,8 +217,9 @@ def test_conditional_gates() -> None: c2 = circuit_from_qasm(qasm_out) assert circ == c2 + def test_named_conditional_barrier() -> None: - circ = Circuit(2,2) + circ = Circuit(2, 2) circ.add_bit(Bit("test", 3)) circ.Z(0, condition_bits=[0, 1], condition_value=2) circ._add_conditional_barrier( From 5f86354f62a78c231d3c0ac80184aab9f1aa1911 Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Thu, 31 Aug 2023 11:38:20 +0100 Subject: [PATCH 15/34] Update main.cpp --- pytket/binders/circuit/main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/pytket/binders/circuit/main.cpp b/pytket/binders/circuit/main.cpp index cb2b215937..48936c8435 100644 --- a/pytket/binders/circuit/main.cpp +++ b/pytket/binders/circuit/main.cpp @@ -637,7 +637,6 @@ PYBIND11_MODULE(circuit, m) { .def_property_readonly( "data", &BarrierOp::get_data, "Get data from BarrierOp"); - init_library(m); auto pyCircuit = py::class_>( m, "Circuit", py::dynamic_attr(), "Encapsulates a quantum circuit using a DAG representation.\n\n>>> " From 0ae0af92fdaa9fbe1844f6877e8d8b67bf2e3525 Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Thu, 31 Aug 2023 12:16:41 +0100 Subject: [PATCH 16/34] Update qasm.py --- pytket/pytket/qasm/qasm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pytket/pytket/qasm/qasm.py b/pytket/pytket/qasm/qasm.py index affec80e2b..be33953c47 100644 --- a/pytket/pytket/qasm/qasm.py +++ b/pytket/pytket/qasm/qasm.py @@ -54,7 +54,7 @@ MultiBitOp, WASMOp, CustomGate, - MetaOp, + BarrierOp, ) from pytket._tket.unit_id import _TEMP_BIT_NAME from pytket.circuit import ( @@ -1330,7 +1330,7 @@ def circuit_to_qasm_io( param = -2 + param params = [param] # type: ignore elif optype == OpType.Barrier and header == "hqslib1_dev": - assert isinstance(op, MetaOp) + assert isinstance(op, BarrierOp) if op.data == "": opstr = _tk_to_qasm_noparams[optype] else: From 9c1119fc5f725fa0f8013d14dc04885b3cd501f1 Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Thu, 31 Aug 2023 14:15:17 +0100 Subject: [PATCH 17/34] Update circuit.pyi --- pytket/pytket/_tket/circuit.pyi | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pytket/pytket/_tket/circuit.pyi b/pytket/pytket/_tket/circuit.pyi index b251e48130..149e89c989 100644 --- a/pytket/pytket/_tket/circuit.pyi +++ b/pytket/pytket/_tket/circuit.pyi @@ -8,6 +8,11 @@ import pytket._tket.pauli import pytket._tket.unit_id import sympy +class BarrierOp(Op): + def __init__(self, signature: List[EdgeType], data: str) -> None: ... + @property + def data(self) -> str: ... + class BasisOrder: __members__: ClassVar[dict] = ... # read-only __entries: ClassVar[dict] = ... @@ -263,6 +268,10 @@ 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: ... From 7e2349ac90e6e4f8e9444e5201997221ee1a8d89 Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Thu, 31 Aug 2023 15:02:11 +0100 Subject: [PATCH 18/34] Update test_Circ.cpp --- tket/test/src/Circuit/test_Circ.cpp | 37 ++++++++++++++--------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/tket/test/src/Circuit/test_Circ.cpp b/tket/test/src/Circuit/test_Circ.cpp index 43d2b68f8f..21596a340c 100644 --- a/tket/test/src/Circuit/test_Circ.cpp +++ b/tket/test/src/Circuit/test_Circ.cpp @@ -3253,26 +3253,25 @@ SCENARIO("Check Circuit::add_conditional_barrier.") { "Add various forms of valid conditional barrier using the unsigned " "constructor.") { Circuit c(4, 5); - c.add_conditional_barrier( - (std::vector){0}, (std::vector){}, - (std::vector){0}, 0, ""); - c.add_conditional_barrier( - (std::vector){0, 1}, (std::vector){0}, - (std::vector){1, 2}, 1, ""); - c.add_conditional_barrier( - (std::vector){0}, (std::vector){0}, - (std::vector){1, 2}, 1, ""); - c.add_conditional_barrier( - (std::vector){1, 3}, (std::vector){0, 1, 2}, - (std::vector){3}, 0, "test"); - c.add_conditional_barrier( - (std::vector){0, 2}, (std::vector){0}, - (std::vector){1, 2}, 1, "test1"); - c.add_conditional_barrier( - (std::vector){0, 1, 2, 3}, (std::vector){0, 1, 2}, - {3}, 0, "test1"); + std::vector c_empty = {}; + std::vector c_0 = {0}; + std::vector c_3 = {3}; + std::vector c_4 = {4}; + std::vector c_01 = {0, 1}; + std::vector c_02 = {0, 2}; + std::vector c_12 = {1, 2}; + std::vector c_13 = {1, 3}; + std::vector c_012 = {0, 1, 2}; + std::vector c_0123 = {0, 1, 2, 3}; + + c.add_conditional_barrier(c_0, c_empty, c_0, 0, ""); + c.add_conditional_barrier(c_01, c_0, c_12, 1, ""); + c.add_conditional_barrier(c_0, c_0, c_12, 1, ""); + c.add_conditional_barrier(c_13, c_012, c_3, 0, "test"); + c.add_conditional_barrier(c_02, c_0, c_12, 1, "test1"); + c.add_conditional_barrier(c_0123, c_012, c_3, 0, "test1"); c.add_measure(3, 4); - c.add_conditional_barrier({0, 1, 2, 3}, {0, 1, 2}, {4}, 0, "test2"); + c.add_conditional_barrier(c_0123, c_012, c_4, 0, "test2"); check_conditional_circuit(c); } GIVEN( From d792bf62ed8ca76f171444d46e4bc33e18914421 Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Mon, 4 Sep 2023 12:32:39 +0100 Subject: [PATCH 19/34] requested changes from review --- pytket/binders/circuit/Circuit/add_op.cpp | 10 +++++----- pytket/pytket/_tket/circuit.pyi | 4 ++-- pytket/pytket/qasm/qasm.py | 2 +- pytket/tests/qasm_test.py | 10 +++++++--- tket/include/tket/Circuit/Circuit.hpp | 4 ++-- tket/include/tket/Ops/BarrierOp.hpp | 3 +-- tket/src/Circuit/basic_circ_manip.cpp | 3 ++- tket/src/Ops/BarrierOp.cpp | 19 +++++-------------- tket/test/src/test_json.cpp | 1 + 9 files changed, 26 insertions(+), 30 deletions(-) diff --git a/pytket/binders/circuit/Circuit/add_op.cpp b/pytket/binders/circuit/Circuit/add_op.cpp index a8c416f384..79d259415e 100644 --- a/pytket/binders/circuit/Circuit/add_op.cpp +++ b/pytket/binders/circuit/Circuit/add_op.cpp @@ -174,7 +174,7 @@ void init_circuit_add_op(py::class_> &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 &barrier_qubits, const std::vector &barrier_bits, const std::vector &condition_bits, unsigned value, @@ -191,7 +191,7 @@ void init_circuit_add_op(py::class_> &c) { "condition " "of barrier operation." "\n:param value: Value that classical condition must have to " - "hold." + "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"), @@ -440,9 +440,9 @@ void init_circuit_add_op(py::class_> &c) { 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); @@ -455,7 +455,7 @@ void init_circuit_add_op(py::class_> &c) { "condition " "of barrier operation." "\n:param value: Value that classical condition must have to " - "hold." + "hold (little-endian)." "\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"), diff --git a/pytket/pytket/_tket/circuit.pyi b/pytket/pytket/_tket/circuit.pyi index 149e89c989..d69727f41c 100644 --- a/pytket/pytket/_tket/circuit.pyi +++ b/pytket/pytket/_tket/circuit.pyi @@ -269,9 +269,9 @@ class 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: ... + 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_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: ... diff --git a/pytket/pytket/qasm/qasm.py b/pytket/pytket/qasm/qasm.py index be33953c47..b1540caa24 100644 --- a/pytket/pytket/qasm/qasm.py +++ b/pytket/pytket/qasm/qasm.py @@ -370,7 +370,7 @@ def barr(self, tree: List[Arg]) -> Iterable[CommandDict]: signature.append("Q") else: raise QASMParseError( - "UnitID", arg, "in Barrier arguments is not declared." + "UnitID " + arg + " in Barrier arguments is not declared." ) yield { "args": args, diff --git a/pytket/tests/qasm_test.py b/pytket/tests/qasm_test.py index 0148c1abf6..651981e056 100644 --- a/pytket/tests/qasm_test.py +++ b/pytket/tests/qasm_test.py @@ -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, data="cond_barrier") 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) @@ -228,14 +228,18 @@ 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) + print(c_from_qs.get_commands()[1].op.op.data) + for i, x in enumerate(c_from_qs.get_commands()): + print(i,x) + assert qs_str == circuit_to_qasm_str(c_from_qs) def test_hqs_conditional() -> None: diff --git a/tket/include/tket/Circuit/Circuit.hpp b/tket/include/tket/Circuit/Circuit.hpp index a309d69feb..f8f246eb4f 100644 --- a/tket/include/tket/Circuit/Circuit.hpp +++ b/tket/include/tket/Circuit/Circuit.hpp @@ -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( @@ -931,7 +931,7 @@ class Circuit { std::optional 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 opgroup = std::nullopt); diff --git a/tket/include/tket/Ops/BarrierOp.hpp b/tket/include/tket/Ops/BarrierOp.hpp index f889b3a265..bae0747dfb 100644 --- a/tket/include/tket/Ops/BarrierOp.hpp +++ b/tket/include/tket/Ops/BarrierOp.hpp @@ -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 */ diff --git a/tket/src/Circuit/basic_circ_manip.cpp b/tket/src/Circuit/basic_circ_manip.cpp index eb0daa880b..36c665dab2 100644 --- a/tket/src/Circuit/basic_circ_manip.cpp +++ b/tket/src/Circuit/basic_circ_manip.cpp @@ -161,7 +161,7 @@ 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 opgroup) { op_signature_t sig; @@ -169,6 +169,7 @@ Vertex Circuit::add_conditional_barrier( if (arg.type() == UnitType::Qubit) { sig.push_back(EdgeType::Quantum); } else { + TKET_ASSERT(arg.type() == UnitType::Bit); sig.push_back(EdgeType::Classical); } } diff --git a/tket/src/Ops/BarrierOp.cpp b/tket/src/Ops/BarrierOp.cpp index f8011362e3..db0a11e4dc 100644 --- a/tket/src/Ops/BarrierOp.cpp +++ b/tket/src/Ops/BarrierOp.cpp @@ -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 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; @@ -73,7 +62,9 @@ BarrierOp::~BarrierOp() {} bool BarrierOp::is_equal(const Op& op_other) const { const BarrierOp& other = dynamic_cast(op_other); - return (get_signature() == other.get_signature()); + return ( + get_signature() == other.get_signature() && + get_data() == other.get_data()); } } // namespace tket diff --git a/tket/test/src/test_json.cpp b/tket/test/src/test_json.cpp index e14f85b5bf..62fd76052e 100644 --- a/tket/test/src/test_json.cpp +++ b/tket/test/src/test_json.cpp @@ -227,6 +227,7 @@ SCENARIO("Test Circuit serialization") { c.add_conditional_gate(OpType::CX, {}, {0, 1}, {0, 1}, 1); c.add_conditional_gate(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(); From 66f826f7a074bd00b45492b445c87220831ce388 Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Mon, 4 Sep 2023 12:46:17 +0100 Subject: [PATCH 20/34] fix types --- pytket/tests/qasm_test.py | 4 ++-- tket/src/Circuit/basic_circ_manip.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pytket/tests/qasm_test.py b/pytket/tests/qasm_test.py index 651981e056..582b7ce185 100644 --- a/pytket/tests/qasm_test.py +++ b/pytket/tests/qasm_test.py @@ -235,10 +235,10 @@ def test_named_conditional_barrier() -> None: data="cond_barrier", ) qs_str: str = circuit_to_qasm_str(circ) - c_from_qs: Circuit = circuit_from_qasm_str(qs_str) + c_from_qs: Circuit = circuit_from_qasm_str(qs_str) print(c_from_qs.get_commands()[1].op.op.data) for i, x in enumerate(c_from_qs.get_commands()): - print(i,x) + print(i, x) assert qs_str == circuit_to_qasm_str(c_from_qs) diff --git a/tket/src/Circuit/basic_circ_manip.cpp b/tket/src/Circuit/basic_circ_manip.cpp index 36c665dab2..80a79b4a52 100644 --- a/tket/src/Circuit/basic_circ_manip.cpp +++ b/tket/src/Circuit/basic_circ_manip.cpp @@ -173,7 +173,7 @@ Vertex Circuit::add_conditional_barrier( sig.push_back(EdgeType::Classical); } } - unit_vector_t args = condition_bits; + bit_vector_t args = condition_bits; args.insert(args.end(), barrier_args.begin(), barrier_args.end()); return add_op( std::make_shared( From 3c03668cc91c1fb7bcb304c5d5542b1804d64093 Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Mon, 4 Sep 2023 15:04:27 +0100 Subject: [PATCH 21/34] Update basic_circ_manip.cpp --- tket/src/Circuit/basic_circ_manip.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tket/src/Circuit/basic_circ_manip.cpp b/tket/src/Circuit/basic_circ_manip.cpp index 80a79b4a52..36c665dab2 100644 --- a/tket/src/Circuit/basic_circ_manip.cpp +++ b/tket/src/Circuit/basic_circ_manip.cpp @@ -173,7 +173,7 @@ Vertex Circuit::add_conditional_barrier( sig.push_back(EdgeType::Classical); } } - bit_vector_t args = condition_bits; + unit_vector_t args = condition_bits; args.insert(args.end(), barrier_args.begin(), barrier_args.end()); return add_op( std::make_shared( From 3a06eaaea8fd55dc8e9a5bf2504a34ba690033f7 Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Mon, 4 Sep 2023 15:22:35 +0100 Subject: [PATCH 22/34] Update basic_circ_manip.cpp --- tket/src/Circuit/basic_circ_manip.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tket/src/Circuit/basic_circ_manip.cpp b/tket/src/Circuit/basic_circ_manip.cpp index 36c665dab2..029452e026 100644 --- a/tket/src/Circuit/basic_circ_manip.cpp +++ b/tket/src/Circuit/basic_circ_manip.cpp @@ -173,7 +173,8 @@ Vertex Circuit::add_conditional_barrier( sig.push_back(EdgeType::Classical); } } - 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( From 04c0c9f85bd6a2c8664c8c02af82667a734b1091 Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Mon, 4 Sep 2023 15:43:07 +0100 Subject: [PATCH 23/34] Update qasm_test.py --- pytket/tests/qasm_test.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/pytket/tests/qasm_test.py b/pytket/tests/qasm_test.py index 582b7ce185..78feeb03eb 100644 --- a/pytket/tests/qasm_test.py +++ b/pytket/tests/qasm_test.py @@ -236,9 +236,6 @@ def test_named_conditional_barrier() -> None: ) qs_str: str = circuit_to_qasm_str(circ) c_from_qs: Circuit = circuit_from_qasm_str(qs_str) - print(c_from_qs.get_commands()[1].op.op.data) - for i, x in enumerate(c_from_qs.get_commands()): - print(i, x) assert qs_str == circuit_to_qasm_str(c_from_qs) From c1f182867f76155e0d0ef629164e309609e92729 Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Mon, 4 Sep 2023 16:01:30 +0100 Subject: [PATCH 24/34] Update qasm_test.py --- pytket/tests/qasm_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytket/tests/qasm_test.py b/pytket/tests/qasm_test.py index 78feeb03eb..1d92d84334 100644 --- a/pytket/tests/qasm_test.py +++ b/pytket/tests/qasm_test.py @@ -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) From 1b94d6f4199a24e92e2bc3e3997b853a1946d23a Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Mon, 4 Sep 2023 16:59:16 +0100 Subject: [PATCH 25/34] Update circuit.pyi --- pytket/pytket/_tket/circuit.pyi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pytket/pytket/_tket/circuit.pyi b/pytket/pytket/_tket/circuit.pyi index f586bd53a8..99237764ac 100644 --- a/pytket/pytket/_tket/circuit.pyi +++ b/pytket/pytket/_tket/circuit.pyi @@ -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: ... @@ -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: ... From ed13e99b1c233141987ed8123e3ac8bcc264ed63 Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Tue, 5 Sep 2023 11:22:21 +0100 Subject: [PATCH 26/34] Add symbolic substituion test for barrier op --- tket/test/src/Circuit/test_Circ.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tket/test/src/Circuit/test_Circ.cpp b/tket/test/src/Circuit/test_Circ.cpp index 21596a340c..42430d4f24 100644 --- a/tket/test/src/Circuit/test_Circ.cpp +++ b/tket/test/src/Circuit/test_Circ.cpp @@ -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(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") { From a6a491b6801c593757a3d40cdeba0707b515cf66 Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Tue, 5 Sep 2023 11:22:37 +0100 Subject: [PATCH 27/34] Update serialization/deserialization for MetaOp/BarrierOp --- tket/include/tket/Ops/MetaOp.hpp | 11 ----------- tket/src/Circuit/OpJson.cpp | 4 +--- tket/src/Ops/BarrierOp.cpp | 7 +------ tket/src/Ops/MetaOp.cpp | 34 -------------------------------- 4 files changed, 2 insertions(+), 54 deletions(-) diff --git a/tket/include/tket/Ops/MetaOp.hpp b/tket/include/tket/Ops/MetaOp.hpp index e3b6cf45d6..64b5616889 100644 --- a/tket/include/tket/Ops/MetaOp.hpp +++ b/tket/include/tket/Ops/MetaOp.hpp @@ -30,8 +30,6 @@ class MetaOp : public Op { SymSet free_symbols() const override; - unsigned n_qubits() const override; - op_signature_t get_signature() const override; std::string get_data() const { return data_; } @@ -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 */ diff --git a/tket/src/Circuit/OpJson.cpp b/tket/src/Circuit/OpJson.cpp index 9aba5c5ab2..46e47f42b2 100644 --- a/tket/src/Circuit/OpJson.cpp +++ b/tket/src/Circuit/OpJson.cpp @@ -27,9 +27,7 @@ namespace tket { void from_json(const nlohmann::json& j, Op_ptr& op) { OpType optype = j.at("type").get(); - 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); diff --git a/tket/src/Ops/BarrierOp.cpp b/tket/src/Ops/BarrierOp.cpp index db0a11e4dc..b6817455c5 100644 --- a/tket/src/Ops/BarrierOp.cpp +++ b/tket/src/Ops/BarrierOp.cpp @@ -47,12 +47,7 @@ nlohmann::json BarrierOp::serialize() const { Op_ptr BarrierOp::deserialize(const nlohmann::json& j) { op_signature_t sig = j.at("signature").get(); - std::string data; - try { - data = j.at("data").get(); - } catch (const nlohmann::json::out_of_range& e) { - data = ""; - } + std::string data = j.at("data").get(); return std::make_shared(sig, data); } diff --git a/tket/src/Ops/MetaOp.cpp b/tket/src/Ops/MetaOp.cpp index e2013e4ee8..2ab18d04ca 100644 --- a/tket/src/Ops/MetaOp.cpp +++ b/tket/src/Ops/MetaOp.cpp @@ -33,15 +33,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 sig = desc_.signature(); if (sig) @@ -50,33 +41,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(); - op_signature_t sig = j.at("signature").get(); - std::string data; - try { - data = j.at("data").get(); - } catch (const nlohmann::json::out_of_range& e) { - data = ""; - } - return std::make_shared(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(op_other); - return (get_signature() == other.get_signature()); -} - } // namespace tket From 312b7f1b4ba9d79a66459221ffa53db9da1cdee9 Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Tue, 5 Sep 2023 11:34:01 +0100 Subject: [PATCH 28/34] add MetaOp::is_equal --- tket/include/tket/Ops/MetaOp.hpp | 4 ++++ tket/src/Ops/MetaOp.cpp | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/tket/include/tket/Ops/MetaOp.hpp b/tket/include/tket/Ops/MetaOp.hpp index 64b5616889..7b49bb3570 100644 --- a/tket/include/tket/Ops/MetaOp.hpp +++ b/tket/include/tket/Ops/MetaOp.hpp @@ -37,6 +37,10 @@ class MetaOp : public Op { bool is_clifford() const override; ~MetaOp() override; + /** + * Equality check between two MetaOp instances + */ + bool is_equal(const Op &other) const override; private: op_signature_t diff --git a/tket/src/Ops/MetaOp.cpp b/tket/src/Ops/MetaOp.cpp index 2ab18d04ca..255568d1e8 100644 --- a/tket/src/Ops/MetaOp.cpp +++ b/tket/src/Ops/MetaOp.cpp @@ -45,4 +45,9 @@ bool MetaOp::is_clifford() const { return true; } MetaOp::~MetaOp() {} +bool MetaOp::is_equal(const Op& op_other) const { + const MetaOp& other = dynamic_cast(op_other); + return (get_signature() == other.get_signature()); +} + } // namespace tket From c3bfbdd3dd6a5869d86613b4a424c89b2d1bd271 Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Tue, 5 Sep 2023 11:58:43 +0100 Subject: [PATCH 29/34] Add back data type --- tket/include/tket/Ops/MetaOp.hpp | 4 ---- tket/src/Ops/BarrierOp.cpp | 7 ++++++- tket/src/Ops/MetaOp.cpp | 5 ----- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/tket/include/tket/Ops/MetaOp.hpp b/tket/include/tket/Ops/MetaOp.hpp index 7b49bb3570..64b5616889 100644 --- a/tket/include/tket/Ops/MetaOp.hpp +++ b/tket/include/tket/Ops/MetaOp.hpp @@ -37,10 +37,6 @@ class MetaOp : public Op { bool is_clifford() const override; ~MetaOp() override; - /** - * Equality check between two MetaOp instances - */ - bool is_equal(const Op &other) const override; private: op_signature_t diff --git a/tket/src/Ops/BarrierOp.cpp b/tket/src/Ops/BarrierOp.cpp index b6817455c5..db0a11e4dc 100644 --- a/tket/src/Ops/BarrierOp.cpp +++ b/tket/src/Ops/BarrierOp.cpp @@ -47,7 +47,12 @@ nlohmann::json BarrierOp::serialize() const { Op_ptr BarrierOp::deserialize(const nlohmann::json& j) { op_signature_t sig = j.at("signature").get(); - std::string data = j.at("data").get(); + std::string data; + try { + data = j.at("data").get(); + } catch (const nlohmann::json::out_of_range& e) { + data = ""; + } return std::make_shared(sig, data); } diff --git a/tket/src/Ops/MetaOp.cpp b/tket/src/Ops/MetaOp.cpp index 255568d1e8..2ab18d04ca 100644 --- a/tket/src/Ops/MetaOp.cpp +++ b/tket/src/Ops/MetaOp.cpp @@ -45,9 +45,4 @@ bool MetaOp::is_clifford() const { return true; } MetaOp::~MetaOp() {} -bool MetaOp::is_equal(const Op& op_other) const { - const MetaOp& other = dynamic_cast(op_other); - return (get_signature() == other.get_signature()); -} - } // namespace tket From 011b7e7394e5b7a4b9e0ae629498881bb77e4815 Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Tue, 5 Sep 2023 15:10:49 +0100 Subject: [PATCH 30/34] Update add_op.cpp --- pytket/binders/circuit/Circuit/add_op.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/pytket/binders/circuit/Circuit/add_op.cpp b/pytket/binders/circuit/Circuit/add_op.cpp index 79d259415e..3e1aa31a34 100644 --- a/pytket/binders/circuit/Circuit/add_op.cpp +++ b/pytket/binders/circuit/Circuit/add_op.cpp @@ -187,12 +187,11 @@ void init_circuit_add_op(py::class_> &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 (little-endian)." - "\n: param data: Additional data stored in Barrier operation." + "\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") = "") @@ -438,7 +437,6 @@ void init_circuit_add_op(py::class_> &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", [](Circuit *circ, const unit_vector_t &barrier_args, @@ -452,11 +450,10 @@ void init_circuit_add_op(py::class_> &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 (little-endian)." - "\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_args"), py::arg("condition_bits"), py::arg("value"), py::arg("data") = "") From 7fcfefa7f6bb84840915eb6d9e294c02fa083fb7 Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Tue, 5 Sep 2023 17:32:07 +0100 Subject: [PATCH 31/34] bump --- pytket/conanfile.py | 2 +- tket/conanfile.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pytket/conanfile.py b/pytket/conanfile.py index cf3933f698..9eccfb041d 100644 --- a/pytket/conanfile.py +++ b/pytket/conanfile.py @@ -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.39@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") diff --git a/tket/conanfile.py b/tket/conanfile.py index ad73ac168f..dd7fbc1ad0 100644 --- a/tket/conanfile.py +++ b/tket/conanfile.py @@ -23,7 +23,7 @@ class TketConan(ConanFile): name = "tket" - version = "1.2.38" + version = "1.2.39" package_type = "library" license = "Apache 2" homepage = "https://github.com/CQCL/tket" From 14563592fcc2bf571443859f3d48abac14275aeb Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Tue, 5 Sep 2023 18:19:11 +0100 Subject: [PATCH 32/34] bump --- pytket/conanfile.py | 2 +- tket/conanfile.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pytket/conanfile.py b/pytket/conanfile.py index cf3933f698..9eccfb041d 100644 --- a/pytket/conanfile.py +++ b/pytket/conanfile.py @@ -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.39@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") diff --git a/tket/conanfile.py b/tket/conanfile.py index ad73ac168f..dd7fbc1ad0 100644 --- a/tket/conanfile.py +++ b/tket/conanfile.py @@ -23,7 +23,7 @@ class TketConan(ConanFile): name = "tket" - version = "1.2.38" + version = "1.2.39" package_type = "library" license = "Apache 2" homepage = "https://github.com/CQCL/tket" From 6deb21d5f91df7029eaafd9460dd6b5b8b222a42 Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Wed, 6 Sep 2023 09:55:38 +0100 Subject: [PATCH 33/34] bump --- pytket/conanfile.py | 2 +- tket/conanfile.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pytket/conanfile.py b/pytket/conanfile.py index 9eccfb041d..22fe5446e0 100644 --- a/pytket/conanfile.py +++ b/pytket/conanfile.py @@ -32,7 +32,7 @@ def package(self): cmake.install() def requirements(self): - self.requires("tket/1.2.39@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") diff --git a/tket/conanfile.py b/tket/conanfile.py index dd7fbc1ad0..97f9578eb3 100644 --- a/tket/conanfile.py +++ b/tket/conanfile.py @@ -23,7 +23,7 @@ class TketConan(ConanFile): name = "tket" - version = "1.2.39" + version = "1.2.40" package_type = "library" license = "Apache 2" homepage = "https://github.com/CQCL/tket" From ef91614954913b181a30ce8a1210ba484bc95e40 Mon Sep 17 00:00:00 2001 From: sjdilkes Date: Wed, 6 Sep 2023 11:15:25 +0100 Subject: [PATCH 34/34] update with requested changes --- pytket/binders/circuit/Circuit/add_op.cpp | 2 +- pytket/docs/changelog.rst | 4 ++++ pytket/pytket/qasm/qasm.py | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/pytket/binders/circuit/Circuit/add_op.cpp b/pytket/binders/circuit/Circuit/add_op.cpp index 3e1aa31a34..e19fa42e69 100644 --- a/pytket/binders/circuit/Circuit/add_op.cpp +++ b/pytket/binders/circuit/Circuit/add_op.cpp @@ -452,7 +452,7 @@ void init_circuit_add_op(py::class_> &c) { "\n:param condition_bits: Bit covering classical control " " condition of barrier operation." "\n:param value: Value that classical condition must have to " - " hold (little-endian)." + "hold (little-endian)." "\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"), diff --git a/pytket/docs/changelog.rst b/pytket/docs/changelog.rst index e27d364c26..18619d4ffc 100644 --- a/pytket/docs/changelog.rst +++ b/pytket/docs/changelog.rst @@ -4,6 +4,10 @@ Changelog Unreleased ---------- +Minor new features: + +* ``Circuit.add_conditional_barrier`` + Fixes: * Correct implementation of `symbol_substitution()` for box types that cannot diff --git a/pytket/pytket/qasm/qasm.py b/pytket/pytket/qasm/qasm.py index b1540caa24..735ccaba45 100644 --- a/pytket/pytket/qasm/qasm.py +++ b/pytket/pytket/qasm/qasm.py @@ -370,7 +370,7 @@ def barr(self, tree: List[Arg]) -> Iterable[CommandDict]: signature.append("Q") else: raise QASMParseError( - "UnitID " + arg + " in Barrier arguments is not declared." + "UnitID " + str(arg) + " in Barrier arguments is not declared." ) yield { "args": args,