diff --git a/pytket/binders/transform.cpp b/pytket/binders/transform.cpp index 53434cce0a..fa2902d9b1 100644 --- a/pytket/binders/transform.cpp +++ b/pytket/binders/transform.cpp @@ -146,7 +146,6 @@ PYBIND11_MODULE(transform, m) { "Rebase from any gate set into the gate set supported by " "ProjectQ (Rx, Ry, Rz, X, Y, Z, S, T, V, H, CX, CZ, CRz, " "SWAP).") - //.def_static("RebaseToMaryland", &Transforms::rebase_UMD) .def_static( "DecomposeCCX", &Transforms::decomp_CCX, "Decomposes all 3-qubit Toffoli (CCX) gates into " diff --git a/pytket/docs/changelog.rst b/pytket/docs/changelog.rst index a5b1d3ce54..02d1fe805c 100644 --- a/pytket/docs/changelog.rst +++ b/pytket/docs/changelog.rst @@ -1,6 +1,13 @@ Changelog ========= +1.0.1 (March 2022) +------------------ + +Fixes: + +* Fix problem with unassigned ancilla qubits during mapping. + 1.0.0 (March 2022) ------------------ diff --git a/pytket/docs/conf.py b/pytket/docs/conf.py index 668ef973ba..c3c60e1d20 100644 --- a/pytket/docs/conf.py +++ b/pytket/docs/conf.py @@ -40,7 +40,7 @@ # The short X.Y version version = "1.0" # The full version, including alpha/beta/rc tags -release = "1.0.0" +release = "1.0.1" # -- General configuration --------------------------------------------------- diff --git a/tket/proptests/proptest.cpp b/tket/proptests/proptest.cpp index dd254747cb..987ea823dc 100644 --- a/tket/proptests/proptest.cpp +++ b/tket/proptests/proptest.cpp @@ -42,11 +42,7 @@ using namespace tket; DO(DecomposeBoxes) \ DO(ComposePhasePolyBoxes) \ DO(SquashTK1) \ - DO(RebaseCirq) \ DO(RebaseTket) \ - DO(RebaseQuil) \ - DO(RebasePyZX) \ - DO(RebaseProjectQ) \ DO(DecomposeBridges) \ DO(FlattenRegisters) \ DO(RemoveBarriers) \ diff --git a/tket/src/ArchAwareSynth/Path.cpp b/tket/src/ArchAwareSynth/Path.cpp index 92313501ca..c2c7cf7dbc 100644 --- a/tket/src/ArchAwareSynth/Path.cpp +++ b/tket/src/ArchAwareSynth/Path.cpp @@ -228,41 +228,6 @@ IterationOrder::IterationOrder(const Architecture &arch) { std::reverse(iterationorder.begin(), iterationorder.end()); } -std::ostream &operator<<(std::ostream &out, const PathHandler &path) { - out << "\nprint the details of a pathhandler: \n"; - out << "size: " << path.get_size() << "\n"; - out << "connectivity_matrix_:\n "; - - for (unsigned i = 0; i != path.get_size(); ++i) { - for (unsigned j = 0; j != path.get_size(); ++j) { - out << path.get_connectivity_matrix()(i, j) << ", "; - } - out << std::endl; - } - out << std::endl; - - out << "distance_matrix_:\n "; - - for (unsigned i = 0; i != path.get_size(); ++i) { - for (unsigned j = 0; j != path.get_size(); ++j) { - out << path.get_distance_matrix()(i, j) << ", "; - } - out << std::endl; - } - out << std::endl; - - out << "path_matrix_:\n "; - - for (unsigned i = 0; i != path.get_size(); ++i) { - for (unsigned j = 0; j != path.get_size(); ++j) { - out << path.get_path_matrix()(i, j) << ", "; - } - out << std::endl; - } - out << std::endl; - return out; -} - MatrixXb PathHandler::get_connectivity_matrix() const { return connectivity_matrix_; } diff --git a/tket/src/ArchAwareSynth/SteinerTree.cpp b/tket/src/ArchAwareSynth/SteinerTree.cpp index b9ba52d426..286b3d3657 100644 --- a/tket/src/ArchAwareSynth/SteinerTree.cpp +++ b/tket/src/ArchAwareSynth/SteinerTree.cpp @@ -806,41 +806,5 @@ unsigned CNotSwapSynth::swap_to_root( bool CNotSwapSynth::valid_result() { return CNOT_matrix.is_id(); } -std::ostream& operator<<(std::ostream& out, const SteinerTree& st) { - out << "\nprint the details of a steiner tree: \n"; - out << "root: " << st.root << "\n"; - out << "cost: " << st.tree_cost << "\n"; - out << "SteinerNodeTypes: "; - for (SteinerNodeType nt : st.node_types) { - out << (int)nt << " "; - } - out << "\n"; - out << "neighbours: "; - - for (unsigned n : st.num_neighbours) { - out << n << " "; - } - out << "\n\n"; - return out; -} - -std::ostream& operator<<(std::ostream& out, const CNotSwapSynth& cnot) { - out << "\nprint the details of a CNot synth object: \n"; - - out << "circuit:\n"; - for (auto g : cnot.circ) { - out << g << ", "; - } - out << std::endl; - - out << "path:\n"; - out << cnot.paths; - - out << "CNot matrix:\n"; - out << cnot.CNOT_matrix; - - return out; -} - } // namespace aas } // namespace tket diff --git a/tket/src/ArchAwareSynth/include/ArchAwareSynth/Path.hpp b/tket/src/ArchAwareSynth/include/ArchAwareSynth/Path.hpp index 9b54c81ff5..68e96988cb 100644 --- a/tket/src/ArchAwareSynth/include/ArchAwareSynth/Path.hpp +++ b/tket/src/ArchAwareSynth/include/ArchAwareSynth/Path.hpp @@ -134,10 +134,5 @@ class IterationOrder { */ std::vector find_hampath(const Architecture &arch, long timeout = 10000); -/** - * print out a given Pathhandler - */ -std::ostream &operator<<(std::ostream &out, const PathHandler &path); - } // namespace aas } // namespace tket diff --git a/tket/src/ArchAwareSynth/include/ArchAwareSynth/SteinerTree.hpp b/tket/src/ArchAwareSynth/include/ArchAwareSynth/SteinerTree.hpp index f9d62d9b03..89dab1c1f1 100644 --- a/tket/src/ArchAwareSynth/include/ArchAwareSynth/SteinerTree.hpp +++ b/tket/src/ArchAwareSynth/include/ArchAwareSynth/SteinerTree.hpp @@ -147,11 +147,6 @@ class SteinerTree { */ std::vector nodes() const; - /** - * function to stream a steiner tree - */ - friend std::ostream &operator<<(std::ostream &out, const SteinerTree &st); - unsigned tree_cost; // the cost to reduce the Steiner tree alone int last_operation_cost; unsigned root; @@ -185,11 +180,6 @@ class CNotSwapSynth { */ bool valid_result(); - /** - * function to stream a CNotSwapSynth - */ - friend std::ostream &operator<<(std::ostream &out, const CNotSwapSynth &cnot); - private: void add_swap(unsigned first, unsigned second); void cleanup_swaps(); diff --git a/tket/src/CMakeLists.txt b/tket/src/CMakeLists.txt index 7dbc490a37..66511a6e9a 100644 --- a/tket/src/CMakeLists.txt +++ b/tket/src/CMakeLists.txt @@ -73,7 +73,6 @@ list(APPEND TKET_COMPS Architecture Simulation Diagonalisation - Program Characterisation Converters Placement diff --git a/tket/src/Mapping/MappingManager.cpp b/tket/src/Mapping/MappingManager.cpp index 2d5de2fca1..35475fe3b7 100644 --- a/tket/src/Mapping/MappingManager.cpp +++ b/tket/src/Mapping/MappingManager.cpp @@ -101,55 +101,60 @@ bool MappingManager::route_circuit_with_maps( // find next routed/unrouted boundary given updates mapping_frontier->advance_frontier_boundary(this->architecture_); } - - // check all nodes placed - - bool found_unplaced_qubit = false; - - // search for unplaced qubitto speed up the runtime - for (Qubit q : mapping_frontier->circuit_.all_qubits()) { - if (!this->architecture_->node_exists(Node(q))) { - found_unplaced_qubit = true; - break; - } - } - - if (found_unplaced_qubit && label_isolated_qubits) { + // there may still be some unlabelled qubits + if (label_isolated_qubits) { circuit_modified = true; - qubit_vector_t q_vec = mapping_frontier->circuit_.all_qubits(); - unit_map_t qubit_to_nodes_place; - node_set_t node_set_placed; - for (Qubit q : q_vec) { - if (this->architecture_->node_exists(Node(q))) { - qubit_to_nodes_place.insert({q, Node(q)}); - node_set_placed.insert(Node(q)); + unit_map_t placement; + qubit_vector_t to_place; + std::vector placed; + + // Find which/if any qubits need placing + for (const Qubit& q : mapping_frontier->circuit_.all_qubits()) { + Node n(q); + if (!this->architecture_->node_exists(n)) { + // Ancilla qubits can be assigned during routing + // If some qubits are unplaced then its possible the returned circuit + // has more qubits than the architecture has nodes, which is bad instead + // at least assign any unlabelled qubits to any ancilla nodes to prevent + // this + if (mapping_frontier->ancilla_nodes_.size() > 0) { + circuit_modified = true; + Node ancilla = *mapping_frontier->ancilla_nodes_.begin(); + mapping_frontier->merge_ancilla(q, ancilla); + mapping_frontier->ancilla_nodes_.erase( + mapping_frontier->ancilla_nodes_.begin()); + placed.push_back(n); + } else { + to_place.push_back(n); + } + } else { + placed.push_back(n); + // if already placed, make sure qubit retains placement + placement.insert({n, n}); } } - - node_vector_t nodes_vec = this->architecture_->get_all_nodes_vec(); - - // place all unplaced qubits - - for (Qubit q : q_vec) { - if (!this->architecture_->node_exists(Node(q))) { - // found unplaced qubit - - unsigned index_to_use = 0; - while (node_set_placed.find(nodes_vec[index_to_use]) != - node_set_placed.end()) { - ++index_to_use; - } - qubit_to_nodes_place.insert({q, nodes_vec[index_to_use]}); - node_set_placed.insert(nodes_vec[index_to_use]); + // avoid doing std::set_difference unless qubits need to be placed + unsigned n_placed = to_place.size(); + if (n_placed > 0) { + std::vector difference, + architecture_nodes = this->architecture_->get_all_nodes_vec(); + std::set_difference( + architecture_nodes.begin(), architecture_nodes.end(), placed.begin(), + placed.end(), std::inserter(difference, difference.begin())); + // should always be enough remaining qubits to assign unplaced qubits to + TKET_ASSERT(difference.size() >= n_placed); + for (unsigned i = 0; i < n_placed; i++) { + // naively assign each qubit to some free node + placement.insert({to_place[i], difference[i]}); mapping_frontier->update_bimaps( - mapping_frontier->get_qubit_from_circuit_uid(q), - nodes_vec[index_to_use]); + mapping_frontier->get_qubit_from_circuit_uid(to_place[i]), + difference[i]); } - } - mapping_frontier->update_linear_boundary_uids(qubit_to_nodes_place); - mapping_frontier->circuit_.rename_units(qubit_to_nodes_place); + mapping_frontier->update_linear_boundary_uids(placement); + mapping_frontier->circuit_.rename_units(placement); + } } return circuit_modified; diff --git a/tket/src/Predicates/CompilerPass.cpp b/tket/src/Predicates/CompilerPass.cpp index 50218aeb84..0c0a05092d 100644 --- a/tket/src/Predicates/CompilerPass.cpp +++ b/tket/src/Predicates/CompilerPass.cpp @@ -378,24 +378,10 @@ void from_json(const nlohmann::json& j, PassPtr& pp) { pp = PeepholeOptimise2Q(); } else if (passname == "FullPeepholeOptimise") { pp = FullPeepholeOptimise(); - } else if (passname == "RebaseCirq") { - pp = RebaseCirq(); } else if (passname == "RebaseTket") { pp = RebaseTket(); - } else if (passname == "RebaseHQS") { - pp = RebaseHQS(); - } else if (passname == "RebaseQuil") { - pp = RebaseQuil(); - } else if (passname == "RebaseProjectQ") { - pp = RebaseProjectQ(); - } else if (passname == "RebasePyZX") { - pp = RebasePyZX(); - } else if (passname == "RebaseUMD") { - pp = RebaseUMD(); } else if (passname == "RebaseUFR") { pp = RebaseUFR(); - } else if (passname == "RebaseOQC") { - pp = RebaseOQC(); } else if (passname == "RemoveRedundancies") { pp = RemoveRedundancies(); } else if (passname == "SynthesiseHQS") { @@ -485,9 +471,6 @@ void from_json(const nlohmann::json& j, PassPtr& pp) { content.at("x_circuit").get()); } pp = gen_simplify_initial(ac, caq, xc); - } else if (passname == "SquashHQS") { - // SEQUENCE PASS - DESERIALIZABLE ONLY - pp = SquashHQS(); } else if (passname == "FullMappingPass") { // SEQUENCE PASS - DESERIALIZABLE ONLY Architecture arc = content.at("architecture").get(); diff --git a/tket/src/Predicates/PassGenerators.cpp b/tket/src/Predicates/PassGenerators.cpp index 23ee444480..4a37176d42 100644 --- a/tket/src/Predicates/PassGenerators.cpp +++ b/tket/src/Predicates/PassGenerators.cpp @@ -250,11 +250,9 @@ PassPtr gen_routing_pass( Transform t = Transform(trans); PredicatePtr twoqbpred = std::make_shared(); - PredicatePtr placedpred = std::make_shared(arc); PredicatePtr n_qubit_pred = std::make_shared(arc.n_nodes()); PredicatePtrMap precons{ - CompilationUnit::make_type_pair(placedpred), CompilationUnit::make_type_pair(twoqbpred), CompilationUnit::make_type_pair(n_qubit_pred)}; diff --git a/tket/src/Predicates/PassLibrary.cpp b/tket/src/Predicates/PassLibrary.cpp index fc1f0d95d1..735bbca14f 100644 --- a/tket/src/Predicates/PassLibrary.cpp +++ b/tket/src/Predicates/PassLibrary.cpp @@ -80,14 +80,6 @@ const PassPtr &SynthesiseUMD() { {OpType::XXPhase, OpType::PhasedX, OpType::Rz}, true, "SynthesiseUMD")); return pp; } - -const PassPtr &RebaseCirq() { - static const PassPtr pp(gate_translation_pass( - Transforms::rebase_cirq(), {OpType::CZ, OpType::PhasedX, OpType::Rz}, - true, "RebaseCirq")); - return pp; -} - const PassPtr &RebaseTket() { static const PassPtr pp(gate_translation_pass( Transforms::rebase_tket(), {OpType::CX, OpType::TK1}, true, @@ -95,46 +87,6 @@ const PassPtr &RebaseTket() { return pp; } -const PassPtr &RebaseQuil() { - static const PassPtr pp(gate_translation_pass( - Transforms::rebase_quil(), {OpType::CZ, OpType::Rx, OpType::Rz}, true, - "RebaseQuil")); - return pp; -} - -const PassPtr &RebasePyZX() { - static const PassPtr pp(gate_translation_pass( - Transforms::rebase_pyzx(), - {OpType::SWAP, OpType::CX, OpType::CZ, OpType::Rz, OpType::Rx, OpType::S, - OpType::T, OpType::Z, OpType::X, OpType::H}, - true, "RebasePyZX")); - return pp; -} - -const PassPtr &RebaseProjectQ() { - static const PassPtr pp(gate_translation_pass( - Transforms::rebase_projectq(), - {OpType::SWAP, OpType::CRz, OpType::CX, OpType::CZ, OpType::H, OpType::X, - OpType::Y, OpType::Z, OpType::S, OpType::T, OpType::V, OpType::Rx, - OpType::Ry, OpType::Rz}, - true, "RebaseProjectQ")); - return pp; -} - -const PassPtr &RebaseHQS() { - static const PassPtr pp(gate_translation_pass( - Transforms::rebase_HQS(), {OpType::ZZMax, OpType::PhasedX, OpType::Rz}, - true, "RebaseHQS")); - return pp; -} - -const PassPtr &RebaseUMD() { - static const PassPtr pp(gate_translation_pass( - Transforms::rebase_UMD(), {OpType::XXPhase, OpType::PhasedX, OpType::Rz}, - true, "RebaseUMD")); - return pp; -} - const PassPtr &RebaseUFR() { static const PassPtr pp(gate_translation_pass( Transforms::rebase_UFR(), {OpType::CX, OpType::Rz, OpType::H}, true, @@ -142,13 +94,6 @@ const PassPtr &RebaseUFR() { return pp; } -const PassPtr &RebaseOQC() { - static const PassPtr pp(gate_translation_pass( - Transforms::rebase_OQC(), {OpType::ECR, OpType::Rz, OpType::SX}, true, - "RebaseOQC")); - return pp; -} - const PassPtr &PeepholeOptimise2Q() { OpTypeSet after_set = { OpType::TK1, OpType::CX, OpType::Measure, OpType::Collapse, @@ -352,14 +297,6 @@ const PassPtr &SquashTK1() { return pp; } -const PassPtr &SquashHQS() { - static const PassPtr pp([]() { - return gen_squash_pass( - {OpType::Rz, OpType::PhasedX}, CircPool::tk1_to_PhasedXRz); - }()); - return pp; -} - const PassPtr &DecomposeBridges() { static const PassPtr pp([]() { Transform t = Transforms::decompose_BRIDGE_to_CX(); diff --git a/tket/src/Predicates/include/Predicates/PassLibrary.hpp b/tket/src/Predicates/include/Predicates/PassLibrary.hpp index cf52b3e87a..42b6c59c25 100644 --- a/tket/src/Predicates/include/Predicates/PassLibrary.hpp +++ b/tket/src/Predicates/include/Predicates/PassLibrary.hpp @@ -42,17 +42,8 @@ const PassPtr &ComposePhasePolyBoxes(); /** Squash sequences of single-qubit gates to TK1 gates. */ const PassPtr &SquashTK1(); -const PassPtr &SquashHQS(); - -const PassPtr &RebaseCirq(); const PassPtr &RebaseTket(); -const PassPtr &RebaseQuil(); -const PassPtr &RebasePyZX(); -const PassPtr &RebaseProjectQ(); -const PassPtr &RebaseHQS(); -const PassPtr &RebaseUMD(); const PassPtr &RebaseUFR(); -const PassPtr &RebaseOQC(); const PassPtr &DecomposeBridges(); const PassPtr &FlattenRegisters(); diff --git a/tket/src/Program/CMakeLists.txt b/tket/src/Program/CMakeLists.txt deleted file mode 100644 index 3cf2fce67e..0000000000 --- a/tket/src/Program/CMakeLists.txt +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2019-2022 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. - -project(tket-${COMP}) - -if (NOT ${COMP} STREQUAL "Program") - message(FATAL_ERROR "Unexpected component name.") -endif() - -add_library(tket-${COMP} - Program_accessors.cpp - Program_analysis.cpp - Program_iteration.cpp - Program_manipulation.cpp - Program_units.cpp) - -list(APPEND DEPS_${COMP} - Circuit - Gate - Ops - OpType - Utils) - -foreach(DEP ${DEPS_${COMP}}) - target_include_directories( - tket-${COMP} PRIVATE ${TKET_${DEP}_INCLUDE_DIR}) - target_link_libraries( - tket-${COMP} PRIVATE tket-${DEP}) -endforeach() - -target_include_directories(tket-${COMP} - PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR} - ${TKET_${COMP}_INCLUDE_DIR} - ${TKET_${COMP}_INCLUDE_DIR}/${COMP}) - -target_link_libraries(tket-${COMP} PRIVATE ${CONAN_LIBS_SYMENGINE}) diff --git a/tket/src/Program/Program_accessors.cpp b/tket/src/Program/Program_accessors.cpp deleted file mode 100644 index 9b822b99e6..0000000000 --- a/tket/src/Program/Program_accessors.cpp +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2019-2022 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 "Program.hpp" - -namespace tket { - -Circuit &Program::get_circuit_ref(const FGVert &vert) { - return flow_[vert].circ; -} - -const Circuit &Program::get_circuit_ref(const FGVert &vert) const { - return flow_[vert].circ; -} - -std::optional Program::get_condition(const FGVert &vert) const { - return flow_[vert].branch_condition; -} - -std::optional Program::get_label(const FGVert &vert) const { - return flow_[vert].label; -} - -bool Program::get_branch(const FGEdge &edge) const { - return flow_[edge].branch; -} - -FGVertVec Program::get_successors(const FGVert &vert) const { - FGEdgeVec outs = get_out_edges(vert); - if (outs.size() == 1) { - return {get_target(outs.front())}; - } else if (outs.size() == 2) { - FGVertVec children(2); - for (const Edge &e : outs) { - if (get_branch(e)) - children[1] = get_target(e); - else - children[0] = get_target(e); - } - return children; - } else - throw ProgramError("Block does not have one or two successsors"); -} - -FGVertVec Program::get_predecessors(const FGVert &vert) const { - FGEdgeVec ins = get_in_edges(vert); - FGVertVec parents; - std::unordered_set lookup; - for (const Edge &e : ins) { - FGVert pred = get_source(e); - if (lookup.find(pred) == lookup.end()) { - parents.push_back(pred); - lookup.insert(pred); - } - } - return parents; -} - -FGVert Program::get_branch_successor(const FGVert &vert, bool branch) const { - FGEdgeVec outs = get_out_edges(vert); - for (const FGEdge &e : outs) { - if (get_branch(e) == branch) { - return get_target(e); - } - } - throw ProgramError("Could not find successor on desired branch"); -} - -FGEdgeVec Program::get_in_edges(const FGVert &vert) const { - FGEdgeVec ins; - for (auto [it, end] = boost::in_edges(vert, flow_); it != end; ++it) { - ins.push_back(*it); - } - return ins; -} - -FGEdgeVec Program::get_out_edges(const FGVert &vert) const { - FGEdgeVec outs; - for (auto [it, end] = boost::out_edges(vert, flow_); it != end; ++it) { - outs.push_back(*it); - } - return outs; -} - -unsigned Program::n_in_edges(const FGVert &vert) const { - return boost::in_degree(vert, flow_); -} - -unsigned Program::n_out_edges(const FGVert &vert) const { - return boost::out_degree(vert, flow_); -} - -FGVert Program::get_source(const FGEdge &edge) const { - return boost::source(edge, flow_); -} - -FGVert Program::get_target(const FGEdge &edge) const { - return boost::target(edge, flow_); -} - -unsigned Program::get_n_vertices() const { return boost::num_vertices(flow_); } - -} // namespace tket diff --git a/tket/src/Program/Program_analysis.cpp b/tket/src/Program/Program_analysis.cpp deleted file mode 100644 index f6479ed9b8..0000000000 --- a/tket/src/Program/Program_analysis.cpp +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2019-2022 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 "Program.hpp" - -namespace tket { - -bool Program::check_valid() const { - bool valid = true; - valid &= get_in_edges(entry_).empty(); - valid &= get_out_edges(entry_).size() == 1; - valid &= get_out_edges(exit_).empty(); - valid &= entry_ != exit_; - BGL_FORALL_VERTICES(block, flow_, FlowGraph) { - FGEdgeVec outs = get_out_edges(block); - if (block != exit_) { - if (flow_[block].branch_condition) { - valid &= outs.size() == 2; - unsigned n_true = 0; - unsigned n_false = 0; - for (const FGEdge &e : outs) { - if (get_branch(e)) - ++n_true; - else - ++n_false; - } - valid &= n_true == 1; - valid &= n_false == 1; - } else { - valid &= outs.size() == 1; - valid &= get_branch(outs.front()) == false; - } - } - for (const Qubit &qb : flow_[block].circ.all_qubits()) { - unit_lookup_t::iterator found = units_.get().find(qb); - valid &= found != units_.get().end(); - valid &= found->type() == UnitType::Qubit; - } - for (const Bit &b : flow_[block].circ.all_bits()) { - unit_lookup_t::iterator found = units_.get().find(b); - valid &= found != units_.get().end(); - valid &= found->type() == UnitType::Bit; - } - } - return valid; -} - -void Program::to_graphviz_file(const std::string &filename) const { - std::ofstream dot_file(filename); - to_graphviz(dot_file); -} - -void Program::to_graphviz(std::ostream &out) const { - out << "digraph G {\n"; - - std::map index_map; - unsigned i = 0; - BGL_FORALL_VERTICES(v, flow_, FlowGraph) { - index_map.insert({v, i}); - out << i << " [label = \""; - if (flow_[v].label) { - out << "LABEL " << *flow_[v].label << "\\n"; - } - for (const Command c : flow_[v].circ) { - out << c.to_str() << "\\n"; - } - if (flow_[v].branch_condition) { - out << "BRANCH " << flow_[v].branch_condition->repr(); - } - out << "\"];\n"; - ++i; - } - BGL_FORALL_EDGES(e, flow_, FlowGraph) { - FGVert source = get_source(e); - FGVert target = get_target(e); - out << index_map.at(source) << " -> " << index_map.at(target) - << " [label = \"" << get_branch(e) << "\"];\n"; - } - out << "}"; -} - -} // namespace tket diff --git a/tket/src/Program/Program_iteration.cpp b/tket/src/Program/Program_iteration.cpp deleted file mode 100644 index af10b97eff..0000000000 --- a/tket/src/Program/Program_iteration.cpp +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright 2019-2022 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 "Ops/FlowOp.hpp" -#include "Program.hpp" - -namespace tket { - -Program::BlockIterator::BlockIterator() - : prog_(nullptr), - current_vert_(boost::graph_traits::null_vertex()) {} - -Program::BlockIterator::BlockIterator(const Program &p) { - FGVert first = p.get_successors(p.entry_).front(); - if (first == p.exit_) { - current_vert_ = boost::graph_traits::null_vertex(); - return; - } - prog_ = &p; - current_vert_ = first; - stack_.push_back(first); - visited_.insert(first); -} - -Program::BlockIterator Program::BlockIterator::operator++(int) { - BlockIterator it = *this; - ++*this; - return it; -} - -Program::BlockIterator &Program::BlockIterator::operator++() { - while (!stack_.empty()) { - FGVert last_branch = stack_.back(); - FGVertVec succs = prog_->get_successors(last_branch); - for (const FGVert &s : succs) { - if (visited_.find(s) == visited_.end() && s != prog_->exit_) { - current_vert_ = s; - stack_.push_back(s); - visited_.insert(s); - return *this; - } - } - stack_.pop_back(); - } - *this = BlockIterator(); - return *this; -} - -Program::BlockIterator Program::block_begin() const { - return BlockIterator(*this); -} - -Program::BlockIterator Program::block_end() { return BlockIterator(); } - -Program::CommandIterator::CommandIterator(const Program &prog) { - prog_ = &prog; - current_block_ = prog_->block_begin(); - stage_ = ComItStage::Label; - prev_block_ = prog_->entry_; - ++*this; -} - -Program::CommandIterator Program::CommandIterator::operator++(int) { - CommandIterator it = *this; - ++*this; - return it; -} - -Program::CommandIterator &Program::CommandIterator::operator++() { - /** - * Approximately follows routine for one-pass code generation from Aho, Lam, - * Sethi, Ullman, section 6.7.1 (No need for backpatching when labels with - * arbitrary names allowed) - * - * for (Block b in prog) - * if b.preds.size > 1 yield LABEL - * for (Command c in b.circ) - * yield c - * if b.condition yield BRANCH - * if visited(b.successor(false)) yield GOTO - * yield STOP - */ - if (stage_ == ComItStage::Final) { - // Just output STOP; move to end() - *this = CommandIterator(); - return *this; - } - while (current_block_ != prog_->block_end()) { - switch (stage_) { - case ComItStage::Label: { - // Just reached a new block; possibly add a label - stage_ = ComItStage::FirstCommand; - FGVert block = *current_block_; - FGEdgeVec ins = prog_->get_in_edges(block); - if (ins.size() != 1 || prog_->get_source(ins.front()) != prev_block_ || - prog_->get_branch(ins.front())) { - // Add LABEL - std::string label = get_label(block); - Op_ptr op = std::make_shared(OpType::Label, label); - current_command_ = Command(op, {}); - return *this; - } else - continue; - } - case ComItStage::FirstCommand: { - // Just output a label; start iterating through commands of block - current_com_iterator_ = current_block_.get_circuit_ref().begin(); - if (current_com_iterator_ == current_block_.get_circuit_ref().end()) { - stage_ = ComItStage::Branch; - continue; - } else { - stage_ = ComItStage::Command; - current_command_ = *current_com_iterator_; - return *this; - } - } - case ComItStage::Command: { - // Just output a command; continue - ++current_com_iterator_; - if (current_com_iterator_ == current_block_.get_circuit_ref().end()) { - stage_ = ComItStage::Branch; - continue; - } else { - current_command_ = *current_com_iterator_; - return *this; - } - } - case ComItStage::Branch: { - // Finished commands for block; possibly add a branch - FGVert block = *current_block_; - std::optional condition = prog_->get_condition(block); - stage_ = ComItStage::Goto; - if (condition) { - // Add BRANCH - FGVert target = prog_->get_branch_successor(block, true); - std::string label = get_label(target); - Op_ptr op = std::make_shared(OpType::Branch, label); - current_command_ = Command(op, {*condition}); - return *this; - } else - continue; - } - case ComItStage::Goto: { - // Reached end of block; possibly add a Goto before moving to next block - prev_block_ = *current_block_; - ++current_block_; - stage_ = ComItStage::Label; - FGVert target = prog_->get_branch_successor(prev_block_, false); - if (current_block_ == prog_->block_end()) { - if (target == prog_->exit_) continue; - } else if (target == *current_block_) - continue; - // Add Goto - std::string label = get_label(target); - Op_ptr op = std::make_shared(OpType::Goto, label); - current_command_ = Command(op, {}); - return *this; - } - default: { - // None of Stop, Final, or End should be hit before - // the block iterator reaches end - throw ProgramError( - "Error in command iteration: hit final stages before " - "reaching exit block"); - } - } - } - // Label to STOP - if (stage_ == ComItStage::Label) { - std::map::iterator found = labels_.find(prog_->exit_); - if (found != labels_.end()) { - Op_ptr op = std::make_shared(OpType::Label, found->second); - current_command_ = Command(op, {}); - stage_ = ComItStage::Stop; - return *this; - } - } - // STOP command - Op_ptr op = std::make_shared(OpType::Stop); - current_command_ = Command(op, {}); - stage_ = ComItStage::Final; - return *this; -} - -std::string Program::CommandIterator::get_label(const FGVert &block) { - std::map::iterator found_label = labels_.find(block); - if (found_label == labels_.end()) { - std::optional label = prog_->get_label(block); - if (!label) label = "lab_" + std::to_string(labels_.size()); - labels_.insert({block, *label}); - return *label; - } else { - return found_label->second; - } -} - -Program::CommandIterator Program::begin() const { - return CommandIterator(*this); -} - -Program::CommandIterator Program::end() { return CommandIterator(); } - -} // namespace tket diff --git a/tket/src/Program/Program_manipulation.cpp b/tket/src/Program/Program_manipulation.cpp deleted file mode 100644 index 19099f78e5..0000000000 --- a/tket/src/Program/Program_manipulation.cpp +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright 2019-2022 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 "Program.hpp" - -namespace tket { - -Program::Program() { - entry_ = add_vertex(Circuit()); - exit_ = add_vertex(Circuit()); - add_edge(entry_, exit_); -} - -Program::Program(const Program &to_copy) { - std::map isomap = copy_graph(to_copy); - entry_ = isomap.at(to_copy.entry_); - exit_ = isomap.at(to_copy.exit_); -} - -Program::Program(unsigned qubits, unsigned bits) : Program() { - add_q_register(q_default_reg(), qubits); - add_c_register(c_default_reg(), bits); -} - -FGVert Program::add_vertex( - const Circuit &circ, std::optional branch_condition, - const std::optional &label) { - for (const Qubit &qb : circ.all_qubits()) { - add_qubit(qb, false); - } - for (const Bit &b : circ.all_bits()) { - add_bit(b, false); - } - FGVert new_v = boost::add_vertex(flow_); - flow_[new_v] = {circ, branch_condition, label}; - return new_v; -} - -void Program::remove_vertex(const FGVert &vert) { - boost::clear_vertex(vert, flow_); - boost::remove_vertex(vert, flow_); -} - -FGEdge Program::add_edge( - const FGVert &source, const FGVert &target, bool branch) { - std::pair edge_pair = boost::add_edge(source, target, flow_); - if (!edge_pair.second) throw ProgramError("Could not add edge to flow graph"); - FGEdge new_e = edge_pair.first; - flow_[new_e] = {branch}; - return new_e; -} - -void Program::remove_edge(const FGEdge &edge) { - boost::remove_edge(edge, flow_); -} - -std::map Program::copy_graph(const Program &to_copy) { - std::map isomap; - if (&to_copy == this) { - throw ProgramError("Cannot copy a program into itself"); - } - for (const Qubit &qb : to_copy.all_qubits()) { - add_qubit(qb, false); - } - for (const Bit &b : to_copy.all_bits()) { - add_bit(b, false); - } - BGL_FORALL_VERTICES(v, to_copy.flow_, FlowGraph) { - FGVert new_v = boost::add_vertex(this->flow_); - this->flow_[new_v] = to_copy.flow_[v]; - isomap.insert({v, new_v}); - } - BGL_FORALL_EDGES(e, to_copy.flow_, FlowGraph) { - FGVert source = isomap.at(to_copy.get_source(e)); - FGVert target = isomap.at(to_copy.get_target(e)); - bool branch = to_copy.get_branch(e); - add_edge(source, target, branch); - } - return isomap; -} - -FGVert Program::add_block(const Circuit &circ) { - FGVert block = add_vertex(circ); - FGEdgeVec ins = get_in_edges(exit_); - for (const FGEdge &e : ins) { - add_edge(get_source(e), block, get_branch(e)); - remove_edge(e); - } - add_edge(block, exit_); - return block; -} - -void Program::add_op(const Op_ptr &op, const std::vector &args) { - unit_vector_t arg_ids; - op_signature_t sig = op->get_signature(); - for (unsigned i = 0; i < args.size(); ++i) { - if (sig.at(i) == EdgeType::Quantum) { - arg_ids.push_back(Qubit(args[i])); - } else { - arg_ids.push_back(Bit(args[i])); - } - } - return add_op(op, arg_ids); -} - -void Program::add_op(const Op_ptr &op, const unit_vector_t &args) { - FGVertVec lasts = get_predecessors(exit_); - FGVert block; - if (lasts.size() == 1 && lasts.front() != entry_ && - !get_condition(lasts.front())) { - block = lasts.front(); - } else { - block = add_block({}); - } - Circuit &circ = flow_[block].circ; - op_signature_t sig = op->get_signature(); - for (unsigned i = 0; i < args.size(); ++i) { - if (sig.at(i) == EdgeType::Quantum) { - circ.add_qubit(Qubit(args[i]), false); - } else { - circ.add_bit(Bit(args[i]), false); - } - } - circ.add_op(op, args); -} - -void Program::append(const Program &to_append) { - std::map isomap = copy_graph(to_append); - FGEdgeVec ins = get_in_edges(exit_); - FGVert added_entry = isomap.at(to_append.entry_); - FGVert target = get_branch_successor(added_entry, false); - for (const FGEdge &e : ins) { - FGVert source = get_source(e); - bool branch = get_branch(e); - add_edge(source, target, branch); - } - remove_vertex(added_entry); - remove_vertex(exit_); - exit_ = isomap.at(to_append.exit_); -} - -void Program::append_if(const Bit &condition_bit, const Program &body) { - std::map isomap = copy_graph(body); - FGVert added_entry = isomap.at(body.entry_); - FGVert added_exit = isomap.at(body.exit_); - FGVert target = get_branch_successor(added_entry, false); - flow_[exit_].branch_condition = condition_bit; - add_edge(exit_, target, true); - add_edge(exit_, added_exit, false); - remove_vertex(added_entry); - exit_ = added_exit; -} - -void Program::append_if_else( - const Bit &condition_bit, const Program &if_body, - const Program &else_body) { - std::map if_map = copy_graph(if_body); - FGVert if_entry = if_map.at(if_body.entry_); - FGVert if_exit = if_map.at(if_body.exit_); - FGVert if_target = get_branch_successor(if_entry, false); - std::map else_map = copy_graph(else_body); - FGVert else_entry = else_map.at(else_body.entry_); - FGVert else_exit = else_map.at(else_body.exit_); - FGVert else_target = get_branch_successor(else_entry, false); - flow_[exit_].branch_condition = condition_bit; - add_edge(exit_, if_target, true); - add_edge(exit_, else_target, false); - remove_vertex(if_entry); - remove_vertex(else_entry); - add_edge(if_exit, else_exit, false); - exit_ = else_exit; -} - -void Program::append_while(const Bit &condition_bit, const Program &body) { - std::map isomap = copy_graph(body); - FGVert added_entry = isomap.at(body.entry_); - FGVert added_exit = isomap.at(body.exit_); - FGVert target = get_branch_successor(added_entry, false); - FGVert new_exit = add_vertex(Circuit()); - flow_[added_exit].branch_condition = condition_bit; - add_edge(added_exit, target, true); - add_edge(added_exit, new_exit, false); - add_edge(exit_, added_exit, false); - remove_vertex(added_entry); - exit_ = new_exit; -} - -Program operator>>(const Program &p1, const Program &p2) { - Program new_prog = p1; - new_prog.append(p2); - return new_prog; -} - -} // namespace tket diff --git a/tket/src/Program/Program_units.cpp b/tket/src/Program/Program_units.cpp deleted file mode 100644 index 1b4e2d0b00..0000000000 --- a/tket/src/Program/Program_units.cpp +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 2019-2022 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 "Program.hpp" - -namespace tket { - -qubit_vector_t Program::all_qubits() const { - qubit_vector_t all_qbs; - for (auto [it, end] = units_.get().equal_range(UnitType::Qubit); - it != end; ++it) { - all_qbs.push_back(Qubit(*it)); - } - return all_qbs; -} - -bit_vector_t Program::all_bits() const { - bit_vector_t all_bs; - for (auto [it, end] = units_.get().equal_range(UnitType::Bit); - it != end; it++) { - all_bs.push_back(Bit(*it)); - } - return all_bs; -} - -unit_vector_t Program::all_units() const { - unit_vector_t all_us; - for (const UnitID& u : units_.get()) { - all_us.push_back(u); - } - return all_us; -} - -std::map Program::bit_readout() const { - std::map res; - - // Order bits to generate indices - bit_vector_t all_bs = all_bits(); - std::sort(all_bs.begin(), all_bs.end()); - unsigned i = 0; - for (const Bit& b : all_bs) { - res.insert({b, i}); - i++; - } - - return res; -} - -std::map Program::qubit_readout() const { - std::map bit_ro = bit_readout(); - FGVertVec finals = get_predecessors(exit_); - if (finals.size() == 1) { - // Circuit may not contain every unit from the full program, so need to map - // indices - const Circuit& circ = get_circuit_ref(finals.front()); - std::map circ_ro = circ.qubit_readout(); - bit_vector_t circ_bits = circ.all_bits(); - std::map result; - for (const std::pair& pair : circ_ro) { - result.insert({pair.first, bit_ro.at(circ_bits.at(pair.second))}); - } - return result; - } else - return {}; -} - -opt_reg_info_t Program::get_reg_info(std::string reg_name) const { - unit_lookup_t::index::type::iterator found = - units_.get().find(reg_name); - if (found == units_.get().end()) - return std::nullopt; - else - return found->reg_info(); -} - -register_t Program::get_reg(std::string reg_name) const { - register_t reg; - for (auto [it, end] = units_.get().equal_range(reg_name); it != end; - it++) { - if (it->reg_dim() != 1) - throw CircuitInvalidity("Cannot linearise register " + reg_name); - reg.insert({it->index()[0], *it}); - } - return reg; -} - -void Program::add_qubit(const Qubit& id, bool reject_dups) { - unit_lookup_t::index::type::iterator found = - units_.get().find(id); - if (found != units_.get().end()) { - if (reject_dups) { - throw CircuitInvalidity( - "A unit with ID \"" + id.repr() + "\" already exists"); - } else if (found->type() == UnitType::Qubit) { - return; - } else { - throw CircuitInvalidity( - "A bit with ID \"" + id.repr() + "\" already exists"); - } - } - opt_reg_info_t reg_info = get_reg_info(id.reg_name()); - register_info_t correct_info = {UnitType::Qubit, id.reg_dim()}; - if (reg_info && !(reg_info.value() == correct_info)) - throw CircuitInvalidity( - "Cannot add qubit with ID \"" + id.repr() + - "\" as register is not compatible"); - units_.insert(id); -} - -void Program::add_bit(const Bit& id, bool reject_dups) { - unit_lookup_t::index::type::iterator found = - units_.get().find(id); - if (found != units_.get().end()) { - if (reject_dups) { - throw CircuitInvalidity( - "A unit with ID \"" + id.repr() + "\" already exists"); - } else if (found->type() == UnitType::Bit) { - return; - } else { - throw CircuitInvalidity( - "A qubit with ID \"" + id.repr() + "\" already exists"); - } - } - opt_reg_info_t reg_info = get_reg_info(id.reg_name()); - register_info_t correct_info = {UnitType::Bit, id.reg_dim()}; - if (reg_info && !(reg_info.value() == correct_info)) - throw CircuitInvalidity( - "Cannot add bit with ID \"" + id.repr() + - "\" as register is not compatible"); - units_.insert(id); -} - -register_t Program::add_q_register(std::string reg_name, unsigned size) { - if (get_reg_info(reg_name)) - throw CircuitInvalidity( - "A register with name \"" + reg_name + "\" already exists"); - register_t ids; - for (unsigned i = 0; i < size; i++) { - Qubit id(reg_name, i); - units_.insert(id); - ids.insert({i, id}); - } - return ids; -} - -register_t Program::add_c_register(std::string reg_name, unsigned size) { - if (get_reg_info(reg_name)) - throw CircuitInvalidity( - "A register with name \"" + reg_name + "\" already exists"); - register_t ids; - for (unsigned i = 0; i < size; i++) { - Bit id(reg_name, i); - units_.insert(id); - ids.insert({i, id}); - } - return ids; -} - -} // namespace tket diff --git a/tket/src/Program/include/Program/Program.hpp b/tket/src/Program/include/Program/Program.hpp deleted file mode 100644 index 8d9b6d6a4c..0000000000 --- a/tket/src/Program/include/Program/Program.hpp +++ /dev/null @@ -1,282 +0,0 @@ -// Copyright 2019-2022 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 "Circuit/Circuit.hpp" - -namespace tket { - -struct FlowVertProperties { - Circuit circ; - std::optional branch_condition; - std::optional label; -}; - -struct FlowEdgeProperties { - bool branch; -}; - -typedef boost::adjacency_list< - boost::listS, boost::listS, boost::bidirectionalS, FlowVertProperties, - FlowEdgeProperties> - FlowGraph; -typedef boost::graph_traits::vertex_descriptor FGVert; -typedef boost::graph_traits::edge_descriptor FGEdge; - -typedef std::vector FGVertVec; -typedef std::vector FGEdgeVec; - -typedef boost::multi_index::multi_index_container< - UnitID, boost::multi_index::indexed_by< - boost::multi_index::ordered_unique< - boost::multi_index::tag, - boost::multi_index::identity >, - boost::multi_index::ordered_non_unique< - boost::multi_index::tag, - boost::multi_index::const_mem_fun< - UnitID, UnitType, &UnitID::type> >, - boost::multi_index::ordered_non_unique< - boost::multi_index::tag, - boost::multi_index::const_mem_fun< - UnitID, std::string, &UnitID::reg_name> > > > - unit_lookup_t; - -class ProgramError : public std::logic_error { - public: - explicit ProgramError(const std::string &message) - : std::logic_error(message) {} -}; - -/** - * A control flow graph where basic blocks are Circuits. - * - * Each block ends with either an unconditional jump, or - * branching based on a single bit condition. - * - * Each block can contain OpenQASM-style conditional gates - * using the Conditional without the need for explicit branching. - */ -class Program { - public: - Program(); - explicit Program(unsigned qubits, unsigned bits = 0); - Program(const Program &to_copy); - - /** Unit control */ - qubit_vector_t all_qubits() const; - bit_vector_t all_bits() const; - std::vector all_units() const; - - std::map bit_readout() const; - std::map qubit_readout() const; - - opt_reg_info_t get_reg_info(std::string reg_name) const; - register_t get_reg(std::string reg_name) const; - - void add_qubit(const Qubit &id, bool reject_dups = true); - void add_bit(const Bit &id, bool reject_dups = true); - register_t add_q_register(std::string reg_name, unsigned size); - register_t add_c_register(std::string reg_name, unsigned size); - - /** Graph accessors */ - Circuit &get_circuit_ref(const FGVert &vert); - const Circuit &get_circuit_ref(const FGVert &vert) const; - std::optional get_condition(const FGVert &vert) const; - std::optional get_label(const FGVert &vert) const; - - bool get_branch(const FGEdge &edge) const; - - FGVertVec get_successors(const FGVert &vert) const; - FGVertVec get_predecessors(const FGVert &vert) const; - - FGVert get_branch_successor(const FGVert &vert, bool branch = false) const; - - FGEdgeVec get_in_edges(const FGVert &vert) const; - FGEdgeVec get_out_edges(const FGVert &vert) const; - unsigned n_in_edges(const FGVert &vert) const; - unsigned n_out_edges(const FGVert &vert) const; - - FGVert get_source(const FGEdge &edge) const; - FGVert get_target(const FGEdge &edge) const; - - unsigned get_n_vertices() const; - - /** Graph manipulation */ - FGVert add_vertex( - const Circuit &circ, std::optional branch_condition = std::nullopt, - const std::optional &label = std::nullopt); - void remove_vertex(const FGVert &vert); - - FGEdge add_edge( - const FGVert &source, const FGVert &target, bool branch = false); - void remove_edge(const FGEdge &edge); - - std::map copy_graph(const Program &to_copy); - - /** Adding instructions to program */ - FGVert add_block(const Circuit &circ); - - void add_op(const Op_ptr &op, const std::vector &args); - void add_op(const Op_ptr &op, const unit_vector_t &args); - - template - void add_op(OpType type, const std::vector &args) { - add_op(get_op_ptr(type, std::vector{}, args.size()), args); - } - template - void add_op(OpType type, const Expr ¶m, const std::vector &args) { - add_op(get_op_ptr(type, param, args.size()), args); - } - template - void add_op( - OpType type, const std::vector ¶ms, - const std::vector &args) { - add_op(get_op_ptr(type, params, args.size()), args); - } - - void append(const Program &to_append); - void append_if(const Bit &condition_bit, const Program &body); - void append_if_else( - const Bit &condition_bit, const Program &if_body, - const Program &else_body); - void append_while(const Bit &condition_bit, const Program &body); - - friend Program operator>>(const Program &p1, const Program &p2); - - /** Graph analysis */ - - /** - * Checks whether flow graph is in the correct format. - * Returning false should be seen as a fatal error. - */ - bool check_valid() const; - - void to_graphviz_file(const std::string &filename) const; - void to_graphviz(std::ostream &out) const; - - // Insert Control Flow optimisations here - - /** Command Iteration */ - - /** - * Iterates through the vertices of the flow graph in a depth-first, - * preorder traversal - */ - class BlockIterator { - public: - BlockIterator(); - explicit BlockIterator(const Program &prog); - - const FGVert &operator*() const { return current_vert_; } - const FGVert *operator->() const { return ¤t_vert_; } - bool operator==(const BlockIterator &other) const { - return this->current_vert_ == other.current_vert_; - } - bool operator!=(const BlockIterator &other) const { - return !(*this == other); - } - - BlockIterator operator++(int); - BlockIterator &operator++(); - - const Circuit &get_circuit_ref() const { - return prog_->get_circuit_ref(current_vert_); - } - std::optional get_condition() const { - return prog_->get_condition(current_vert_); - } - - private: - const Program *prog_; - FGVert current_vert_; - std::list stack_; - std::set visited_; - }; - - BlockIterator block_begin() const; - static BlockIterator block_end(); - - /** - * Iterates through the commands of the program. - * Commands in each block are given by the iteration order of the Circuit - * class. Blocks are then ordered according to BlockIterator. Labels, jumps, - * branches and exit commands are inserted at beginning and end of blocks. - */ - class CommandIterator { - public: - explicit CommandIterator(const Program &prog); - CommandIterator() : stage_(ComItStage::End) {} - - Command operator*() const { return current_command_; } - const Command *operator->() const { return ¤t_command_; } - bool operator==(const CommandIterator &other) const { - return (current_block_ == other.current_block_) && - (current_com_iterator_ == other.current_com_iterator_) && - (stage_ == other.stage_); - } - bool operator!=(const CommandIterator &other) const { - return !(*this == other); - } - // Postfix incrementer - CommandIterator operator++(int); - // Prefix incrementer - CommandIterator &operator++(); - - friend std::ostream &operator<<( - std::ostream &out, const CommandIterator &cit) { - out << cit->to_str(); - return out; - }; - - private: - Command current_command_; - BlockIterator current_block_; - Circuit::CommandIterator current_com_iterator_; - std::map labels_; - const Program *prog_; - - /** - * Stage of command iteration to come next - */ - enum class ComItStage { - Label, // Just reached a new block; possibly add a label - FirstCommand, // Just output a label; start iterating through commands of - // block - Command, // Just output a command; continue - Branch, // Finished commands for block; possibly add a branch - Goto, // Reached end of block; possibly add a Goto before moving to next - // block - Stop, // Just output label for exit block; output STOP - Final, // Just output STOP; move to end() - End // Reserved for end() - }; - ComItStage stage_; // The next stage of a block's commands to try - FGVert prev_block_; // Used to determine if a label is needed - - std::string get_label(const FGVert &block); - }; - - CommandIterator begin() const; - static CommandIterator end(); - - private: - FlowGraph flow_; - FGVert entry_; - FGVert exit_; - - unit_lookup_t units_; -}; - -} // namespace tket diff --git a/tket/src/Transformations/Rebase.cpp b/tket/src/Transformations/Rebase.cpp index fedb1903f9..50ac872ea8 100644 --- a/tket/src/Transformations/Rebase.cpp +++ b/tket/src/Transformations/Rebase.cpp @@ -123,18 +123,6 @@ Transform rebase_cirq() { CircPool::tk1_to_PhasedXRz); } -Transform rebase_HQS() { - return rebase_factory( - {OpType::ZZMax, OpType::PhasedX, OpType::Rz}, CircPool::CX_using_ZZMax(), - CircPool::tk1_to_PhasedXRz); -} - -Transform rebase_UMD() { - return rebase_factory( - {OpType::XXPhase, OpType::PhasedX, OpType::Rz}, - CircPool::CX_using_XXPhase_0(), CircPool::tk1_to_PhasedXRz); -} - Transform rebase_quil() { return rebase_factory( {OpType::CZ, OpType::Rx, OpType::Rz}, CircPool::H_CZ_H(), diff --git a/tket/src/Transformations/include/Transformations/Rebase.hpp b/tket/src/Transformations/include/Transformations/Rebase.hpp index ff0bca2095..d5a8707b67 100644 --- a/tket/src/Transformations/include/Transformations/Rebase.hpp +++ b/tket/src/Transformations/include/Transformations/Rebase.hpp @@ -37,14 +37,6 @@ Transform rebase_tket(); // Singleqs: PhasedX, Rz Transform rebase_cirq(); -// Multiqs: ZZMax -// Singleqs: PhasedX, Rz -Transform rebase_HQS(); - -// Multiqs: XXPhase -// Singleqs: PhasedX, Rz -Transform rebase_UMD(); - // Multiqs: CZ // Singleqs: Rx, Rz Transform rebase_quil(); diff --git a/tket/tests/CMakeLists.txt b/tket/tests/CMakeLists.txt index 84b3c17691..27e54165be 100644 --- a/tket/tests/CMakeLists.txt +++ b/tket/tests/CMakeLists.txt @@ -64,7 +64,6 @@ target_link_libraries(test_tket PRIVATE tket-OpType tket-PauliGraph tket-Predicates - tket-Program tket-Placement tket-TokenSwapping tket-Mapping diff --git a/tket/tests/test_LexiRoute.cpp b/tket/tests/test_LexiRoute.cpp index 91ec62a7c5..035b02340b 100644 --- a/tket/tests/test_LexiRoute.cpp +++ b/tket/tests/test_LexiRoute.cpp @@ -1003,8 +1003,10 @@ SCENARIO( MappingManager mm(std::make_shared(test_arc)); REQUIRE(!mm.route_circuit( - test_circuit, {std::make_shared(), - std::make_shared()})); + test_circuit, + {std::make_shared(), + std::make_shared()}, + false)); qubit_vector_t all_qs_post_solve = test_circuit.all_qubits(); REQUIRE(all_qs_post_place == all_qs_post_solve); @@ -1223,8 +1225,10 @@ SCENARIO("Empty circuits, with and without blank wires") { RingArch arc(6); MappingManager mm(std::make_shared(arc)); REQUIRE(!mm.route_circuit( - circ, {std::make_shared(), - std::make_shared()})); + circ, + {std::make_shared(), + std::make_shared()}, + false)); REQUIRE(circ.depth() == 0); REQUIRE(circ.n_gates() == 0); REQUIRE(circ.n_qubits() == 0); @@ -1525,7 +1529,36 @@ SCENARIO("Initial map should contain all data qubits") { REQUIRE(test_unitary_comparison(initial_circ, circ)); } } +SCENARIO("Unlabelled qubits should be assigned to ancilla qubits.") { + Architecture arc({{0, 1}, {1, 2}, {2, 3}, {3, 0}}); + Circuit c(4); + c.add_op(OpType::CZ, {0, 3}); + c.add_op(OpType::CZ, {1, 0}); + c.add_op(OpType::CZ, {3, 1}); + c.add_op(OpType::H, {2}); + + std::shared_ptr maps = std::make_shared(); + // Initialise the maps by the same way it's done with CompilationUnit + for (const UnitID& u : c.all_units()) { + maps->initial.insert({u, u}); + maps->final.insert({u, u}); + } + MappingManager mm(std::make_shared(arc)); + mm.route_circuit_with_maps( + c, + {std::make_shared(), + std::make_shared()}, + maps, true); + REQUIRE(maps->initial.left.find(Qubit(0))->second == Node(0)); + REQUIRE(maps->initial.left.find(Qubit(1))->second == Node(3)); + REQUIRE(maps->initial.left.find(Qubit(2))->second == Node(2)); + REQUIRE(maps->initial.left.find(Qubit(3))->second == Node(1)); + REQUIRE(maps->final.left.find(Qubit(0))->second == Node(0)); + REQUIRE(maps->final.left.find(Qubit(1))->second == Node(2)); + REQUIRE(maps->final.left.find(Qubit(2))->second == Node(3)); + REQUIRE(maps->final.left.find(Qubit(3))->second == Node(1)); +} SCENARIO("Lexi relabel with partially mapped circuit") { GIVEN("With an unplaced qubit") { Architecture arc({{0, 1}, {1, 2}}); diff --git a/tket/tests/test_Program.cpp b/tket/tests/test_Program.cpp deleted file mode 100644 index b6be4956df..0000000000 --- a/tket/tests/test_Program.cpp +++ /dev/null @@ -1,438 +0,0 @@ -// Copyright 2019-2022 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 - -#include "Program/Program.hpp" -#include "testutil.hpp" - -namespace tket { -namespace test_Program { - -SCENARIO("Basic Program construction") { - GIVEN("An empty Program") { - Program p; - p.check_valid(); - REQUIRE(p.get_n_vertices() == 2); - } - GIVEN("A single block via add_block") { - Program p(2, 2); - Circuit c(2, 2); - c.add_op(OpType::X, uvec{0}); - c.add_measure(0, 0); - p.add_block(c); - p.check_valid(); - REQUIRE(p.get_n_vertices() == 3); - } - GIVEN("A single block via add_op") { - Program p(2, 2); - p.add_op(OpType::X, uvec{0}); - p.add_op(OpType::Measure, uvec{1, 1}); - p.check_valid(); - REQUIRE(p.get_n_vertices() == 3); - REQUIRE(p.bit_readout().size() == 2); - REQUIRE(p.qubit_readout().size() == 1); - REQUIRE(p.qubit_readout().at(Qubit(1)) == 1); - } - GIVEN("A straight-line block sequence") { - Program p(2, 2); - Circuit c(2, 2); - c.add_op(OpType::X, uvec{0}); - c.add_measure(0, 0); - p.add_block(c); - p.add_block(c); - p.add_block(c); - p.check_valid(); - REQUIRE(p.get_n_vertices() == 5); - } - GIVEN("Conditional execution") { - Program p(2, 2); - p.add_op(OpType::X, uvec{0}); - p.add_op(OpType::Measure, uvec{0, 0}); - Program body(2, 2); - body.add_op(OpType::X, uvec{1}); - p.append_if(Bit(0), body); - p.add_op(OpType::Z, uvec{0}); - p.check_valid(); - REQUIRE(p.get_n_vertices() == 6); - } - GIVEN("If-else") { - Program p(2, 2); - p.add_op(OpType::X, uvec{0}); - p.add_op(OpType::Measure, uvec{0, 0}); - Program ifbody(2, 2); - ifbody.add_op(OpType::X, uvec{1}); - Program elsebody(2, 2); - elsebody.add_op(OpType::Y, uvec{1}); - p.append_if_else(Bit(0), ifbody, elsebody); - p.add_op(OpType::Z, uvec{0}); - p.check_valid(); - REQUIRE(p.get_n_vertices() == 8); - } - GIVEN("While loop") { - Program p(2, 2); - p.add_op(OpType::X, uvec{0}); - p.add_op(OpType::Measure, uvec{0, 0}); - Program whilebody(2, 2); - whilebody.add_op(OpType::H, uvec{0}); - whilebody.add_op(OpType::Measure, uvec{0, 0}); - p.append_while(Bit(0), whilebody); - p.add_op(OpType::Y, uvec{1}); - p.check_valid(); - REQUIRE(p.get_n_vertices() == 7); - } - GIVEN("Appending interesting programs") { - Program p(2, 2); - Program ifbody(2, 2); - ifbody.add_op(OpType::X, uvec{1}); - p.append_if(Bit(0), ifbody); - Program p2(2, 2); - Program whilebody(2, 2); - whilebody.add_op(OpType::H, uvec{0}); - whilebody.add_op(OpType::Measure, uvec{0, 0}); - p2.append_while(Bit(0), whilebody); - p.append(p2); - p.check_valid(); - REQUIRE(p.get_n_vertices() == 7); - } -} - -SCENARIO("Check producing Graphviz does not fail") { - GIVEN("If-else") { - Program p(2, 2); - p.add_op(OpType::X, uvec{0}); - p.add_op(OpType::Measure, uvec{0, 0}); - Program ifbody(2, 2); - ifbody.add_op(OpType::X, uvec{1}); - Program elsebody(2, 2); - elsebody.add_op(OpType::Y, uvec{1}); - p.append_if_else(Bit(0), ifbody, elsebody); - p.add_op(OpType::Z, uvec{0}); - REQUIRE_NOTHROW(p.to_graphviz_file("ifelse.dot")); - remove("ifelse.dot"); - } -} - -SCENARIO("Block iteration") { - GIVEN("An empty Program") { - Program p; - REQUIRE(p.block_begin() == p.block_end()); - } - GIVEN("A single block via add_block") { - Program p(2, 2); - Circuit c(2, 2); - c.add_op(OpType::X, uvec{0}); - c.add_measure(0, 0); - FGVert block = p.add_block(c); - Program::BlockIterator blit = p.block_begin(); - CHECK(*blit == block); - ++blit; - CHECK(blit == p.block_end()); - } - GIVEN("A single block via add_op") { - Program p(2, 2); - p.add_op(OpType::X, uvec{0}); - p.add_op(OpType::Measure, uvec{0, 0}); - Program::BlockIterator blit = p.block_begin(); - CHECK(blit != p.block_end()); - ++blit; - CHECK(blit == p.block_end()); - } - GIVEN("A straight-line block sequence") { - Program p(2, 2); - Circuit c(2, 2); - c.add_op(OpType::X, uvec{0}); - c.add_measure(0, 0); - FGVert block0 = p.add_block(c); - FGVert block1 = p.add_block(c); - FGVert block2 = p.add_block(c); - Program::BlockIterator blit = p.block_begin(); - CHECK(*blit == block0); - ++blit; - CHECK(*blit == block1); - ++blit; - CHECK(*blit == block2); - ++blit; - CHECK(blit == p.block_end()); - } - GIVEN("Conditional execution") { - Program p(2, 2); - p.add_op(OpType::X, uvec{0}); - p.add_op(OpType::Measure, uvec{0, 0}); - Program body(2, 2); - body.add_op(OpType::X, uvec{1}); - p.append_if(Bit(0), body); - p.add_op(OpType::Z, uvec{0}); - Program::BlockIterator blit = p.block_begin(); - // Initial gates - CHECK(blit.get_circuit_ref().n_gates() == 2); - ++blit; - // Block is just a branch - CHECK(blit.get_condition()); - ++blit; - // Block AFTER the if - CHECK(blit.get_circuit_ref().n_gates() == 1); - CHECK(p.n_in_edges(*blit) == 2); - ++blit; - // Body of the if - CHECK(blit.get_circuit_ref().n_gates() == 1); - CHECK(p.n_in_edges(*blit) == 1); - ++blit; - // Exit - CHECK(blit == p.block_end()); - } - GIVEN("If-else") { - Program p(2, 2); - p.add_op(OpType::X, uvec{0}); - p.add_op(OpType::Measure, uvec{0, 0}); - Program ifbody(2, 2); - ifbody.add_op(OpType::X, uvec{1}); - Program elsebody(1, 1); - elsebody.add_op(OpType::Y, uvec{0}); - p.append_if_else(Bit(0), ifbody, elsebody); - p.add_op(OpType::Z, uvec{0}); - Program::BlockIterator blit = p.block_begin(); - // Initial gates - CHECK(blit.get_circuit_ref().n_gates() == 2); - ++blit; - // Block is just a branch - CHECK(blit.get_condition()); - ++blit; - // Else block - CHECK(blit.get_circuit_ref().n_qubits() == 1); - ++blit; - // Block after if-else - CHECK(blit.get_circuit_ref().n_gates() == 1); - CHECK(p.n_in_edges(*blit) == 2); - ++blit; - // Body of the if - CHECK(blit.get_circuit_ref().n_gates() == 1); - CHECK(p.n_in_edges(*blit) == 1); - ++blit; - // Exit of if - CHECK(blit.get_circuit_ref().n_gates() == 0); - CHECK(p.n_in_edges(*blit) == 1); - ++blit; - // Exit - CHECK(blit == p.block_end()); - } - GIVEN("While loop") { - Program p(2, 2); - p.add_op(OpType::X, uvec{0}); - p.add_op(OpType::Y, uvec{1}); - p.add_op(OpType::Measure, uvec{0, 0}); - Program whilebody(2, 2); - whilebody.add_op(OpType::H, uvec{0}); - whilebody.add_op(OpType::Measure, uvec{0, 0}); - p.append_while(Bit(0), whilebody); - p.add_op(OpType::Y, uvec{1}); - Program::BlockIterator blit = p.block_begin(); - // Initial gates - CHECK(blit.get_circuit_ref().n_gates() == 3); - ++blit; - // Empty block - CHECK(blit.get_circuit_ref().n_gates() == 0); - CHECK(!blit.get_condition()); - ++blit; - // Condition - CHECK(blit.get_condition()); - ++blit; - // Final command - CHECK(blit.get_circuit_ref().n_gates() == 1); - ++blit; - // While body - CHECK(blit.get_circuit_ref().n_gates() == 2); - ++blit; - // Exit - CHECK(blit == p.block_end()); - } - GIVEN("Appending interesting programs") { - Bit b0(0); - Bit b1(1); - Program p(2, 2); - Program ifbody(2, 2); - ifbody.add_op(OpType::X, uvec{1}); - p.append_if(b1, ifbody); - Program p2(2, 2); - Program whilebody(2, 2); - whilebody.add_op(OpType::H, uvec{0}); - whilebody.add_op(OpType::Measure, uvec{0, 0}); - p2.append_while(b0, whilebody); - p.append(p2); - Program::BlockIterator blit = p.block_begin(); - // Initial empty block for if condition - CHECK(blit.get_circuit_ref().n_gates() == 0); - CHECK(blit.get_condition() == b1); - ++blit; - // Empty block after if - CHECK(blit.get_circuit_ref().n_gates() == 0); - CHECK_FALSE(blit.get_condition()); - ++blit; - // While condition - CHECK(blit.get_circuit_ref().n_gates() == 0); - CHECK(blit.get_condition() == b0); - ++blit; - // While body - CHECK(blit.get_circuit_ref().n_gates() == 2); - ++blit; - // If body - CHECK(blit.get_circuit_ref().n_gates() == 1); - ++blit; - // Exit - CHECK(blit == p.block_end()); - } -} - -static void test_command_types_sequence( - const Program& p, const std::vector& expected_types) { - Program::CommandIterator cit = p.begin(); - for (auto type : expected_types) { - CHECK(cit->get_op_ptr()->get_type() == type); - ++cit; - } - CHECK(cit == p.end()); -} - -SCENARIO("Command iteration") { - GIVEN("An empty Program") { - Program p; - test_command_types_sequence(p, {OpType::Stop}); - } - GIVEN("A single block via add_op") { - Program p(2, 2); - p.add_op(OpType::X, uvec{0}); - p.add_op(OpType::Measure, uvec{0, 0}); - test_command_types_sequence(p, {OpType::X, OpType::Measure, OpType::Stop}); - } - GIVEN("A straight-line block sequence") { - unsigned N = 3; - Program p(2, 2); - Circuit c(2, 2); - c.add_op(OpType::X, uvec{0}); - c.add_measure(0, 0); - for (unsigned i = 0; i < N; ++i) { - p.add_block(c); - } - Program::CommandIterator cit = p.begin(); - for (unsigned i = 0; i < N; ++i) { - CHECK(cit->get_op_ptr()->get_type() == OpType::X); - ++cit; - CHECK(cit->get_op_ptr()->get_type() == OpType::Measure); - ++cit; - } - CHECK(cit->get_op_ptr()->get_type() == OpType::Stop); - ++cit; - CHECK(cit == p.end()); - } - GIVEN("Conditional execution") { - Program p(2, 2); - p.add_op(OpType::X, uvec{0}); - p.add_op(OpType::Measure, uvec{0, 0}); - Program body(2, 2); - body.add_op(OpType::X, uvec{1}); - p.append_if(Bit(0), body); - p.add_op(OpType::Z, uvec{0}); - - test_command_types_sequence( - p, {// Initial gates - OpType::X, OpType::Measure, - // Block is just a branch - OpType::Branch, - // Block AFTER the if - OpType::Label, OpType::Z, OpType::Goto, - // Body of the if - OpType::Label, OpType::X, OpType::Goto, - // Exit - OpType::Label, OpType::Stop}); - } - GIVEN("If-else") { - Program p(2, 2); - p.add_op(OpType::X, uvec{0}); - p.add_op(OpType::Measure, uvec{0, 0}); - Program ifbody(2, 2); - ifbody.add_op(OpType::X, uvec{1}); - Program elsebody(1, 1); - elsebody.add_op(OpType::Y, uvec{0}); - p.append_if_else(Bit(0), ifbody, elsebody); - p.add_op(OpType::Z, uvec{0}); - - test_command_types_sequence( - p, {// Initial gates - OpType::X, OpType::Measure, - // Block is just a branch - OpType::Branch, - // Else block - OpType::Y, - // Block after if-else - OpType::Label, OpType::Z, OpType::Goto, - // Body of the if - OpType::Label, OpType::X, OpType::Goto, - // Exit - OpType::Label, OpType::Stop}); - } - GIVEN("While loop") { - Program p(2, 2); - p.add_op(OpType::X, uvec{0}); - p.add_op(OpType::Y, uvec{1}); - p.add_op(OpType::Measure, uvec{0, 0}); - Program whilebody(2, 2); - whilebody.add_op(OpType::H, uvec{0}); - whilebody.add_op(OpType::Measure, uvec{0, 0}); - p.append_while(Bit(0), whilebody); - p.add_op(OpType::Y, uvec{1}); - - test_command_types_sequence( - p, {// Initial gates - OpType::X, OpType::Y, OpType::Measure, - // Condition - OpType::Label, OpType::Branch, - // Final command - OpType::Y, OpType::Goto, - // While body - OpType::Label, OpType::H, OpType::Measure, OpType::Goto, - // Exit - OpType::Label, OpType::Stop}); - } - GIVEN("Appending interesting programs") { - Bit b0(0); - Bit b1(1); - Program p(2, 2); - Program ifbody(2, 2); - ifbody.add_op(OpType::X, uvec{1}); - p.append_if(b1, ifbody); - Program p2(2, 2); - Program whilebody(2, 2); - whilebody.add_op(OpType::H, uvec{0}); - whilebody.add_op(OpType::Measure, uvec{0, 0}); - p2.append_while(b0, whilebody); - p.append(p2); - - test_command_types_sequence( - p, {// Initial empty block for if condition - OpType::Branch, - // Empty block after if - OpType::Label, - // While condition - OpType::Label, OpType::Branch, OpType::Goto, - // While body - OpType::Label, OpType::H, OpType::Measure, OpType::Goto, - // If body - OpType::Label, OpType::X, OpType::Goto, - // Exit - OpType::Label, OpType::Stop}); - } -} - -} // namespace test_Program -} // namespace tket diff --git a/tket/tests/test_Synthesis.cpp b/tket/tests/test_Synthesis.cpp index a8ec7cb7ac..f52a3e9904 100644 --- a/tket/tests/test_Synthesis.cpp +++ b/tket/tests/test_Synthesis.cpp @@ -757,7 +757,10 @@ SCENARIO("Testing general 1qb squash") { circ.add_op(OpType::Rz, 0.43, {0}); circ.add_op(OpType::CX, {0, 1}); Circuit copy = circ; - bool success = Transforms::rebase_HQS().apply(circ); + bool success = Transforms::rebase_factory( + {OpType::ZZMax, OpType::PhasedX, OpType::Rz}, + CircPool::CX_using_ZZMax(), CircPool::tk1_to_PhasedXRz) + .apply(circ); REQUIRE(success); OpTypeSet singleqs = {OpType::Rz, OpType::PhasedX}; success = Transforms::squash_factory(singleqs, CircPool::tk1_to_PhasedXRz) diff --git a/tket/tests/test_json.cpp b/tket/tests/test_json.cpp index beab6979e5..50567a12e2 100644 --- a/tket/tests/test_json.cpp +++ b/tket/tests/test_json.cpp @@ -570,15 +570,8 @@ SCENARIO("Test compiler pass serializations") { COMPPASSJSONTEST(DecomposeSingleQubitsTK1, DecomposeSingleQubitsTK1()) COMPPASSJSONTEST(PeepholeOptimise2Q, PeepholeOptimise2Q()) COMPPASSJSONTEST(FullPeepholeOptimise, FullPeepholeOptimise()) - COMPPASSJSONTEST(RebaseCirq, RebaseCirq()) COMPPASSJSONTEST(RebaseTket, RebaseTket()) - COMPPASSJSONTEST(RebaseHQS, RebaseHQS()) - COMPPASSJSONTEST(RebaseQuil, RebaseQuil()) - COMPPASSJSONTEST(RebaseProjectQ, RebaseProjectQ()) - COMPPASSJSONTEST(RebasePyZX, RebasePyZX()) - COMPPASSJSONTEST(RebaseUMD, RebaseUMD()) COMPPASSJSONTEST(RebaseUFR, RebaseUFR()) - COMPPASSJSONTEST(RebaseOQC, RebaseOQC()) COMPPASSJSONTEST(RemoveRedundancies, RemoveRedundancies()) COMPPASSJSONTEST(SynthesiseHQS, SynthesiseHQS()) COMPPASSJSONTEST(SynthesiseTket, SynthesiseTket()) @@ -659,22 +652,6 @@ SCENARIO("Test compiler pass serializations") { nlohmann::json j_loaded = loaded; REQUIRE(j_pp == j_loaded); } -#define COMPPASSDESERIALIZE(passname, pass) \ - GIVEN(#passname) { \ - Circuit circ = CircuitsForTesting::get().uccsd; \ - CompilationUnit cu{circ}; \ - CompilationUnit copy = cu; \ - PassPtr pp = pass; \ - nlohmann::json j_pp; \ - j_pp["pass_class"] = "StandardPass"; \ - j_pp["StandardPass"]["name"] = #passname; \ - PassPtr loaded = j_pp.get(); \ - pp->apply(cu); \ - loaded->apply(copy); \ - REQUIRE(cu.get_circ_ref() == copy.get_circ_ref()); \ - } - COMPPASSDESERIALIZE(SquashHQS, SquashHQS()) -#undef COMPPASSDESERIALIZE GIVEN("FullMappingPass") { // Sequence pass - deserializable only Circuit circ = CircuitsForTesting::get().uccsd; diff --git a/tket/tests/tkettestsfiles.cmake b/tket/tests/tkettestsfiles.cmake index ea9a347b30..b549428bb9 100644 --- a/tket/tests/tkettestsfiles.cmake +++ b/tket/tests/tkettestsfiles.cmake @@ -63,7 +63,6 @@ set(TEST_SOURCES ${TKET_TESTS_DIR}/Circuit/test_Circ.cpp ${TKET_TESTS_DIR}/Circuit/test_Symbolic.cpp ${TKET_TESTS_DIR}/Circuit/test_ThreeQubitConversion.cpp - ${TKET_TESTS_DIR}/test_Program.cpp ${TKET_TESTS_DIR}/test_CliffTableau.cpp ${TKET_TESTS_DIR}/test_UnitaryTableau.cpp ${TKET_TESTS_DIR}/test_PhasePolynomials.cpp