#include "component/controller/GraphLayouter.h" #include #include #include #include #include "component/view/graphElements/GraphEdge.h" #include "component/view/graphElements/GraphNode.h" #include "utility/math/MatrixDynamicBase.h" // for prototyping, remove when done #include "Eigen/Dense" #include "Eigen/Eigenvalues" #include "unsupported/Eigen/MatrixFunctions" bool compareEigenvaluePairs(const std::pair& p0, const std::pair& p1) { return p0.second > p1.second; } void GraphLayouter::layoutSimpleRaster(std::vector& nodes) { int x = 0; int y = 0; int offset = 150; int w = ceil(sqrt(nodes.size())); for (unsigned int i = 0; i < nodes.size(); i++) { if (i > 0 && i % w == 0) { y += offset; x = 0; } nodes[i].position = Vec2i(x, y); x += offset; } } void GraphLayouter::layoutSimpleRing(std::vector& nodes) { if (nodes.size() >= 1) { nodes[0].position = Vec2i(0, 0); if (nodes.size() > 1) { float offset = 200.0f; for (unsigned int i = 1; i < nodes.size(); i++) { float rad = 2.0f * 3.14159265359f / float(nodes.size() - 1) * i - 1; int x = offset * std::cos(rad); int y = offset * std::sin(rad); nodes[i].position = Vec2i(x, y); } } } } void GraphLayouter::layoutSpectralPrototype(std::vector& nodes, const std::vector& edges) { if(nodes.size() < 2) { LOG_WARNING("Not enough nodes for layouting"); return; } MatrixDynamicBase laplacian = buildLaplacianMatrix(nodes, edges); Eigen::MatrixXd degreeMatrix(laplacian.getColumnsCount(), laplacian.getRowsCount()); Eigen::MatrixXd eigenMatrix(laplacian.getColumnsCount(), laplacian.getRowsCount()); for(unsigned int x = 0; x < laplacian.getColumnsCount(); x++) { for(unsigned int y = 0; y < laplacian.getRowsCount(); y++) { eigenMatrix(x, y) = laplacian.getValue(x, y); if(x == y) { degreeMatrix(x, y) = laplacian.getValue(x, y); } } } degreeMatrix = degreeMatrix.inverse(); Eigen::MatrixPower dPow(degreeMatrix); degreeMatrix = dPow(0.5); eigenMatrix = degreeMatrix * eigenMatrix * degreeMatrix; eigenMatrix.normalize(); Eigen::EigenSolver solver(eigenMatrix); std::vector> eigenVectors; for(unsigned int i = 0; i < solver.eigenvectors().cols(); i++) { eigenVectors.push_back(std::vector()); for(unsigned int j = 0; j < solver.eigenvectors().rows(); j++) { eigenVectors[i].push_back(solver.eigenvectors()(i*solver.eigenvectors().rows() + j).real()); } } std::vector> eigenValues; for(unsigned int i = 0; i < solver.eigenvalues().size(); i++) { eigenValues.push_back(std::pair(i, solver.eigenvalues()(i).real())); } std::sort(eigenValues.begin(), eigenValues.end(), compareEigenvaluePairs); if(eigenVectors.size() > 0 && eigenVectors[0].size() >= 3) { unsigned int xIdx = eigenValues[eigenValues.size()-2].first; unsigned int yIdx = eigenValues[eigenValues.size()-3].first; /*double xEigenValue = std::sqrt(solver.eigenvalues()(xIdx).real()); double yEigenValue = std::sqrt(solver.eigenvalues()(yIdx).real());*/ for(unsigned int i = 0; i < nodes.size(); i++) { float xPos = eigenVectors[xIdx][i]; float yPos = eigenVectors[yIdx][i]; Vec2f newPos(xPos, yPos); newPos.normalize(); newPos *= 600.0f; nodes[i].position.x = newPos.x; nodes[i].position.y = newPos.y; //std::cout << newPos << std::endl; } //std::cout << "=================" << std::endl; } } MatrixDynamicBase GraphLayouter::buildLaplacianMatrix(const std::vector& nodes, const std::vector& edges) { MatrixDynamicBase matrix(nodes.size(), nodes.size()); std::map nodesMap; std::queue remainingNodes; for(unsigned int i = 0; i < nodes.size(); i++) { remainingNodes.push(nodes[i]); } while(remainingNodes.size() > 0) { if(remainingNodes.front().subNodes.size() > 0) { for(unsigned int i = 0; i < remainingNodes.front().subNodes.size(); i++) { remainingNodes.push(remainingNodes.front().subNodes[i]); } } nodesMap[remainingNodes.front().tokenId] = remainingNodes.front(); remainingNodes.pop(); } std::map, int> weightsMap; for(unsigned int i = 0; i < edges.size(); i++) { DummyNode ownerNode = nodesMap[edges[i].ownerId]; DummyNode targetNode = nodesMap[edges[i].targetId]; if(ownerNode.topLevelAncestorId != targetNode.topLevelAncestorId) { int weightIncrement = 1; Id ownerId = ownerNode.topLevelAncestorId; Id targetId = targetNode.topLevelAncestorId; std::pair key(ownerId, targetId); std::pair inverseKey(targetId, ownerId); std::pair keyOwner(ownerId, ownerId); std::pair keyTarget(targetId, targetId); std::map, int>::iterator it = weightsMap.find(key); if(it == weightsMap.end()) { weightsMap[key] = 0; } weightsMap[key] += weightIncrement; it = weightsMap.find(inverseKey); if(it == weightsMap.end()) { weightsMap[inverseKey] = 0; } weightsMap[inverseKey] += weightIncrement; it = weightsMap.find(keyOwner); if(it == weightsMap.end()) { weightsMap[keyOwner] = 0; } weightsMap[keyOwner] += weightIncrement; it = weightsMap.find(keyTarget); if(it == weightsMap.end()) { weightsMap[keyTarget] = 0; } weightsMap[keyTarget] += weightIncrement; } } for(unsigned int x = 0; x < nodes.size(); x++) { for(unsigned int y = x; y < nodes.size(); y++) { unsigned int xNodeId = nodes[x].tokenId; unsigned int yNodeId = nodes[y].tokenId; std::pair key(xNodeId, yNodeId); if(x == y) { matrix.setValue(x, y, weightsMap[key]); } else { matrix.setValue(x, y, -weightsMap[key]); matrix.setValue(y, x, -weightsMap[key]); } } } return matrix; }