Skip to content

Commit

Permalink
Feature/TokenSwapping (#94)
Browse files Browse the repository at this point in the history
* Copy TokenSwapping CodeBase, update CMakeLists.txt

* Add TokenSwapping tests

* Update GraphTests to use TokenSwapping RNG

* Remove "class RNG;"

* Add cpp files to compilation
  • Loading branch information
sjdilkes authored Oct 25, 2021
1 parent 3c84f72 commit 39f46d3
Show file tree
Hide file tree
Showing 119 changed files with 18,727 additions and 24 deletions.
40 changes: 40 additions & 0 deletions tket/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ set(TKET_OPS_DIR ${TKET_SRC_DIR}/Ops)
set(TKET_GATE_DIR ${TKET_SRC_DIR}/Gate)
set(TKET_SIMULATION_DIR ${TKET_SRC_DIR}/Simulation)
set(TKET_ROUTING_DIR ${TKET_SRC_DIR}/Routing)
set(TKET_TOKEN_SWAPPING_DIR ${TKET_SRC_DIR}/TokenSwapping)
set(TKET_TRANSFORM_DIR ${TKET_SRC_DIR}/Transformations)
set(TKET_CHARACTERISATION_DIR ${TKET_SRC_DIR}/Characterisation)
set(TKET_PREDS_DIR ${TKET_SRC_DIR}/Predicates)
Expand Down Expand Up @@ -156,6 +157,45 @@ set(TKET_SOURCES
${TKET_GRAPH_DIR}/ArticulationPoints.cpp
${TKET_GRAPH_DIR}/UIDConnectivity.cpp

# Token swapping
${TKET_TOKEN_SWAPPING_DIR}/TSAUtils/DebugFunctions.cpp
${TKET_TOKEN_SWAPPING_DIR}/TSAUtils/DistanceFunctions.cpp
${TKET_TOKEN_SWAPPING_DIR}/TSAUtils/GeneralFunctions.cpp
${TKET_TOKEN_SWAPPING_DIR}/TSAUtils/SwapFunctions.cpp
${TKET_TOKEN_SWAPPING_DIR}/TSAUtils/VertexMappingFunctions.cpp
${TKET_TOKEN_SWAPPING_DIR}/TSAUtils/VertexSwapResult.cpp
${TKET_TOKEN_SWAPPING_DIR}/ArchitectureMapping.cpp
${TKET_TOKEN_SWAPPING_DIR}/BestFullTsa.cpp
${TKET_TOKEN_SWAPPING_DIR}/CyclesCandidateManager.cpp
${TKET_TOKEN_SWAPPING_DIR}/CyclesGrowthManager.cpp
${TKET_TOKEN_SWAPPING_DIR}/CyclesPartialTsa.cpp
${TKET_TOKEN_SWAPPING_DIR}/CyclicShiftCostEstimate.cpp
${TKET_TOKEN_SWAPPING_DIR}/DistancesFromArchitecture.cpp
${TKET_TOKEN_SWAPPING_DIR}/DistancesInterface.cpp
${TKET_TOKEN_SWAPPING_DIR}/DynamicTokenTracker.cpp
${TKET_TOKEN_SWAPPING_DIR}/HybridTsa00.cpp
${TKET_TOKEN_SWAPPING_DIR}/main_entry_functions.cpp
${TKET_TOKEN_SWAPPING_DIR}/NeighboursFromArchitecture.cpp
${TKET_TOKEN_SWAPPING_DIR}/NeighboursInterface.cpp
${TKET_TOKEN_SWAPPING_DIR}/PartialTsaInterface.cpp
${TKET_TOKEN_SWAPPING_DIR}/PathFinderInterface.cpp
${TKET_TOKEN_SWAPPING_DIR}/RiverFlowPathFinder.cpp
${TKET_TOKEN_SWAPPING_DIR}/RNG.cpp
${TKET_TOKEN_SWAPPING_DIR}/SwapListOptimiser.cpp
${TKET_TOKEN_SWAPPING_DIR}/TrivialTSA.cpp
${TKET_TOKEN_SWAPPING_DIR}/VectorListHybridSkeleton.cpp

# Token swapping table lookup
${TKET_TOKEN_SWAPPING_DIR}/TableLookup/CanonicalRelabelling.cpp
${TKET_TOKEN_SWAPPING_DIR}/TableLookup/ExactMappingLookup.cpp
${TKET_TOKEN_SWAPPING_DIR}/TableLookup/FilteredSwapSequences.cpp
${TKET_TOKEN_SWAPPING_DIR}/TableLookup/PartialMappingLookup.cpp
${TKET_TOKEN_SWAPPING_DIR}/TableLookup/SwapConversion.cpp
${TKET_TOKEN_SWAPPING_DIR}/TableLookup/SwapListSegmentOptimiser.cpp
${TKET_TOKEN_SWAPPING_DIR}/TableLookup/SwapListTableOptimiser.cpp
${TKET_TOKEN_SWAPPING_DIR}/TableLookup/SwapSequenceTable.cpp
${TKET_TOKEN_SWAPPING_DIR}/TableLookup/VertexMapResizing.cpp

# Transformations
${TKET_TRANSFORM_DIR}/Combinator.cpp
${TKET_TRANSFORM_DIR}/Rebase.cpp
Expand Down
70 changes: 70 additions & 0 deletions tket/src/TokenSwapping/ArchitectureMapping.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#include "ArchitectureMapping.hpp"

#include <sstream>
#include <stdexcept>

namespace tket {
namespace tsa_internal {

ArchitectureMapping::ArchitectureMapping(const Architecture& arch)
: m_arch(arch) {
const auto uids = arch.get_all_uids();
m_vertex_to_node_mapping.reserve(uids.size());
for (const UnitID& uid : uids) {
m_vertex_to_node_mapping.emplace_back(Node(uid));
}

for (size_t ii = 0; ii < m_vertex_to_node_mapping.size(); ++ii) {
const auto& node = m_vertex_to_node_mapping[ii];
{
const auto citer = m_node_to_vertex_mapping.find(node);
if (citer != m_node_to_vertex_mapping.cend()) {
std::stringstream ss;
ss << "Duplicate node " << node.repr() << " at vertices "
<< citer->second << ", " << ii;
throw std::runtime_error(ss.str());
}
}
m_node_to_vertex_mapping[node] = ii;
}
}

size_t ArchitectureMapping::number_of_vertices() const {
return m_vertex_to_node_mapping.size();
}

const Node& ArchitectureMapping::get_node(size_t vertex) const {
const auto num_vertices = number_of_vertices();
if (vertex >= num_vertices) {
std::stringstream ss;
ss << "get_node: invalid vertex " << vertex << " (architecture only has "
<< num_vertices << " vertices)";
throw std::runtime_error(ss.str());
}
return m_vertex_to_node_mapping[vertex];
}

size_t ArchitectureMapping::get_vertex(const Node& node) const {
const auto citer = m_node_to_vertex_mapping.find(node);
if (citer == m_node_to_vertex_mapping.cend()) {
std::stringstream ss;
ss << "get_vertex: node " << node.repr() << " has no vertex number";
throw std::runtime_error(ss.str());
}
return citer->second;
}

const Architecture& ArchitectureMapping::get_architecture() const {
return m_arch;
}

std::vector<Swap> ArchitectureMapping::get_edges() const {
std::vector<Swap> edges;
for (auto [node1, node2] : m_arch.get_connections_vec()) {
edges.emplace_back(get_swap(get_vertex(node1), get_vertex(node2)));
}
return edges;
}

} // namespace tsa_internal
} // namespace tket
78 changes: 78 additions & 0 deletions tket/src/TokenSwapping/ArchitectureMapping.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#ifndef _TKET_TokenSwapping_ArchitectureMapping_H_
#define _TKET_TokenSwapping_ArchitectureMapping_H_

#include "Architecture/Architectures.hpp"
#include "TSAUtils/SwapFunctions.hpp"

namespace tket {
namespace tsa_internal {

/** For mapping between nodes in an architecture and size_t vertex numbers.
* The vertex numbers are merely the indices of each Node
* within the vector returned by the get_all_uids() function.
*
* For now, we don't want to use Node objects as (1) this would make
* TokenSwapping dependent on other parts of Tket and hence less modular,
* (2) it would probably slow things down significantly because Nodes
* contain extra data, like vectors and strings, which are relatively
* expensive to copy; vertices get copied and moved around many times
* by any TSA.
*
* TODO: it would be better to use a Vertex wrapper class
* instead of raw size_t. (Also, might change to unsigned instead of size_t).
*/
class ArchitectureMapping {
public:
/** The object must remain valid and unchanged
* throughout the life of this object.
* @param arch The finished Architecture object, must remain valid
* for the lifetime of this object.
*/
explicit ArchitectureMapping(const Architecture& arch);

/** Convenient reference to the Architecture object we used
* to construct this ArchitectureMapping.
*/
const Architecture& get_architecture() const;

/** The number of vertices in the Architecture.
* @return The number of vertices
*/
size_t number_of_vertices() const;

/** Get the newly created vertex assigned to the node.
* Throws if the node is invalid.
* @param node The node within the original Architecture object
* @return The newly created vertex representing this node
*/
size_t get_vertex(const Node& node) const;

/** Reverse of "get_vertex", throws if the vertex is invalid.
* @param vertex The vertex created by this ArchitectureMapping object.
* @return The node corresponding to this vertex.
*/
const Node& get_node(size_t vertex) const;

/** Get the edges using the vertices created by this ArchitectureMapping
* object. The vertex numbers, of course, do not necessarily match with
* the Node uids of the underlying architecture object
* (that's why we have a mapping).
* @return The vector of edges in the architecture, using the new
* vertex numbers.
*/
std::vector<Swap> get_edges() const;

private:
/// Store a reference to the Architecture passed into the constructor.
const Architecture& m_arch;

/// Element i is simply the node corresponding to vertex i.
node_vector_t m_vertex_to_node_mapping;

/// Reverse of m_vertex_to_node_mapping; look up the index of a node.
std::map<Node, size_t> m_node_to_vertex_mapping;
};

} // namespace tsa_internal
} // namespace tket
#endif
52 changes: 52 additions & 0 deletions tket/src/TokenSwapping/BestFullTsa.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#include "BestFullTsa.hpp"

#include "DistancesFromArchitecture.hpp"
#include "NeighboursFromArchitecture.hpp"
#include "RiverFlowPathFinder.hpp"
#include "TableLookup/VertexMapResizing.hpp"

namespace tket {
namespace tsa_internal {

BestFullTsa::BestFullTsa() { m_name = "BestFullTsa"; }

HybridTsa00& BestFullTsa::get_hybrid_tsa_for_testing() { return m_hybrid_tsa; }

void BestFullTsa::append_partial_solution(
SwapList& swaps, VertexMapping& vertex_mapping,
const ArchitectureMapping& arch_mapping) {
DistancesFromArchitecture distances(arch_mapping);
NeighboursFromArchitecture neighbours(arch_mapping);
RiverFlowPathFinder path_finder(distances, neighbours, m_rng);
m_rng.set_seed();
append_partial_solution(
swaps, vertex_mapping, distances, neighbours, path_finder);
}

void BestFullTsa::append_partial_solution(
SwapList& swaps, VertexMapping& vertex_mapping,
DistancesInterface& distances, NeighboursInterface& neighbours,
PathFinderInterface& path_finder) {
auto vm_copy = vertex_mapping;

m_hybrid_tsa.append_partial_solution(
swaps, vm_copy, distances, neighbours, path_finder);

// Still subject to experimentation, but this seems the best
m_swap_list_optimiser.optimise_pass_with_zero_travel(swaps);
m_swap_list_optimiser.optimise_pass_with_token_tracking(swaps);
m_swap_list_optimiser.optimise_pass_remove_empty_swaps(swaps, vertex_mapping);
m_swap_list_optimiser.full_optimise(swaps, vertex_mapping);

VertexMapResizing map_resizing(neighbours);
std::set<size_t> vertices_with_tokens_at_start;
for (const auto& entry : vertex_mapping) {
vertices_with_tokens_at_start.insert(entry.first);
}
m_table_optimiser.optimise(
vertices_with_tokens_at_start, map_resizing, swaps,
m_swap_list_optimiser);
}

} // namespace tsa_internal
} // namespace tket
68 changes: 68 additions & 0 deletions tket/src/TokenSwapping/BestFullTsa.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#ifndef _TKET_TokenSwapping_BestFullTsa_H_
#define _TKET_TokenSwapping_BestFullTsa_H_
#include "ArchitectureMapping.hpp"
#include "HybridTsa00.hpp"
#include "RNG.hpp"
#include "SwapListOptimiser.hpp"
#include "TableLookup/SwapListTableOptimiser.hpp"

namespace tket {
namespace tsa_internal {

/** To enable easier experimentation, keep this up-to-date with the best
* end-to-end known default options, but also make it possible to change
* the options.
* Also include the best known postprocessing swap list optimisations.
*/
class BestFullTsa : public PartialTsaInterface {
public:
BestFullTsa();

/** We emphasise that, unlike the general PartialTsaInterface, the solution
* returned is complete, AND includes all known swap list optimisations.
* Warning: unlike most PartialTsaInterface objects, the vertex_mapping
* is NOT updated. (There's no point for a full TSA).
* @param swaps The list of swaps to append to (does not clear first).
* @param vertex_mapping The current desired mapping, giving (current source
* vertex)->(target vertex) mappings. NOT updated at the end.
* @param distances An object to calculate distances between vertices.
* @param neighbours An object to calculate adjacent vertices to any given
* vertex.
* @param path_finder An object to calculate a shortest path between any
* pair of vertices. (Of course, paths might not be unique if the graph
* is not a tree).
*/
virtual void append_partial_solution(
SwapList& swaps, VertexMapping& vertex_mapping,
DistancesInterface& distances, NeighboursInterface& neighbours,
PathFinderInterface& path_finder) override;

/** Wrapper around the main append_partial_solution function, but constructing
* and using the best known PathFinderInterface object. The DistancesInterface
* and NeighboursInterface objects will automatically be constructed.
* @param swaps The list of swaps to append to.
* @param vertex_mapping The current desired mapping. Will be updated with
* the new added swaps.
* @param arch_mapping An ArchitectureMapping object, which knows the graph,
* how to do Node <-> vertex size_t conversions, etc.
*/
void append_partial_solution(
SwapList& swaps, VertexMapping& vertex_mapping,
const ArchitectureMapping& arch_mapping);

/** For experiments, provide access to the internal stored TSA object. This
* function may be deleted later!
* @return Reference to the internal stored TSA object.
*/
HybridTsa00& get_hybrid_tsa_for_testing();

private:
HybridTsa00 m_hybrid_tsa;
SwapListOptimiser m_swap_list_optimiser;
SwapListTableOptimiser m_table_optimiser;
RNG m_rng;
};

} // namespace tsa_internal
} // namespace tket
#endif
Loading

0 comments on commit 39f46d3

Please sign in to comment.