Skip to content

LMRP heuristic finisher #16

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

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Own stuff
build/
**/build/
Makefile
.vscode/
external/lemon/
Expand Down
7 changes: 6 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ cmake_minimum_required(VERSION 3.7)

project(majorminer)

option(MAJORMINER_BUILD_TESTS "Build majorminer test executable" ON)
option(MAJORMINER_BUILD_TESTS "Build majorminer test executable" ON)
option(MAJORMINER_BUILD_EXAMPLES "Build majorminer example executable" ON)
enable_language(C CXX)
set(CMAKE_CXX_STANDARD 20)
set(CXX_STANDARD_REQUIRED ON)
Expand Down Expand Up @@ -46,4 +47,8 @@ if ( ${MAJORMINER_BUILD_TESTS} )
add_subdirectory(test)
target_include_directories(majorminer_test PRIVATE src ${MM_INCLUDE_LIBS})
target_link_libraries(majorminer_test majorminer gtest_main)
endif()

if ( ${MAJORMINER_BUILD_EXAMPLES} )
add_subdirectory(examples)
endif()
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ cmake .. -DMAJORMINER_BUILD_TESTS=[ON|OFF] # depending on whether you want to ru
make
```

## use the C++ libary
In the [examples](examples/) folder, there is an example project that solves embedding problem and creates debug images.
There is a readme containing the output in the same folder as well.

## Libraries used in the C++-Project
#### [oneTBB](https://github.com/oneapi-src/oneTBB) (License: [Apache 2.0](https://choosealicense.com/licenses/apache-2.0/))
#### [GoogleTest](https://github.com/google/googletest) (License: [BSD 3-Clause "New" or "Revised"](https://choosealicense.com/licenses/bsd-3-clause/))
Expand Down
37 changes: 37 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
cmake_minimum_required(VERSION 3.7)

project(example_majorminer)

enable_language(C CXX)
set(CMAKE_CXX_STANDARD 20)
set(CXX_STANDARD_REQUIRED ON)
set(CMAKE_BUILD_TYPE Release)
set(MM_INCLUDES ../include/ ../src/ ../src/common/ ../src/lmrp/ ../src/evolutionary/ ../src/initial ../)
set(INCLUDE_LIBS ../external/oneTBB/include ../build/external/lemon/ ../external/lemon/ ../external/ ${MM_INCLUDES})
set(LINK_LIBS TBB::tbb lemon majorminer pthread)

# neither build tests nor tbbmalloc in oneTBB
set(TBB_TEST CACHE BOOL OFF)
set(TBBMALLOC_BUILD CACHE BOOL OFF)
set(TBB_DISABLE_HWLOC_AUTOMATIC_SEARCH CACHE BOOL OFF)

set(LEMON_ENABLE_GLPK CACHE BOOL OFF)
set(LEMON_ENABLE_ILOG CACHE BOOL OFF)
set(LEMON_ENABLE_ILOG CACHE BOOL OFF)
set(LEMON_ENABLE_COIN CACHE BOOL OFF)
set(LEMON_ENABLE_SOPLEX CACHE BOOL OFF)




if ( CMAKE_COMPILER_IS_GNUCC )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -Werror -fdiagnostics-color=always")
endif()
if ( MSVC )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /WX")
endif()

add_executable(example_majorminer example_majorminer.cpp)

target_include_directories(example_majorminer PRIVATE ${INCLUDE_LIBS})
target_link_libraries(example_majorminer ${LINK_LIBS})
55 changes: 55 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@

# Example project containing this library


## Build the example project
The project is built by default when building the root project.


## How it works
```example_majorminer.cpp``` contains the following code

```
#include <iostream>
#include <majorminer_lib.hpp>


using namespace majorminer;

int main()
{
// Generate some source graph that should be embedded
graph_t H = majorminer::generate_completegraph(8);

// Generate the hardware graph
graph_t G = majorminer::generate_chimera(3, 3);

// For debugging purposes: Get us a visualizer
ChimeraVisualizer vis{H, G, "imgs/example_majorminer/simple_example", 3, 3};

// Embedd the problem
EmbeddingSuite suite{H, G, &vis};
embedding_mapping_t mapping = suite.find_embedding();

// We can validate the embedding
EmbeddingAnalyzer analyzer{mapping};
std::cout << "Result has " << analyzer.getNbOverlaps() << " overlaps and uses "
<< analyzer.getNbUsedNodes() << " vertices." << std::endl;

return 0;
}
```

Note that ```graph_t``` is just a ```typedef``` on ```Set<std::pair<fuint32_t, fuint32_t>>```. For ```Set<>```, we use oneTBB sets, i. e. ```tbb::unordered_set<>```.

In the code, we create the source graph ```H``` and the target graph ```G```, in this case a complete graph on ```n = 8``` vertices and a perfect Chimera graph consisting of ```3x3``` unit cells, respectively. For debugging purposes, we create a visualizer for the Chimera graph that outputs an image of the embedding in each iteration and pass those three objects to the ```EmbeddingSuite``` which tries to embedd ```H``` onto ```G```. The result of type ```embedding_mapping_t``` is a ```typedef``` on an ```UnorderedMultiMap<fuint32_t, fuint32_t>```, which in turn is a ```tbb::unordered_multimap```, containing a vertex in ```H``` as key and a vertex in ```G``` as value.

The embedding might not always be disjoint and can be analyzed using the ```EmbeddingAnalyzer```.

The result of the code above might look as follows
```
Result has 0 overlaps and uses 37 vertices.
```

The images are generated in the folder ```./imgs/example_majorminer/``` and the last could look as follows
![Last iteration of the embedding process for a K_8 graph on a 3x3 Chimera graph.](../img/simple_example_44.svg)
29 changes: 29 additions & 0 deletions examples/example_majorminer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include <iostream>
#include <majorminer_lib.hpp>


using namespace majorminer;

int main()
{
// Generate some source graph that should be embedded
graph_t H = majorminer::generate_completegraph(8);

// Generate the hardware graph
graph_t G = majorminer::generate_chimera(3, 3);

// For debugging purposes: Get us a visualizer
ChimeraVisualizer vis{H, G, "imgs/example_majorminer/simple_example", 3, 3};

// Embedd the problem
EmbeddingSuite suite{H, G, &vis};
embedding_mapping_t mapping = suite.find_embedding();

// We can validate the embedding
EmbeddingAnalyzer analyzer{mapping};
std::cout << "Result has " << analyzer.getNbOverlaps() << " overlaps and uses "
<< analyzer.getNbUsedNodes() << " vertices." << std::endl;

return 0;
}

2 changes: 2 additions & 0 deletions img/simple_example_44.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions include/majorminer_lib.hpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#ifndef __MAJORMINER_MAJORMINER_LIB_HPP_
#define __MAJORMINER_MAJORMINER_LIB_HPP_

#include <majorminer_types.hpp>

#include <src/majorminer_types.hpp>
#include <src/majorminer.hpp>

#include <src/common/embedding_analyzer.hpp>
#include <src/common/graph_info.hpp>
#include <src/common/graph_gen.hpp>
#include <src/common/embedding_validator.hpp>
#include <src/common/embedding_visualizer.hpp>
#include <src/lmrp/lmrp_king_subgraph.hpp>
Expand Down
7 changes: 6 additions & 1 deletion src/common/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@
#define EIGEN_MPL2_ONLY
#define TBB_PREVIEW_CONCURRENT_LRU_CACHE 1
#define __DEBUG__ 1
#define __NONLINEAR_COST__ 1


#if __NONLINEAR_COST__ == 1
#define NONLINEAR(...) (pow(__VA_ARGS__, 2))
#else
#define NONLINEAR(...) (__VA_ARGS__)
#endif


#if __DEBUG__ == 1
Expand Down
8 changes: 8 additions & 0 deletions src/common/debug_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,11 @@ void majorminer::printEmbeddingOverlapStats(const embedding_mapping_t& mapping)
for (const auto& stat : stats) std::cout << "Source vertex " << stat.second << " is mapped onto " << stat.first << " vertices." << std::endl;
}

void majorminer::printGraph(const graph_t& graph)
{
for (const auto& p : graph)
{
std::cout << "(" << p.first << ", " << p.second << ")" << std::endl;
}
}

2 changes: 2 additions & 0 deletions src/common/debug_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ namespace majorminer
embedding_mapping_t getReverseMapping(const embedding_mapping_t& mapping);

void printEmbeddingOverlapStats(const embedding_mapping_t& mapping);

void printGraph(const graph_t& graph);
}

#endif
11 changes: 7 additions & 4 deletions src/common/embedding_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ void EmbeddingManager::mapNode(fuint32_t node, fuint32_t targetNode)
{
if (!m_changesToPropagate.empty()) synchronize();
m_lastNode = node;
DEBUG(std::cout << node << " -> " << targetNode << std::endl;)
// DEBUG(std::cout << node << " -> " << targetNode << std::endl;)

m_nodesOccupied.insert(targetNode);
m_mapping.insert(std::make_pair(node, targetNode));
Expand All @@ -32,17 +32,17 @@ void EmbeddingManager::mapNode(fuint32_t node, const nodeset_t& targetNodes)
{
if (!m_changesToPropagate.empty()) synchronize();
m_lastNode = node;
DEBUG(OUT_S << node << " -> {";)
// DEBUG(OUT_S << node << " -> {";)
for(auto targetNode : targetNodes)
{
DEBUG(OUT_S << " " << targetNode;)
//DEBUG(OUT_S << " " << targetNode;)
m_nodesOccupied.insert(targetNode);
m_mapping.insert(std::make_pair(node, targetNode));
m_reverseMapping.insert(std::make_pair(targetNode, node));
m_targetNodesRemaining.unsafe_extract(targetNode);

}
DEBUG(OUT_S << " }" << std::endl;)
// DEBUG(OUT_S << " }" << std::endl;)
m_state.mapNode(node, targetNodes);
}
#undef ADJUST
Expand Down Expand Up @@ -123,6 +123,7 @@ void EmbeddingManager::synchronize()
auto& sourceFreeNeighbors = m_state.getSourceFreeNeighbors();
auto& nodesOccupied = m_state.getNodesOccupied();
auto& targetNodesRemaining = m_state.getRemainingTargetNodes();
auto& revCount = m_state.getRevMappingCount();
while(!m_changesToPropagate.empty() && m_nbCommitsRemaining > 0)
{
bool success = m_changesToPropagate.try_pop(change);
Expand All @@ -131,13 +132,15 @@ void EmbeddingManager::synchronize()
{
case ChangeType::DEL_MAPPING:
{
revCount[change.m_b]--;
eraseSinglePair(mapping, change.m_a, change.m_b);
eraseSinglePair(revMapping, change.m_b, change.m_a);
m_changeHistory[change.m_a].m_timestampNodeChanged = m_time.load();
break;
}
case ChangeType::INS_MAPPING:
{
revCount[change.m_b]++;
mapping.insert(std::make_pair(change.m_a, change.m_b));
revMapping.insert(std::make_pair(change.m_b, change.m_a));
m_changeHistory[change.m_a].m_timestampNodeChanged = m_time.load();
Expand Down
30 changes: 20 additions & 10 deletions src/common/embedding_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,20 @@ void EmbeddingState::initialize()
m_numberSourceVertices = m_nodesRemaining.size();
}

fint32_t EmbeddingState::getReverseMappedCnt(vertex_t target) const
{
auto findIt = m_reverseCount.find(target);
return findIt != m_reverseCount.end() ? findIt->second : 0;
}

fuint32_t EmbeddingState::getTrivialNode()
{ // TODO: assert
auto node = *m_nodesRemaining.begin();
m_nodesRemaining.unsafe_erase(m_nodesRemaining.begin());
return node.first;
}

bool EmbeddingState::removeRemainingNode(fuint32_t node)
bool EmbeddingState::removeRemainingNode(vertex_t node)
{
if (!m_nodesRemaining.contains(node)) return false;
m_nodesRemaining.unsafe_erase(node);
Expand All @@ -48,27 +54,29 @@ void EmbeddingState::unmapNode(vertex_t sourceVertex)
auto range = m_mapping.equal_range(sourceVertex);
for (auto mappedIt = range.first; mappedIt != range.second; ++mappedIt)
{
m_reverseCount[mappedIt->second]--;
eraseSinglePair(m_reverseMapping, mappedIt->second, mappedIt->first);
}
m_mapping.unsafe_erase(sourceVertex);
}

void EmbeddingState::updateNeededNeighbors(fuint32_t node)
void EmbeddingState::updateNeededNeighbors(vertex_t node)
{
fuint32_t nbNodes = 0;
iterateSourceGraphAdjacent(node, [&, this](fuint32_t adjacentSource){
iterateSourceGraphAdjacent(node, [&, this](vertex_t adjacentSource){
if (isNodeMapped(adjacentSource))
{
nbNodes++; m_sourceNeededNeighbors[adjacentSource]--;
nbNodes++;
m_sourceNeededNeighbors[adjacentSource]--;
}
});
m_sourceNeededNeighbors[node] -= nbNodes;
}


void EmbeddingState::updateConnections(fuint32_t node, PrioNodeQueue& nodesToProcess)
void EmbeddingState::updateConnections(vertex_t node, PrioNodeQueue& nodesToProcess)
{
iterateSourceGraphAdjacent(node, [&](fuint32_t adjacent){
iterateSourceGraphAdjacent(node, [&](vertex_t adjacent){
auto findIt = m_nodesRemaining.find(adjacent);
if (findIt != m_nodesRemaining.end())
{
Expand All @@ -78,34 +86,36 @@ void EmbeddingState::updateConnections(fuint32_t node, PrioNodeQueue& nodesToPro
});
}

int EmbeddingState::numberFreeNeighborsNeeded(fuint32_t sourceNode) const
int EmbeddingState::numberFreeNeighborsNeeded(vertex_t sourceNode) const
{ // TODO: rework
// std::cout << "Source node " << sourceNode << " needs " << m_sourceNeededNeighbors[sourceNode].load() << " neighbors and has " << m_sourceFreeNeighbors[sourceNode].load() << std::endl;
auto it = m_sourceNeededNeighbors.find(sourceNode);
return 2 * (it == m_sourceNeededNeighbors.end() ? 0 : it->second.load())
- std::max(getSourceNbFreeNeighbors(sourceNode), 0);
}

int EmbeddingState::getSourceNbFreeNeighbors(fuint32_t sourceNode) const
int EmbeddingState::getSourceNbFreeNeighbors(vertex_t sourceNode) const
{
auto it = m_sourceFreeNeighbors.find(sourceNode);
return it == m_sourceFreeNeighbors.end() ? 0 : it->second.load();
}


void EmbeddingState::mapNode(fuint32_t source, fuint32_t targetNode)
void EmbeddingState::mapNode(vertex_t source, vertex_t targetNode)
{
m_reverseCount[targetNode]++;
m_nodesOccupied.insert(targetNode);
m_mapping.insert(std::make_pair(source, targetNode));
m_reverseMapping.insert(std::make_pair(targetNode, source));
m_targetNodesRemaining.unsafe_extract(targetNode);
removeRemainingNode(source);
}

void EmbeddingState::mapNode(fuint32_t source, const nodeset_t& targets)
void EmbeddingState::mapNode(vertex_t source, const nodeset_t& targets)
{
for (auto targetNode : targets)
{
m_reverseCount[targetNode]++;
m_nodesOccupied.insert(targetNode);
m_mapping.insert(std::make_pair(source, targetNode));
m_reverseMapping.insert(std::make_pair(targetNode, source));
Expand Down
4 changes: 4 additions & 0 deletions src/common/embedding_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ namespace majorminer

ThreadManager& getThreadManager() { return m_threadManager; }
void setLMRPSubgraphGenerator(LMRPSubgraph* gen) { m_lmrpGen = gen; }
fint32_t getReverseMappedCnt(vertex_t target) const;
UnorderedMap<vertex_t, fint32_t>& getRevMappingCount() { return m_reverseCount; }

public: // getter
const graph_t* getSourceGraph() const override { return m_sourceGraph; }
Expand Down Expand Up @@ -88,6 +90,8 @@ namespace majorminer
LMRPSubgraph* m_lmrpGen;

ThreadManager m_threadManager;

UnorderedMap<vertex_t, fint32_t> m_reverseCount;
};

}
Expand Down
2 changes: 1 addition & 1 deletion src/common/graph_gen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ graph_t majorminer::generate_king(fuint32_t rows, fuint32_t cols)
}


graph_t majorminer::import_graph(std::string filename)
graph_t majorminer::import_graph(const std::string& filename)
{
std::ifstream file(filename);
if (!file.is_open()) throw std::runtime_error("File not found.");
Expand Down
Loading