Refactoring. Saving intermediate states during drm

This commit is contained in:
iasonmanolas 2021-08-06 14:35:28 +03:00
parent 922b525fbe
commit 21d79f07aa
11 changed files with 412 additions and 233 deletions

View File

@ -54,7 +54,6 @@ download_project(PROJ TBB
option(TBB_BUILD_TESTS "Build TBB tests and enable testing infrastructure" OFF) option(TBB_BUILD_TESTS "Build TBB tests and enable testing infrastructure" OFF)
add_subdirectory(${TBB_SOURCE_DIR} ${TBB_BINARY_DIR}) add_subdirectory(${TBB_SOURCE_DIR} ${TBB_BINARY_DIR})
link_directories(${TBB_BINARY_DIR}) link_directories(${TBB_BINARY_DIR})
message(${TBB_BINARY_DIR})
###Eigen 3 NOTE: Eigen is required on the system the code is ran ###Eigen 3 NOTE: Eigen is required on the system the code is ran
@ -77,7 +76,7 @@ target_include_directories(${PROJECT_NAME}
) )
if(${USE_POLYSCOPE}) if(${USE_POLYSCOPE})
target_link_libraries(${PROJECT_NAME} Eigen3::Eigen matplot polyscope glad ThreedBeamFEA ${TBB_BINARY_DIR}/libtbb_static.a pthread) target_link_libraries(${PROJECT_NAME} Eigen3::Eigen matplot polyscope glad ThreedBeamFEA tbb pthread)
else() else()
target_link_libraries(${PROJECT_NAME} -static Eigen3::Eigen matplot ThreedBeamFEA ${TBB_BINARY_DIR}/libtbb_static.a pthread) target_link_libraries(${PROJECT_NAME} -static Eigen3::Eigen matplot ThreedBeamFEA ${TBB_BINARY_DIR}/libtbb_static.a pthread)
endif() endif()

View File

@ -32,14 +32,10 @@ public:
fs_.clear(std::cout.rdstate()); fs_.clear(std::cout.rdstate());
fs_.basic_ios<char>::rdbuf(std::cout.rdbuf()); fs_.basic_ios<char>::rdbuf(std::cout.rdbuf());
} else { } else {
if (!std::filesystem::exists( if (!std::filesystem::exists(std::filesystem::path(filename))) {
std::filesystem::path("../OptimizationResults") std::ofstream outfile(filename);
.append("statistics.csv"))) { outfile.close();
std::ofstream outfile(std::filesystem::path("../OptimizationResults") }
.append("statistics.csv")
.string());
outfile.close();
}
overwrite ? fs_.open(filename, std::ios::trunc) overwrite ? fs_.open(filename, std::ios::trunc)
: fs_.open(filename, std::ios::app); : fs_.open(filename, std::ios::app);
} }

View File

@ -1030,11 +1030,6 @@ void DRMSimulationModel::updateResidualForcesOnTheFly(
} }
pMesh->previousTotalResidualForcesNorm = pMesh->totalResidualForcesNorm; pMesh->previousTotalResidualForcesNorm = pMesh->totalResidualForcesNorm;
pMesh->totalResidualForcesNorm = totalResidualForcesNorm; pMesh->totalResidualForcesNorm = totalResidualForcesNorm;
if (mSettings.beVerbose) {
if (minTotalResidualForcesNorm > pMesh->totalResidualForcesNorm) {
minTotalResidualForcesNorm = pMesh->totalResidualForcesNorm;
}
}
pMesh->averageResidualForcesNorm = totalResidualForcesNorm / pMesh->VN(); pMesh->averageResidualForcesNorm = totalResidualForcesNorm / pMesh->VN();
// pMesh->averageResidualForcesNorm = sumOfResidualForces.norm() / pMesh->VN(); // pMesh->averageResidualForcesNorm = sumOfResidualForces.norm() / pMesh->VN();
@ -2277,6 +2272,17 @@ SimulationResults DRMSimulationModel::executeSimulation(const std::shared_ptr<Si
break; break;
} }
if (minTotalResidualForcesNorm > pMesh->totalResidualForcesNorm) {
minTotalResidualForcesNorm = pMesh->totalResidualForcesNorm;
static int lastSavedStep = mCurrentSimulationStep;
if (mSettings.saveIntermediateBestStates.has_value()
&& mSettings.saveIntermediateBestStates.value()
&& mCurrentSimulationStep - lastSavedStep > 20000) {
lastSavedStep = mCurrentSimulationStep;
computeResults(pJob).save("./IntermediateResults_" + pJob->getLabel());
}
}
//normalized sum of displacements //normalized sum of displacements
// double sumOfDisplacementsNorm = 0; // double sumOfDisplacementsNorm = 0;
// for (size_t vi = 0; vi < pMesh->VN(); vi++) { // for (size_t vi = 0; vi < pMesh->VN(); vi++) {
@ -2693,6 +2699,16 @@ void DRMSimulationModel::Settings::save(const std::filesystem::path &folderPath)
json[jsonLabels.linearGuessForceScaleFactor] = linearGuessForceScaleFactor.value(); json[jsonLabels.linearGuessForceScaleFactor] = linearGuessForceScaleFactor.value();
} }
// if (intermediateResultsSaveStep.has_value()) {
// json[GET_VARIABLE_NAME(intermediateResultsSaveStep)] = intermediateResultsSaveStep.value();
// }
if (saveIntermediateBestStates.has_value()) {
json[GET_VARIABLE_NAME(saveIntermediateBestStates)] = saveIntermediateBestStates.value()
? "true"
: "false";
}
const std::string jsonFilename = "drmSettings.json"; const std::string jsonFilename = "drmSettings.json";
std::ofstream jsonFile(std::filesystem::path(folderPath).append(jsonFilename)); std::ofstream jsonFile(std::filesystem::path(folderPath).append(jsonFilename));
jsonFile << json; jsonFile << json;
@ -2756,5 +2772,16 @@ bool DRMSimulationModel::Settings::load(const std::filesystem::path &jsonFilePat
linearGuessForceScaleFactor = json.at(jsonLabels.linearGuessForceScaleFactor); linearGuessForceScaleFactor = json.at(jsonLabels.linearGuessForceScaleFactor);
} }
// if (json.contains(GET_VARIABLE_NAME(intermediateResultsSaveStep))) {
// intermediateResultsSaveStep = json.at(GET_VARIABLE_NAME(intermediateResultsSaveStep));
// }
if (json.contains(GET_VARIABLE_NAME(saveIntermediateBestStates))) {
saveIntermediateBestStates = json.at(GET_VARIABLE_NAME(saveIntermediateBestStates))
== "true"
? true
: false;
}
return true; return true;
} }

View File

@ -45,6 +45,8 @@ public:
std::optional<double> totalTranslationalKineticEnergyThreshold; std::optional<double> totalTranslationalKineticEnergyThreshold;
std::optional<double> averageResidualForcesCriterionThreshold; std::optional<double> averageResidualForcesCriterionThreshold;
std::optional<double> linearGuessForceScaleFactor; std::optional<double> linearGuessForceScaleFactor;
// std::optional<int> intermediateResultsSaveStep;
std::optional<bool> saveIntermediateBestStates;
Settings() {} Settings() {}
void save(const std::filesystem::path &folderPath) const; void save(const std::filesystem::path &folderPath) const;
bool load(const std::filesystem::path &filePath); bool load(const std::filesystem::path &filePath);

View File

@ -195,6 +195,7 @@ public:
bool load(const std::string &jsonFilename, const bool &shouldLoadMesh = true) bool load(const std::string &jsonFilename, const bool &shouldLoadMesh = true)
{ {
std::cout << jsonFilename << std::endl;
label = "empty_job"; label = "empty_job";
constrainedVertices.clear(); constrainedVertices.clear();
nodalExternalForces.clear(); nodalExternalForces.clear();
@ -256,8 +257,8 @@ public:
if (json.contains(jsonLabels.nodalForces)) { if (json.contains(jsonLabels.nodalForces)) {
auto f = auto f =
json[jsonLabels.nodalForces].get<std::unordered_map<VertexIndex, std::array<double, 6>>>(); json[jsonLabels.nodalForces].get<std::unordered_map<VertexIndex, std::array<double, 6>>>();
for (const auto &forces : f) { for (const auto &force : f) {
nodalExternalForces[forces.first] = Vector6d(forces.second); nodalExternalForces[force.first] = Vector6d(force.second);
} }
if (beVerbose) { if (beVerbose) {
std::cout << "Loaded forces. Number of forces found:" << nodalExternalForces.size() std::cout << "Loaded forces. Number of forces found:" << nodalExternalForces.size()
@ -345,6 +346,7 @@ json[jsonLabels.meshFilename]= std::filesystem::relative(std::filesystem::path(m
} }
std::ofstream jsonFile(jsonFilename); std::ofstream jsonFile(jsonFilename);
jsonFile << json; jsonFile << json;
jsonFile.close();
// std::cout << "Saved simulation job as:" << jsonFilename << std::endl; // std::cout << "Saved simulation job as:" << jsonFilename << std::endl;
return returnValue; return returnValue;
@ -518,9 +520,12 @@ struct SimulationResults
const std::string filename(getLabel() + "_displacements.eigenBin"); const std::string filename(getLabel() + "_displacements.eigenBin");
Eigen::MatrixXd m = Utilities::toEigenMatrix(displacements); Eigen::MatrixXd m = Utilities::toEigenMatrix(displacements);
Eigen::write_binary(std::filesystem::path(outputFolderPath).append(filename).string(), m); const std::filesystem::path resultsFolderPath(
std::filesystem::path(outputFolder).append("Results"));
std::filesystem::create_directories(resultsFolderPath);
Eigen::write_binary(std::filesystem::path(resultsFolderPath).append(filename).string(), m);
saveDeformedModel(outputFolderPath.string()); saveDeformedModel(resultsFolderPath.string());
} }
// The comparison of the results happens comparing the 6-dof nodal // The comparison of the results happens comparing the 6-dof nodal

View File

@ -1,11 +1,12 @@
#include "topologyenumerator.hpp" #include "topologyenumerator.hpp"
#include <algorithm> #include <algorithm>
#include <boost/graph/biconnected_components.hpp>
#include <iostream> #include <iostream>
#include <math.h> #include <math.h>
#include <numeric> #include <numeric>
#include <unordered_set> #include <unordered_set>
const bool debugIsOn{true}; const bool debugIsOn{false};
const bool savePlyFiles{true}; const bool savePlyFiles{true};
// size_t binomialCoefficient(size_t n, size_t m) { // size_t binomialCoefficient(size_t n, size_t m) {
@ -123,7 +124,7 @@ void TopologyEnumerator::computeValidPatterns(const std::vector<size_t> &reduced
// statistics.numberOfValidEdges = validEdges.size(); // statistics.numberOfValidEdges = validEdges.size();
// Find pairs of intersecting edges // Find pairs of intersecting edges
std::unordered_map<size_t, std::unordered_set<size_t>> intersectingEdges const std::unordered_map<size_t, std::unordered_set<size_t>> intersectingEdges
= patternAllValidEdges.getIntersectingEdges(statistics.numberOfIntersectingEdgePairs); = patternAllValidEdges.getIntersectingEdges(statistics.numberOfIntersectingEdgePairs);
if (debugIsOn) { if (debugIsOn) {
auto intersectingEdgesPath = std::filesystem::path(resultsPath) auto intersectingEdgesPath = std::filesystem::path(resultsPath)
@ -170,19 +171,19 @@ void TopologyEnumerator::computeValidPatterns(const std::vector<size_t> &reduced
// std::filesystem::path(resultsPath).append("patterns.patt")); // std::filesystem::path(resultsPath).append("patterns.patt"));
// } // }
if (numberOfDesiredEdges == -1) { if (numberOfDesiredEdges == -1) {
for (size_t numberOfEdges = 2; numberOfEdges < validEdges.size(); numberOfEdges++) { for (size_t numberOfEdges = 2; numberOfEdges <= validEdges.size(); numberOfEdges++) {
std::cout << "Computing " + setupString << " with " << numberOfEdges << " edges." std::cout << "Computing " + setupString << " with " << numberOfEdges << " edges."
<< std::endl; << std::endl;
auto perEdgeResultPath = std::filesystem::path(resultsPath) auto perEdgeResultPath = std::filesystem::path(resultsPath)
.append(std::to_string(numberOfEdges)); .append(std::to_string(numberOfEdges));
if (std::filesystem::exists(perEdgeResultPath)) { if (std::filesystem::exists(perEdgeResultPath)) {
if (debugIsOn) { // if (debugIsOn) {
std::filesystem::remove_all(perEdgeResultPath); std::filesystem::remove_all(perEdgeResultPath);
} else { // } else {
continue; // continue;
} // }
} }
std::filesystem::create_directory(perEdgeResultPath); std::filesystem::create_directory(perEdgeResultPath);
computeValidPatterns(numberOfNodesPerSlot, computeValidPatterns(numberOfNodesPerSlot,
@ -434,7 +435,7 @@ void TopologyEnumerator::computeValidPatterns(
// std::string previousPatternBinaryRepresentation(validEdges.size(),'0'); // std::string previousPatternBinaryRepresentation(validEdges.size(),'0');
size_t patternIndex = 0; size_t patternIndex = 0;
bool validPatternsExist = false; bool validPatternsExist = false;
const bool exportTilledPattern = false; const bool exportTilledPattern = debugIsOn;
const bool saveCompressedFormat = false; const bool saveCompressedFormat = false;
do { do {
patternIndex++; patternIndex++;
@ -479,6 +480,7 @@ void TopologyEnumerator::computeValidPatterns(
const bool tiledPatternHasEdgesWithAngleSmallerThanThreshold const bool tiledPatternHasEdgesWithAngleSmallerThanThreshold
= patternGeometry.hasAngleSmallerThanThreshold(numberOfNodesPerSlot, 15); = patternGeometry.hasAngleSmallerThanThreshold(numberOfNodesPerSlot, 15);
if (tiledPatternHasEdgesWithAngleSmallerThanThreshold) { if (tiledPatternHasEdgesWithAngleSmallerThanThreshold) {
statistics.numberOfPatternsViolatingAngleThreshold++;
if (debugIsOn /*|| savePlyFiles*/) { if (debugIsOn /*|| savePlyFiles*/) {
if (savePlyFiles) { if (savePlyFiles) {
exportPattern(std::filesystem::path(resultsPath) exportPattern(std::filesystem::path(resultsPath)
@ -494,6 +496,7 @@ void TopologyEnumerator::computeValidPatterns(
const bool tiledPatternHasNodeWithValenceGreaterThanDesired const bool tiledPatternHasNodeWithValenceGreaterThanDesired
= patternGeometry.hasValenceGreaterThan(numberOfNodesPerSlot, 6); = patternGeometry.hasValenceGreaterThan(numberOfNodesPerSlot, 6);
if (tiledPatternHasNodeWithValenceGreaterThanDesired) { if (tiledPatternHasNodeWithValenceGreaterThanDesired) {
statistics.numberOfPatternsViolatingValenceThreshold++;
if (debugIsOn) { if (debugIsOn) {
if (savePlyFiles) { if (savePlyFiles) {
auto highValencePath = std::filesystem::path(resultsPath) auto highValencePath = std::filesystem::path(resultsPath)
@ -510,8 +513,82 @@ void TopologyEnumerator::computeValidPatterns(
numberOfNodesPerSlot); // marks the nodes with valence>=1 numberOfNodesPerSlot); // marks the nodes with valence>=1
// Create the tiled geometry of the pattern // Create the tiled geometry of the pattern
const bool hasFloatingComponents = !patternGeometry.isFullyConnectedWhenTiled(); const bool hasFloatingComponents = !patternGeometry.isFullyConnectedWhenTiled();
FlatPatternTopology topology(numberOfNodesPerSlot, patternEdges);
const bool hasArticulationPoints = topology.containsArticulationPoints(); PatternGeometry fanPatternGeometry = PatternGeometry::createFan(patternGeometry);
const int interfaceNodeVi = 3;
std::vector<PatternGeometry::EdgeType *> connectedEdges;
vcg::edge::VEStarVE(&fanPatternGeometry.vert[interfaceNodeVi], connectedEdges);
if (!connectedEdges.empty()) {
for (int i = 1; i < 6; i++) {
vcg::tri::Allocator<PatternGeometry>::AddEdge(fanPatternGeometry,
interfaceNodeVi
+ (i - 1) * patternGeometry.VN(),
interfaceNodeVi
+ i * patternGeometry.VN());
}
}
vcg::tri::Clean<PatternGeometry>::MergeCloseVertex(fanPatternGeometry, 0.0000005);
vcg::tri::Allocator<PatternGeometry>::CompactEveryVector(fanPatternGeometry);
vcg::tri::UpdateTopology<PatternGeometry>::VertexEdge(fanPatternGeometry);
vcg::tri::UpdateTopology<PatternGeometry>::EdgeEdge(fanPatternGeometry);
// for (PatternGeometry::VertexType &v : tilledPatternGeometry.vert) {
// std::vector<PatternGeometry::EdgeType *> connectedEdges;
// vcg::edge::VEStarVE(&v, connectedEdges);
// if (connectedEdges.size() == 1) {
// vcg::tri::Allocator<PatternGeometry>::DeleteVertex(tilledPatternGeometry, v);
// vcg::tri::Allocator<PatternGeometry>::DeleteEdge(tilledPatternGeometry,
// *connectedEdges[0]);
// }
// }
// // vcg::tri::Allocator<PatternGeometry>::CompactEveryVector(tilledPatternGeometry);
// fanPatternGeometry.updateEigenEdgeAndVertices();
BoostGraph fanPatternGraph(fanPatternGeometry.VN());
// std::cout << "Edges:";
for (const PatternGeometry::EdgeType &e : fanPatternGeometry.edge) {
if (e.IsD() || e.cV(0)->IsD() || e.cV(1)->IsD()) {
continue;
}
const int vi0 = fanPatternGeometry.getIndex(e.cV(0));
const int vi1 = fanPatternGeometry.getIndex(e.cV(1));
boost::add_edge(vi0, vi1, fanPatternGraph);
// std::cout << vi0 << "," << vi1 << " ";
}
// std::cout << std::endl;
std::vector<vertex_t> articulationPoints;
boost::articulation_points(fanPatternGraph, std::back_inserter(articulationPoints));
const bool hasArticulationPoints = !articulationPoints.empty();
// if (hasArticulationPoints /*&& !patternContainsIntersectingEdges
// && !tiledPatternHasDanglingEdges && !hasFloatingComponents
// && !tiledPatternHasNodeWithValenceGreaterThanDesired
// && !tiledPatternHasEdgesWithAngleSmallerThanThreshold*/) {
// for (PatternGeometry::VertexType &v : patternGeometry.vert) {
// v.C() = vcg::Color4b::Yellow;
// }
// // std::cout << "AP:";
// for (const int articulationPointVi : articulationPoints) {
// if (articulationPointVi >= patternGeometry.VN()) {
// continue;
// }
// // std::cout << articulationPointVi << " ";
// patternGeometry.vert[articulationPointVi].C() = vcg::Color4b::Red;
// }
// PatternGeometry tilledPatternGeometry = PatternGeometry::createTile(patternGeometry);
// // std::cout << std::endl;
// std::vector<glm::vec3> fanVertexColors(tilledPatternGeometry.VN(), glm::vec3(0, 0, 1));
// for (const PatternGeometry::VertexType &v : tilledPatternGeometry.vert) {
// const auto vColor = glm::vec3(v.cC()[0] / 255, v.cC()[1] / 255, v.cC()[2] / 255);
// const auto vi = tilledPatternGeometry.getIndex(v);
// fanVertexColors[vi] = vColor;
// }
// // tilledPatternGeometry.updateEigenEdgeAndVertices();
// // tilledPatternGeometry.registerForDrawing()
// // ->addNodeColorQuantity("ap_tilled", fanVertexColors)
// // ->setEnabled(true);
// // polyscope::show();
// // tilledPatternGeometry.unregister();
// }
// duplicated here // duplicated here
// Check dangling edges with vcg method // Check dangling edges with vcg method
// const bool vcg_tiledPatternHasDangling = // const bool vcg_tiledPatternHasDangling =
@ -618,7 +695,7 @@ void TopologyEnumerator::computeValidPatterns(
// if(patternName=='2055'){ // if(patternName=='2055'){
// PatternGeometry tiledPatternGeometry = PatternGeometry::createTile( // PatternGeometry tiledPatternGeometry = PatternGeometry::createTile(
// patternGeometry); // the marked nodes of hasDanglingEdges are // patternGeometry); // the marked nodes of hasDanglingEdges are
// tiledPatternGeometry.registerForDrawing(); // tiledPatternGeometry.registerForDrawing(std::array<double, 3>{0, 0, 1});
// polyscope::show(); // polyscope::show();
// tiledPatternGeometry.unregister(); // tiledPatternGeometry.unregister();
// } // }
@ -656,6 +733,7 @@ void TopologyEnumerator::computeValidPatterns(
} }
} }
} }
std::vector<size_t> TopologyEnumerator::getCoincideEdges( std::vector<size_t> TopologyEnumerator::getCoincideEdges(
const std::vector<size_t> &edgeNodeIndices) const const std::vector<size_t> &edgeNodeIndices) const
{ {

View File

@ -62,6 +62,8 @@ class TopologyEnumerator {
size_t numberOfPatternsWithMoreThanASingleCC{0}; size_t numberOfPatternsWithMoreThanASingleCC{0};
size_t numberOfPatternsWithADanglingEdgeOrNode{0}; size_t numberOfPatternsWithADanglingEdgeOrNode{0};
size_t numberOfPatternsWithArticulationPoints{0}; size_t numberOfPatternsWithArticulationPoints{0};
size_t numberOfPatternsViolatingAngleThreshold{0};
size_t numberOfPatternsViolatingValenceThreshold{0};
size_t numberOfValidPatterns{0}; size_t numberOfValidPatterns{0};
nlohmann::json convertToJson() const nlohmann::json convertToJson() const
{ {
@ -79,6 +81,8 @@ class TopologyEnumerator {
json["numPatternsWithDangling"] = numberOfPatternsWithADanglingEdgeOrNode; json["numPatternsWithDangling"] = numberOfPatternsWithADanglingEdgeOrNode;
json["numPatternsWithArticulationPoints"] = numberOfPatternsWithArticulationPoints; json["numPatternsWithArticulationPoints"] = numberOfPatternsWithArticulationPoints;
json["numValidPatterns"] = numberOfValidPatterns; json["numValidPatterns"] = numberOfValidPatterns;
json["violatingAngle"] = numberOfPatternsViolatingAngleThreshold;
json["violatingValence"] = numberOfPatternsViolatingValenceThreshold;
return json; return json;
} }
@ -141,6 +145,8 @@ class TopologyEnumerator {
numberOfPatternsWithADanglingEdgeOrNode = 0; numberOfPatternsWithADanglingEdgeOrNode = 0;
numberOfPatternsWithArticulationPoints = 0; numberOfPatternsWithArticulationPoints = 0;
numberOfValidPatterns = 0; numberOfValidPatterns = 0;
numberOfPatternsViolatingAngleThreshold = 0;
numberOfPatternsViolatingValenceThreshold = 0;
} }
}; };

View File

@ -116,6 +116,7 @@ PatternGeometry PatternGeometry::createTile(PatternGeometry &pattern) {
// tile.vert[vi].C() = vcg::Color4b::Blue; // tile.vert[vi].C() = vcg::Color4b::Blue;
// } // }
tile.setLabel("tilled_" + pattern.getLabel());
tile.updateEigenEdgeAndVertices(); tile.updateEigenEdgeAndVertices();
return tile; return tile;
} }
@ -674,23 +675,22 @@ bool PatternGeometry::hasIntersectingEdges(
bool containsIntersectingEdges = false; bool containsIntersectingEdges = false;
for (size_t validEdgeIndex = 0; for (size_t validEdgeIndex = 0;
validEdgeIndex < patternBinaryRepresentation.size(); validEdgeIndex++) { validEdgeIndex < patternBinaryRepresentation.size(); validEdgeIndex++) {
if (patternBinaryRepresentation[validEdgeIndex] == '1' && if (patternBinaryRepresentation[validEdgeIndex] == '1'
intersectingEdges.count(validEdgeIndex) != 0) { && intersectingEdges.contains(validEdgeIndex)) {
for (auto edgeIndexIt = for (auto edgeIndexIt = intersectingEdges.find(validEdgeIndex)->second.begin();
intersectingEdges.find(validEdgeIndex)->second.begin(); edgeIndexIt != intersectingEdges.find(validEdgeIndex)->second.end();
edgeIndexIt != intersectingEdges.find(validEdgeIndex)->second.end(); edgeIndexIt++) {
edgeIndexIt++) { if (patternBinaryRepresentation[*edgeIndexIt] == '1') {
if (patternBinaryRepresentation[*edgeIndexIt] == '1') { containsIntersectingEdges = true;
containsIntersectingEdges = true; // statistics.numberOfIntersectingEdgesOverAllPatterns++;
// statistics.numberOfIntersectingEdgesOverAllPatterns++; break; // should be uncommented in order to improve
break; // should be uncommented in order to improve // performance
// performance }
} }
if (containsIntersectingEdges) {
break; // should be uncommented in order to improve performance
}
} }
if (containsIntersectingEdges) {
break; // should be uncommented in order to improve performance
}
}
} }
return containsIntersectingEdges; return containsIntersectingEdges;

View File

@ -5,64 +5,71 @@
FlatPatternTopology::FlatPatternTopology() {} FlatPatternTopology::FlatPatternTopology() {}
FlatPatternTopology::FlatPatternTopology( FlatPatternTopology::FlatPatternTopology(const std::vector<size_t> &numberOfNodesPerSlot,
const std::vector<size_t> &numberOfNodesPerSlot, const std::vector<vcg::Point2i> &edges)
const std::vector<vcg::Point2i> &edges) : numberOfNodesPerSlot(numberOfNodesPerSlot)
: numberOfNodesPerSlot(numberOfNodesPerSlot) { {
pattern = BoostGraph(std::accumulate(numberOfNodesPerSlot.begin(), pattern = BoostGraph(
numberOfNodesPerSlot.end(), 0)); std::accumulate(numberOfNodesPerSlot.begin(), numberOfNodesPerSlot.end(), 0));
for (const vcg::Point2i &e : edges) { isAdjacentTo.resize(boost::num_vertices(pattern),
boost::add_edge(e[0], e[1], pattern); std::vector<bool>(boost::num_vertices(pattern), false));
} for (const vcg::Point2i &e : edges) {
boost::add_edge(e[0], e[1], pattern);
isAdjacentTo[e[0]][e[1]] = true;
isAdjacentTo[e[1]][e[0]] = true;
}
constructNodeToSlotMap(); constructNodeToSlotMap();
constructSlotToNodeMap(); constructSlotToNodeMap();
constructCorresponginNodeMap(); constructCorresponginNodeMap();
} }
bool FlatPatternTopology::containsArticulationPoints() const { bool FlatPatternTopology::containsArticulationPoints(std::vector<int> &articulationPointsVi) const
assert(numberOfNodesPerSlot.size() == 7 && numberOfNodesPerSlot[4] < 2 && {
!nodeToSlot.empty() && !correspondingNode.empty()); assert(numberOfNodesPerSlot.size() == 7 && numberOfNodesPerSlot[4] < 2 && !nodeToSlot.empty()
BoostGraph copyOfPattern(pattern); && !correspondingNode.empty());
// std::cout << std::endl; BoostGraph copyOfPattern(pattern);
std::vector<int> componentsBefore(boost::num_vertices(copyOfPattern)); // std::cout << std::endl;
size_t num_components = // std::vector<int> componentsBefore(boost::num_vertices(copyOfPattern));
boost::connected_components(copyOfPattern, &componentsBefore[0]); // size_t num_components = boost::connected_components(copyOfPattern, &componentsBefore[0]);
// std::cout << "Number of cc before:" << num_components << std::endl; // std::cout << "Number of cc before:" << num_components << std::endl;
// printGraph(copyOfPattern); // printGraph(copyOfPattern);
copyOfPattern = constructRotationallySymmetricPattern( copyOfPattern = constructRotationallySymmetricPattern(copyOfPattern,
copyOfPattern, slotToNode, nodeToSlot, correspondingNode); slotToNode,
// // Remove edges connected to the bottom edge node nodeToSlot,
// assert(slotToNode.find(4) != slotToNode.end()); correspondingNode);
// std::unordered_set<size_t> bottomEdgeNodeSet = // // Remove edges connected to the bottom edge node
// (slotToNode.find(4))->second; // assert(slotToNode.find(4) != slotToNode.end());
// size_t bottomEdgeNodeIndex = *bottomEdgeNodeSet.begin(); // std::unordered_set<size_t> bottomEdgeNodeSet =
// boost::clear_vertex(bottomEdgeNodeIndex, copyOfPattern); // (slotToNode.find(4))->second;
// size_t bottomEdgeNodeIndex = *bottomEdgeNodeSet.begin();
// boost::clear_vertex(bottomEdgeNodeIndex, copyOfPattern);
std::vector<int> componentsAfter(boost::num_vertices(copyOfPattern)); // std::vector<int> componentsAfter(boost::num_vertices(copyOfPattern));
num_components = // num_components = boost::connected_components(copyOfPattern, &componentsAfter[0]);
boost::connected_components(copyOfPattern, &componentsAfter[0]); // std::cout << "Number of cc after:" << num_components << std::endl;
// std::cout << "Number of cc after:" << num_components << std::endl; // printGraph(copyOfPattern);
// printGraph(copyOfPattern);
// Compute articulation points on the edited graph // Compute articulation points on the edited graph
std::vector<vertex_t> articulationPoints; std::vector<vertex_t> articulationPoints;
boost::articulation_points(copyOfPattern, boost::articulation_points(copyOfPattern, std::back_inserter(articulationPoints));
std::back_inserter(articulationPoints)); for (const auto apVi : articulationPoints) {
// std::cout << "Found " << articulationPoints.size() articulationPointsVi.push_back(static_cast<int>(apVi));
// << " articulation points.\n"; }
// size_t numberOfNonValidArticulationPoints = 0; // std::cout << "Found " << articulationPoints.size()
for (std::size_t i = 0; i < articulationPoints.size(); ++i) { // << " articulation points.\n";
// size_t numberOfNonValidArticulationPoints = 0;
// for (std::size_t i = 0; i < articulationPoints.size(); ++i) {
// std::cout << articulationPoints[i] << std::endl; // std::cout << articulationPoints[i] << std::endl;
// if (boost::out_degree(articulationPoints[i], copyOfPattern) < 3) { // if (boost::out_degree(articulationPoints[i], copyOfPattern) < 3) {
// numberOfNonValidArticulationPoints++; // numberOfNonValidArticulationPoints++;
// } // }
} // }
// if (numberOfNonValidArticulationPoints == articulationPoints.size()) { // if (numberOfNonValidArticulationPoints == articulationPoints.size()) {
// return false; // return false;
// } // }
return !articulationPoints.empty(); return !articulationPoints.empty();
} }
void FlatPatternTopology::constructNodeToSlotMap( void FlatPatternTopology::constructNodeToSlotMap(
@ -139,6 +146,29 @@ void FlatPatternTopology::constructCorresponginNodeMap() {
} }
} }
bool FlatPatternTopology::pathExists(int src, int dest) const
{
const int N = boost::num_vertices(pattern);
std::vector<bool> visited(N, false);
visited[src] = true;
std::stack<int> next;
next.push(src);
while (!next.empty()) {
int cv = next.top();
next.pop();
for (int nv = 0; nv < N; ++nv) {
if (!visited[nv] && isAdjacentTo[cv][nv] == 1) {
visited[nv] = true;
next.push(nv);
}
}
}
// dest was reached from src?
return visited[dest];
}
/* /*
* In this function I create an "extended" pattern of the one in the base * In this function I create an "extended" pattern of the one in the base
* triangle by: * triangle by:
@ -152,147 +182,179 @@ BoostGraph FlatPatternTopology::constructRotationallySymmetricPattern(
const BoostGraph &pattern, const BoostGraph &pattern,
const std::unordered_map<size_t, std::unordered_set<size_t>> &slotToNodes, const std::unordered_map<size_t, std::unordered_set<size_t>> &slotToNodes,
const std::unordered_map<size_t, size_t> &nodeToSlot, const std::unordered_map<size_t, size_t> &nodeToSlot,
const std::unordered_map<size_t, size_t> &correspondingNode) { const std::unordered_map<size_t, size_t> &correspondingNode) const
BoostGraph rotationallySymmetricPattern(pattern); {
BoostGraph rotationallySymmetricPattern(pattern);
boost::graph_traits<BoostGraph>::out_edge_iterator ei, ei_end; // for (const std::pair<size_t, size_t> &correspondingPair : correspondingNode) {
// Copy edges that lay on the left edge to the right edge // const auto v0 = boost::vertex(correspondingPair.first, pattern);
const auto slot3NodesPairIt = slotToNodes.find(3); // const auto v1 = boost::vertex(correspondingPair.second, pattern);
if (slot3NodesPairIt != slotToNodes.end()) { // if (boost::degree(v0, pattern) != 0 || boost::degree(v1, pattern) != 0) {
for (const size_t &nodeIndex : slot3NodesPairIt->second) { // boost::add_edge(v0, v1, rotationallySymmetricPattern);
for (boost::tie(ei, ei_end) = boost::out_edges(nodeIndex, pattern); // }
ei != ei_end; ++ei) { // }
auto vt = boost::target(*ei, pattern);
const auto vtNodeSlotPairIt = nodeToSlot.find(vt); boost::graph_traits<BoostGraph>::out_edge_iterator ei, ei_end;
assert(vtNodeSlotPairIt != nodeToSlot.end()); // Copy edges that lay on the left edge to the right edge
const size_t vtSlot = vtNodeSlotPairIt->second; const auto slot3NodesPairIt = slotToNodes.find(3);
if (vtSlot == 3 || vtSlot == 1 || vtSlot == 0) { if (slot3NodesPairIt != slotToNodes.end()) {
// Connect the corresponding nodes on the opposite edge for (const size_t &nodeIndex : slot3NodesPairIt->second) {
auto correspondingNodeIndexIt = correspondingNode.find(nodeIndex); for (boost::tie(ei, ei_end) = boost::out_edges(nodeIndex, pattern); ei != ei_end; ++ei) {
assert(correspondingNodeIndexIt != correspondingNode.end()); auto vt = boost::target(*ei, pattern);
auto correspondingVtIt = correspondingNode.find(vt); const auto vtNodeSlotPairIt = nodeToSlot.find(vt);
assert(correspondingVtIt != correspondingNode.end() || vtSlot == 0); assert(vtNodeSlotPairIt != nodeToSlot.end());
const size_t &correspondingNodeIndex = const size_t vtSlot = vtNodeSlotPairIt->second;
correspondingNodeIndexIt->second; if (vtSlot == 3 || vtSlot == 1 || vtSlot == 0) {
size_t correspondingVt = 0; // Connect the corresponding nodes on the opposite edge
if (correspondingVtIt != correspondingNode.end()) { auto correspondingNodeIndexIt = correspondingNode.find(nodeIndex);
correspondingVt = correspondingVtIt->second; assert(correspondingNodeIndexIt != correspondingNode.end());
} auto correspondingVtIt = correspondingNode.find(vt);
boost::add_edge(correspondingNodeIndex, correspondingVt, assert(correspondingVtIt != correspondingNode.end() || vtSlot == 0);
rotationallySymmetricPattern); const size_t &correspondingNodeIndex = correspondingNodeIndexIt->second;
size_t correspondingVt = 0;
if (correspondingVtIt != correspondingNode.end()) {
correspondingVt = correspondingVtIt->second;
}
boost::add_edge(correspondingNodeIndex,
correspondingVt,
rotationallySymmetricPattern);
}
}
} }
}
} }
}
// Copy edges that lay on the right edge to the left edge // // Copy edges that lay on the right edge to the left edge
const auto slot5NodesPairIt = slotToNodes.find(5); const auto slot5NodesPairIt = slotToNodes.find(5);
if (slot5NodesPairIt != slotToNodes.end()) { if (slot5NodesPairIt != slotToNodes.end()) {
for (const size_t &nodeIndex : slot5NodesPairIt->second) { for (const size_t &nodeIndex : slot5NodesPairIt->second) {
for (boost::tie(ei, ei_end) = boost::out_edges(nodeIndex, pattern); for (boost::tie(ei, ei_end) = boost::out_edges(nodeIndex, pattern); ei != ei_end; ++ei) {
ei != ei_end; ++ei) { auto vt = boost::target(*ei, pattern);
auto vt = boost::target(*ei, pattern); const auto vtNodeSlotPairIt = nodeToSlot.find(vt);
const auto vtNodeSlotPairIt = nodeToSlot.find(vt); assert(vtNodeSlotPairIt != nodeToSlot.end());
assert(vtNodeSlotPairIt != nodeToSlot.end()); const size_t vtSlot = vtNodeSlotPairIt->second;
const size_t vtSlot = vtNodeSlotPairIt->second; if (vtSlot == 5 || vtSlot == 2 || vtSlot == 0) {
if (vtSlot == 5 || vtSlot == 2 || vtSlot == 0) { // Connect the corresponding nodes on the opposite edge
// Connect the corresponding nodes on the opposite edge auto correspondingNodeIndexIt = correspondingNode.find(nodeIndex);
auto correspondingNodeIndexIt = correspondingNode.find(nodeIndex); assert(correspondingNodeIndexIt != correspondingNode.end());
assert(correspondingNodeIndexIt != correspondingNode.end()); auto correspondingVtIt = correspondingNode.find(vt);
auto correspondingVtIt = correspondingNode.find(vt); assert(correspondingVtIt != correspondingNode.end() || vtSlot == 0);
assert(correspondingVtIt != correspondingNode.end() || vtSlot == 0); const size_t &correspondingNodeIndex = correspondingNodeIndexIt->second;
const size_t &correspondingNodeIndex = size_t correspondingVt = 0;
correspondingNodeIndexIt->second; if (correspondingVtIt != correspondingNode.end()) {
size_t correspondingVt = 0; correspondingVt = correspondingVtIt->second;
if (correspondingVtIt != correspondingNode.end()) { }
correspondingVt = correspondingVtIt->second; boost::add_edge(correspondingNodeIndex,
} correspondingVt,
boost::add_edge(correspondingNodeIndex, correspondingVt, rotationallySymmetricPattern);
rotationallySymmetricPattern); }
}
} }
}
} }
}
// NOTE: The problem with that approach is that I connect !all! "external" // NOTE: The problem with that approach is that I connect !all! "external"
// nodes with each other, which might not be entirely true. If the number of // nodes with each other, which might not be entirely true. If the number of
// cc of the tilled configuration is not 1 this might not label patterns as // cc of the tilled configuration is not 1 this might not label patterns as
// having an articulation node although they might have one. Create set of // having an articulation node although they might have one. Create set of
// nodes connected with "external" edges // nodes connected with "external" edges
std::unordered_set<size_t> externallyConnectedNodes; std::unordered_set<size_t> externallyConnectedNodes;
// Mark the star node as external // Mark the star node as external
const auto slot0NodesPairIt = slotToNodes.find(0); const auto slot0NodesPairIt = slotToNodes.find(0);
if (slot0NodesPairIt != slotToNodes.end()) { if (slot0NodesPairIt != slotToNodes.end()) {
externallyConnectedNodes.insert(slot0NodesPairIt->second.begin(), externallyConnectedNodes.insert(slot0NodesPairIt->second.begin(),
slot0NodesPairIt->second.end()); slot0NodesPairIt->second.end());
} }
// Mark all bottom nodes as external since they are allways connected to the // Mark all bottom nodes as external since they are allways connected to the
// south-neighbouring pattern // south-neighbouring pattern
const auto slot4NodesPairIt = slotToNodes.find(4); const auto slot4NodesPairIt = slotToNodes.find(4);
if (slot4NodesPairIt != slotToNodes.end()) { if (slot4NodesPairIt != slotToNodes.end()) {
externallyConnectedNodes.insert(slot4NodesPairIt->second.begin(), externallyConnectedNodes.insert(slot4NodesPairIt->second.begin(),
slot4NodesPairIt->second.end()); slot4NodesPairIt->second.end());
} }
// Add all slot3 nodes that have a connection to the "inside" // Add all slot3 nodes that have a connection to the "inside"
if (slot3NodesPairIt != slotToNodes.end()) { if (slot3NodesPairIt != slotToNodes.end()) {
for (const size_t &nodeIndex : slot3NodesPairIt->second) { externallyConnectedNodes.insert(slot3NodesPairIt->second.begin(),
for (boost::tie(ei, ei_end) = boost::out_edges(nodeIndex, pattern); slot3NodesPairIt->second.end());
ei != ei_end; ++ei) { for (const size_t &nodeIndex : slot3NodesPairIt->second) {
auto vt = boost::target(*ei, pattern); auto correspondingNodePairIt = correspondingNode.find(nodeIndex);
const auto vtNodeSlotPairIt = nodeToSlot.find(vt); // for (boost::tie(ei, ei_end) = boost::out_edges(nodeIndex, pattern); ei != ei_end; ++ei) {
assert(vtNodeSlotPairIt != nodeToSlot.end()); // auto vt = boost::target(*ei, pattern);
const size_t vtSlot = vtNodeSlotPairIt->second; // const auto vtNodeSlotPairIt = nodeToSlot.find(vt);
if (vtSlot != 3) { // assert(vtNodeSlotPairIt != nodeToSlot.end());
auto correspondingNodePairIt = correspondingNode.find(nodeIndex); // const size_t vtSlot = vtNodeSlotPairIt->second;
assert(correspondingNodePairIt != correspondingNode.end()); // if (vtSlot != 3) {
externallyConnectedNodes.insert(correspondingNodePairIt->second); // assert(correspondingNodePairIt != correspondingNode.end());
// externallyConnectedNodes.insert(correspondingNodePairIt->second);
// // boost::add_edge(correspondingNodePairIt->second,
// // vt,
// // rotationallySymmetricPattern);
// // boost::add_edge(nodeIndex, vt, rotationallySymmetricPattern);
// }
// }
boost::add_edge(correspondingNodePairIt->second,
nodeIndex,
rotationallySymmetricPattern);
} }
}
} }
} // Add all slot5 nodes that have a connection to the "inside"
// Add all slot5 nodes that have a connection to the "inside" if (slot5NodesPairIt != slotToNodes.end()) {
if (slot5NodesPairIt != slotToNodes.end()) { for (const size_t &nodeIndex : slot5NodesPairIt->second) {
for (const size_t &nodeIndex : slot5NodesPairIt->second) { auto correspondingNodePairIt = correspondingNode.find(nodeIndex);
for (boost::tie(ei, ei_end) = boost::out_edges(nodeIndex, pattern); // for (boost::tie(ei, ei_end) = boost::out_edges(nodeIndex, pattern); ei != ei_end; ++ei) {
ei != ei_end; ++ei) { // auto vt = boost::target(*ei, pattern);
auto vt = boost::target(*ei, pattern); // const auto vtNodeSlotPairIt = nodeToSlot.find(vt);
const auto vtNodeSlotPairIt = nodeToSlot.find(vt); // assert(vtNodeSlotPairIt != nodeToSlot.end());
assert(vtNodeSlotPairIt != nodeToSlot.end()); // const size_t vtSlot = vtNodeSlotPairIt->second;
const size_t vtSlot = vtNodeSlotPairIt->second; // if (vtSlot != 5) {
if (vtSlot != 5) { // assert(correspondingNodePairIt != correspondingNode.end());
auto correspondingNodePairIt = correspondingNode.find(nodeIndex); // externallyConnectedNodes.insert(correspondingNodePairIt->second);
assert(correspondingNodePairIt != correspondingNode.end()); // boost::add_edge(correspondingNodePairIt->second,
externallyConnectedNodes.insert(correspondingNodePairIt->second); // vt,
// rotationallySymmetricPattern);
// }
// }
boost::add_edge(correspondingNodePairIt->second,
nodeIndex,
rotationallySymmetricPattern);
} }
} externallyConnectedNodes.insert(slot5NodesPairIt->second.begin(),
slot5NodesPairIt->second.end());
} }
}
// connecting all is wrong. Maybe I should check whether the external nodes // connecting all is wrong. Maybe I should check whether the external nodes
// are connected via a single node? If so this node is an articulation point. // are connected via a single node? If so this node is an articulation point.
// I could test this by checking if it filters out only the falsely labeled // I could test this by checking if it filters out only the falsely labeled
// pattern 2367 // pattern 2367
const size_t &n = externallyConnectedNodes.size(); const size_t &n = externallyConnectedNodes.size();
const size_t numberOfExternalEdges = n * (n - 1) / 2; const size_t numberOfExternalEdges = n * (n - 1) / 2;
// Connect all external nodes with each other // Connect all external nodes with each other
for (size_t edgeIndex = 0; edgeIndex < numberOfExternalEdges; edgeIndex++) { for (size_t edgeIndex = 0; edgeIndex < numberOfExternalEdges; edgeIndex++) {
const int sei0 = const int sei0 = n - 2
n - 2 - - std::floor(std::sqrt(-8 * edgeIndex + 4 * n * (n - 1) - 7) / 2.0 - 0.5);
std::floor(std::sqrt(-8 * edgeIndex + 4 * n * (n - 1) - 7) / 2.0 - 0.5); const int sei1 = edgeIndex + sei0 + 1 - n * (n - 1) / 2 + (n - sei0) * ((n - sei0) - 1) / 2;
const int sei1 = edgeIndex + sei0 + 1 - n * (n - 1) / 2 + const size_t ni0 = *std::next(externallyConnectedNodes.begin(), sei0);
(n - sei0) * ((n - sei0) - 1) / 2; const size_t ni1 = *std::next(externallyConnectedNodes.begin(), sei1);
const size_t ni0 = *std::next(externallyConnectedNodes.begin(), sei0); if (correspondingNode.contains(ni0) || correspondingNode.contains(ni1)) {
const size_t ni1 = *std::next(externallyConnectedNodes.begin(), sei1); if (correspondingNode.contains(ni0) && correspondingNode.contains(ni1)
boost::add_edge(ni0, ni1, rotationallySymmetricPattern); && pathExists(correspondingNode.at(ni0), correspondingNode.at(ni1))) {
} boost::add_edge(ni0, ni1, rotationallySymmetricPattern);
} else if (!correspondingNode.contains(ni0) && correspondingNode.contains(ni1)
&& pathExists(ni0, correspondingNode.at(ni1))) {
boost::add_edge(ni0, ni1, rotationallySymmetricPattern);
} else if (correspondingNode.contains(ni0) && !correspondingNode.contains(ni1)
&& pathExists(correspondingNode.at(ni0), ni1)) {
boost::add_edge(ni0, ni1, rotationallySymmetricPattern);
}
}
}
return rotationallySymmetricPattern; return rotationallySymmetricPattern;
} }
void FlatPatternTopology::printGraph(const BoostGraph &g) const { void FlatPatternTopology::printGraph(const BoostGraph &g)
boost::graph_traits<BoostGraph>::edge_iterator ei, ei_end; {
for (boost::tie(ei, ei_end) = boost::edges(g); ei != ei_end; ++ei) boost::graph_traits<BoostGraph>::edge_iterator ei, ei_end;
std::cout << (char)(boost::source(*ei, g) + 'A') << " -- " for (boost::tie(ei, ei_end) = boost::edges(g); ei != ei_end; ++ei)
<< (char)(boost::target(*ei, g) + 'A'); std::cout << (char) (boost::source(*ei, g) + 'A') << " -- "
std::cout << std::endl; << (char) (boost::target(*ei, g) + 'A');
std::cout << std::endl;
} }

View File

@ -13,7 +13,7 @@ using vertex_t = boost::graph_traits<BoostGraph>::vertex_descriptor;
class FlatPatternTopology { class FlatPatternTopology {
public: public:
bool containsArticulationPoints() const; bool containsArticulationPoints(std::vector<int> &articulationPointsVi) const;
FlatPatternTopology(const std::vector<size_t> &numberOfNodesPerSlot, FlatPatternTopology(const std::vector<size_t> &numberOfNodesPerSlot,
const std::vector<vcg::Point2i> &edges); const std::vector<vcg::Point2i> &edges);
static void static void
@ -22,28 +22,30 @@ public:
static void constructSlotToNodeMap( static void constructSlotToNodeMap(
const std::unordered_map<size_t, size_t> &nodeToSlot, const std::unordered_map<size_t, size_t> &nodeToSlot,
std::unordered_map<size_t, std::unordered_set<size_t>> &slotToNode); std::unordered_map<size_t, std::unordered_set<size_t>> &slotToNode);
static void printGraph(const BoostGraph &g);
FlatPatternTopology(); FlatPatternTopology();
BoostGraph constructRotationallySymmetricPattern(
private: const BoostGraph &pattern,
BoostGraph pattern; const std::unordered_map<size_t, std::unordered_set<size_t>> &slotToNodes,
const std::unordered_map<size_t, size_t> &nodeToSlot,
const std::unordered_map<size_t, size_t> &correspondingNode) const;
std::vector<size_t> numberOfNodesPerSlot; std::vector<size_t> numberOfNodesPerSlot;
std::unordered_map<size_t, size_t> nodeToSlot; std::unordered_map<size_t, size_t> nodeToSlot;
std::unordered_map<size_t, std::unordered_set<size_t>> slotToNode; std::unordered_map<size_t, std::unordered_set<size_t>> slotToNode;
std::unordered_map<size_t, size_t> correspondingNode; std::unordered_map<size_t, size_t> correspondingNode;
private:
std::vector<std::vector<bool>> isAdjacentTo;
BoostGraph pattern;
void constructCorresponginNodeMap(); void constructCorresponginNodeMap();
/* /*
* Creates a pattern which is a copy of the input pattern but with added edges * Creates a pattern which is a copy of the input pattern but with added edges
* that result * that result
* */ * */
void printGraph(const BoostGraph &g) const;
static BoostGraph constructRotationallySymmetricPattern(
const BoostGraph &pattern,
const std::unordered_map<size_t, std::unordered_set<size_t>> &slotToNodes,
const std::unordered_map<size_t, size_t> &nodeToSlot,
const std::unordered_map<size_t, size_t> &correspondingNode);
void constructNodeToSlotMap(); void constructNodeToSlotMap();
void constructSlotToNodeMap(); void constructSlotToNodeMap();
bool pathExists(int src, int dest) const;
}; };
#endif // FLATPATTTERNTOPOLOGY_HPP #endif // FLATPATTTERNTOPOLOGY_HPP

View File

@ -9,6 +9,8 @@
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#define GET_VARIABLE_NAME(Variable) (#Variable)
struct Vector6d : public std::array<double, 6> { struct Vector6d : public std::array<double, 6> {
Vector6d() { Vector6d() {
for (size_t i = 0; i < 6; i++) { for (size_t i = 0; i < 6; i++) {