Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/TokenSwapping #94

Merged
merged 5 commits into from
Oct 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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