From 06c66ed21a25c530619ad79bf385250ea3093a3a Mon Sep 17 00:00:00 2001 From: Federico Bond Date: Tue, 27 Jun 2017 14:53:55 -0300 Subject: [PATCH 1/5] Add simple Delaunay library to test --- vendor/delaunay/.gitignore | 7 ++ vendor/delaunay/LICENSE | 24 ++++++ vendor/delaunay/README.md | 62 ++++++++++++++++ vendor/delaunay/delaunay.h | 145 +++++++++++++++++++++++++++++++++++++ vendor/delaunay/edge.h | 33 +++++++++ vendor/delaunay/main.cpp | 99 +++++++++++++++++++++++++ vendor/delaunay/sample.png | Bin 0 -> 15847 bytes vendor/delaunay/triangle.h | 65 +++++++++++++++++ vendor/delaunay/vector2.h | 71 ++++++++++++++++++ 9 files changed, 506 insertions(+) create mode 100644 vendor/delaunay/.gitignore create mode 100644 vendor/delaunay/LICENSE create mode 100644 vendor/delaunay/README.md create mode 100644 vendor/delaunay/delaunay.h create mode 100644 vendor/delaunay/edge.h create mode 100644 vendor/delaunay/main.cpp create mode 100644 vendor/delaunay/sample.png create mode 100644 vendor/delaunay/triangle.h create mode 100644 vendor/delaunay/vector2.h diff --git a/vendor/delaunay/.gitignore b/vendor/delaunay/.gitignore new file mode 100644 index 0000000..7563863 --- /dev/null +++ b/vendor/delaunay/.gitignore @@ -0,0 +1,7 @@ +test +delaunay +*.swp +build/ +peda-session-delaunay.txt +*.lua +.gdb_history diff --git a/vendor/delaunay/LICENSE b/vendor/delaunay/LICENSE new file mode 100644 index 0000000..71568cf --- /dev/null +++ b/vendor/delaunay/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2015 Simon Zeni (simonzeni@gmail.com) + + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + diff --git a/vendor/delaunay/README.md b/vendor/delaunay/README.md new file mode 100644 index 0000000..c0c6c85 --- /dev/null +++ b/vendor/delaunay/README.md @@ -0,0 +1,62 @@ +# delaunay-triangulation + +## Pseudo-code algorithm + +``` +function BowyerWatson (pointList) + // pointList is a set of coordinates defining the points to be triangulated + triangulation := empty triangle mesh data structure + add super-triangle to triangulation // must be large enough to completely contain all the points in pointList + for each point in pointList do // add all the points one at a time to the triangulation + badTriangles := empty set + for each triangle in triangulation do // first find all the triangles that are no longer valid due to the insertion + if point is inside circumcircle of triangle + add triangle to badTriangles + polygon := empty set + for each triangle in badTriangles do // find the boundary of the polygonal hole + for each edge in triangle do + if edge is not shared by any other triangles in badTriangles + add edge to polygon + for each triangle in badTriangles do // remove them from the data structure + remove triangle from triangulation + for each edge in polygon do // re-triangulate the polygonal hole + newTri := form a triangle from edge to point + add newTri to triangulation + for each triangle in triangulation // done inserting points, now clean up + if triangle contains a vertex from original super-triangle + remove triangle from triangulation + return triangulation +``` + +## Sample + +![alt text](https://github.com/Bl4ckb0ne/delaunay-triangulation/blob/master/sample.png "Sample image (if you see this, then the image can't load or hasn't loaded yet)") + + +From the [Wikipedia page of the algorithm](https://en.wikipedia.org/wiki/Bowyer%E2%80%93Watson_algorithm) + +## Requirement + +You will need [SFML 2+](http://www.sfml-dev.org/download/sfml/2.3.2/) to run the example, and C++11 to compile it. + +## Usage + +To build it, you can type in : +```sh +make +``` +You may change the compiler on the makefile (using the CXX var) +```sh +make CXX=g++ # to use the GCC compiler +make CXX=clang++ # default compiler +``` + +The executable name is ``` delaunay ```, without arguments +```sh +./delaunay +``` + +You also can clear the executable and the build folder. +```sh +make clean +``` diff --git a/vendor/delaunay/delaunay.h b/vendor/delaunay/delaunay.h new file mode 100644 index 0000000..e04ce23 --- /dev/null +++ b/vendor/delaunay/delaunay.h @@ -0,0 +1,145 @@ +#ifndef H_DELAUNAY +#define H_DELAUNAY + +#include "vector2.h" +#include "edge.h" +#include "triangle.h" + +#include +#include + +template +class Delaunay +{ + public: + using TriangleType = Triangle; + using EdgeType = Edge; + using VertexType = Vector2; + + const std::vector& triangulate(std::vector &vertices) + { + // Store the vertices localy + _vertices = vertices; + + // Determinate the super triangle + float minX = vertices[0].x; + float minY = vertices[0].y; + float maxX = minX; + float maxY = minY; + + for(std::size_t i = 0; i < vertices.size(); ++i) + { + if (vertices[i].x < minX) minX = vertices[i].x; + if (vertices[i].y < minY) minY = vertices[i].y; + if (vertices[i].x > maxX) maxX = vertices[i].x; + if (vertices[i].y > maxY) maxY = vertices[i].y; + } + + float dx = maxX - minX; + float dy = maxY - minY; + float deltaMax = std::max(dx, dy); + float midx = (minX + maxX) / 2.f; + float midy = (minY + maxY) / 2.f; + + VertexType p1(midx - 20 * deltaMax, midy - deltaMax); + VertexType p2(midx, midy + 20 * deltaMax); + VertexType p3(midx + 20 * deltaMax, midy - deltaMax); + + //std::cout << "Super triangle " << std::endl << Triangle(p1, p2, p3) << std::endl; + + // Create a list of triangles, and add the supertriangle in it + _triangles.push_back(TriangleType(p1, p2, p3)); + + for(auto p = begin(vertices); p != end(vertices); p++) + { + //std::cout << "Traitement du point " << *p << std::endl; + //std::cout << "_triangles contains " << _triangles.size() << " elements" << std::endl; + + std::vector badTriangles; + std::vector polygon; + + for(auto t = begin(_triangles); t != end(_triangles); t++) + { + //std::cout << "Processing " << std::endl << *t << std::endl; + + if(t->circumCircleContains(*p)) + { + //std::cout << "Pushing bad triangle " << *t << std::endl; + badTriangles.push_back(*t); + polygon.push_back(t->e1); + polygon.push_back(t->e2); + polygon.push_back(t->e3); + } + else + { + //std::cout << " does not contains " << *p << " in his circum center" << std::endl; + } + } + + _triangles.erase(std::remove_if(begin(_triangles), end(_triangles), [badTriangles](TriangleType &t){ + for(auto bt = begin(badTriangles); bt != end(badTriangles); bt++) + { + if(*bt == t) + { + //std::cout << "Removing bad triangle " << std::endl << *bt << " from _triangles" << std::endl; + return true; + } + } + return false; + }), end(_triangles)); + + std::vector badEdges; + for(auto e1 = begin(polygon); e1 != end(polygon); e1++) + { + for(auto e2 = begin(polygon); e2 != end(polygon); e2++) + { + if(e1 == e2) + continue; + + if(*e1 == *e2) + { + badEdges.push_back(*e1); + badEdges.push_back(*e2); + } + } + } + + polygon.erase(std::remove_if(begin(polygon), end(polygon), [badEdges](EdgeType &e){ + for(auto it = begin(badEdges); it != end(badEdges); it++) + { + if(*it == e) + return true; + } + return false; + }), end(polygon)); + + for(auto e = begin(polygon); e != end(polygon); e++) + _triangles.push_back(TriangleType(e->p1, e->p2, *p)); + + } + + _triangles.erase(std::remove_if(begin(_triangles), end(_triangles), [p1, p2, p3](TriangleType &t){ + return t.containsVertex(p1) || t.containsVertex(p2) || t.containsVertex(p3); + }), end(_triangles)); + + for(auto t = begin(_triangles); t != end(_triangles); t++) + { + _edges.push_back(t->e1); + _edges.push_back(t->e2); + _edges.push_back(t->e3); + } + + return _triangles; + } + + const std::vector& getTriangles() const { return _triangles; }; + const std::vector& getEdges() const { return _edges; }; + const std::vector& getVertices() const { return _vertices; }; + + private: + std::vector _triangles; + std::vector _edges; + std::vector _vertices; +}; + +#endif diff --git a/vendor/delaunay/edge.h b/vendor/delaunay/edge.h new file mode 100644 index 0000000..cc9e8ac --- /dev/null +++ b/vendor/delaunay/edge.h @@ -0,0 +1,33 @@ +#ifndef H_EDGE +#define H_EDGE + +#include "vector2.h" + +template +class Edge +{ + public: + using VertexType = Vector2; + + Edge(const VertexType &p1, const VertexType &p2) : p1(p1), p2(p2) {}; + Edge(const Edge &e) : p1(e.p1), p2(e.p2) {}; + + VertexType p1; + VertexType p2; +}; + +template +inline std::ostream &operator << (std::ostream &str, Edge const &e) +{ + return str << "Edge " << e.p1 << ", " << e.p2; +} + +template +inline bool operator == (const Edge & e1, const Edge & e2) +{ + return (e1.p1 == e2.p1 && e1.p2 == e2.p2) || + (e1.p1 == e2.p2 && e1.p2 == e2.p1); +} + +#endif + diff --git a/vendor/delaunay/main.cpp b/vendor/delaunay/main.cpp new file mode 100644 index 0000000..0f1f649 --- /dev/null +++ b/vendor/delaunay/main.cpp @@ -0,0 +1,99 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "vector2.h" +#include "triangle.h" +#include "delaunay.h" + +float RandomFloat(float a, float b) { + float random = ((float) rand()) / (float) RAND_MAX; + float diff = b - a; + float r = random * diff; + return a + r; +} + +int main() +{ + srand (time(NULL)); + float numberPoints = roundf(RandomFloat(4, 40)); + + std::cout << "Generating " << numberPoints << " random points" << std::endl; + + std::vector> points; + for(int i = 0; i < numberPoints; i++) { + points.push_back(Vector2(RandomFloat(0, 800), RandomFloat(0, 600))); + } + + Delaunay triangulation; + std::vector> triangles = triangulation.triangulate(points); + std::cout << triangles.size() << " triangles generated\n"; + std::vector> edges = triangulation.getEdges(); + + std::cout << " ========= "; + + std::cout << "\nPoints : " << points.size() << std::endl; + for(auto &p : points) + std::cout << p << std::endl; + + std::cout << "\nTriangles : " << triangles.size() << std::endl; + for(auto &t : triangles) + std::cout << t << std::endl; + + std::cout << "\nEdges : " << edges.size() << std::endl; + for(auto &e : edges) + std::cout << e << std::endl; + + // SFML window + sf::RenderWindow window(sf::VideoMode(800, 600), "Delaunay triangulation"); + + // Transform each points of each vector as a rectangle + std::vector squares; + + for(auto p = begin(points); p != end(points); p++) { + sf::RectangleShape *c1 = new sf::RectangleShape(sf::Vector2f(4, 4)); + c1->setPosition(p->x, p->y); + squares.push_back(c1); + } + + // Make the lines + std::vector > lines; + for(auto e = begin(edges); e != end(edges); e++) { + lines.push_back({{ + sf::Vertex(sf::Vector2f((*e).p1.x + 2, (*e).p1.y + 2)), + sf::Vertex(sf::Vector2f((*e).p2.x + 2, (*e).p2.y + 2)) + }}); + } + + while (window.isOpen()) + { + sf::Event event; + while (window.pollEvent(event)) + { + if (event.type == sf::Event::Closed) + window.close(); + } + + window.clear(); + + // Draw the squares + for(auto s = begin(squares); s != end(squares); s++) { + window.draw(**s); + } + + // Draw the lines + for(auto l = begin(lines); l != end(lines); l++) { + window.draw((*l).data(), 2, sf::Lines); + } + + window.display(); + } + + return 0; +} diff --git a/vendor/delaunay/sample.png b/vendor/delaunay/sample.png new file mode 100644 index 0000000000000000000000000000000000000000..fef352eeed8db5f31c03d7754540118fc4f1a612 GIT binary patch literal 15847 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 literal 0 HcmV?d00001 diff --git a/vendor/delaunay/triangle.h b/vendor/delaunay/triangle.h new file mode 100644 index 0000000..e068a5c --- /dev/null +++ b/vendor/delaunay/triangle.h @@ -0,0 +1,65 @@ +#ifndef H_TRIANGLE +#define H_TRIANGLE + +#include "vector2.h" +#include "edge.h" + +#include +#include + +template +class Triangle +{ + public: + using EdgeType = Edge; + using VertexType = Vector2; + + Triangle(const VertexType &_p1, const VertexType &_p2, const VertexType &_p3) + : p1(_p1), p2(_p2), p3(_p3), + e1(_p1, _p2), e2(_p2, _p3), e3(_p3, _p1) + {} + + bool containsVertex(const VertexType &v) + { + return p1 == v || p2 == v || p3 == v; + } + + bool circumCircleContains(const VertexType &v) + { + float ab = (p1.x * p1.x) + (p1.y * p1.y); + float cd = (p2.x * p2.x) + (p2.y * p2.y); + float ef = (p3.x * p3.x) + (p3.y * p3.y); + + float circum_x = (ab * (p3.y - p2.y) + cd * (p1.y - p3.y) + ef * (p2.y - p1.y)) / (p1.x * (p3.y - p2.y) + p2.x * (p1.y - p3.y) + p3.x * (p2.y - p1.y)) / 2.f; + float circum_y = (ab * (p3.x - p2.x) + cd * (p1.x - p3.x) + ef * (p2.x - p1.x)) / (p1.y * (p3.x - p2.x) + p2.y * (p1.x - p3.x) + p3.y * (p2.x - p1.x)) / 2.f; + float circum_radius = sqrtf(((p1.x - circum_x) * (p1.x - circum_x)) + ((p1.y - circum_y) * (p1.y - circum_y))); + + float dist = sqrtf(((v.x - circum_x) * (v.x - circum_x)) + ((v.y - circum_y) * (v.y - circum_y))); + return dist <= circum_radius; + } + + VertexType p1; + VertexType p2; + VertexType p3; + EdgeType e1; + EdgeType e2; + EdgeType e3; +}; + +template +inline std::ostream &operator << (std::ostream &str, const Triangle & t) +{ + return str << "Triangle:" << std::endl << "\t" << t.p1 << std::endl << "\t" << t.p2 << std::endl << "\t" << t.p3 << std::endl << "\t" << t.e1 << std::endl << "\t" << t.e2 << std::endl << "\t" << t.e3 << std::endl; + +} + +template +inline bool operator == (const Triangle &t1, const Triangle &t2) +{ + return (t1.p1 == t2.p1 || t1.p1 == t2.p2 || t1.p1 == t2.p3) && + (t1.p2 == t2.p1 || t1.p2 == t2.p2 || t1.p2 == t2.p3) && + (t1.p3 == t2.p1 || t1.p3 == t2.p2 || t1.p3 == t2.p3); +} + + +#endif diff --git a/vendor/delaunay/vector2.h b/vendor/delaunay/vector2.h new file mode 100644 index 0000000..d187fe3 --- /dev/null +++ b/vendor/delaunay/vector2.h @@ -0,0 +1,71 @@ +#ifndef H_VECTOR2 +#define H_VECTOR2 + +#include +#include + +template +class Vector2 +{ + public: + // + // Constructors + // + + Vector2() + { + x = 0; + y = 0; + } + + Vector2(T _x, T _y) + { + x = _x; + y = _y; + } + + Vector2(const Vector2 &v) + { + x = v.x; + y = v.y; + } + + void set(const Vector2 &v) + { + x = v.x; + y = v.y; + } + + // + // Operations + // + T dist2(const Vector2 &v) + { + T dx = x - v.x; + T dy = y - v.y; + return dx * dx + dy * dy; + } + + float dist(const Vector2 &v) + { + return sqrtf(dist2(v)); + } + + T x; + T y; + +}; + +template +std::ostream &operator << (std::ostream &str, Vector2 const &point) +{ + return str << "Point x: " << point.x << " y: " << point.y; +} + +template +bool operator == (Vector2 v1, Vector2 v2) +{ + return (v1.x == v2.x) && (v1.y == v2.y); +} + +#endif From 2f1c8dc718689908ea291119082a86b4f9c5d7a6 Mon Sep 17 00:00:00 2001 From: Federico Bond Date: Tue, 18 Jul 2017 03:16:13 -0300 Subject: [PATCH 2/5] Add basic algorithm for optimized HOT --- src/ComplexNets/GraphGenerator.cpp | 268 +++++++++-------------------- 1 file changed, 80 insertions(+), 188 deletions(-) diff --git a/src/ComplexNets/GraphGenerator.cpp b/src/ComplexNets/GraphGenerator.cpp index 758160e..5cd6432 100644 --- a/src/ComplexNets/GraphGenerator.cpp +++ b/src/ComplexNets/GraphGenerator.cpp @@ -175,7 +175,7 @@ Graph* GraphGenerator::generateBarabasiAlbertGraph(unsigned int m_0, unsigned in * minimizes the euclidean distance from U to V and the hoops distance from U to root. This process * is repeated m times for each new vertex added. * Step 3) Create q new edges on the graph for the vertex added - * Step 4) A new root is chosen with probability dependant on the node degree every t rounds. + * Step 4) A new root is chosen with probability dependant on the node degree every t rounds. (@TODO) * */ Graph* GraphGenerator::generateHotExtendedGraph( @@ -183,218 +183,110 @@ Graph* GraphGenerator::generateHotExtendedGraph( { auto graph = new Graph(); - // Every time an edge is added, two entries are added in vertexIndexes, the two indexes of the - // nodes joined. - std::vector vertexIndexes; - unsigned int root = 1; + // add root vertex + Vertex* root = new Vertex(0); + graph->addVertex(root); - vertexesPositions.clear(); - // Firts vertex + addPosition(root); + + // for each of the nodes we will be adding to the graph + for (unsigned i = 1; i < n; i++) + { + Vertex* v = new Vertex(i); + addPosition(v); - // Step 1 + // setup minWeight, minVertex, minHop + auto minWeight = distance(v, root); + auto minVertex = root; + auto minHop = 0; - addOriginalVertex(graph); + // TODO: consider how maxHop is computed - // For each of the nodes we will be adding to the graph - for (unsigned int i = 2; i <= n; i++) - { - // Step 2 + // for hop j from 1 to maxHop + for (unsigned hop = 1; hop <= maxHop; hop++) + { + auto nn = singleHopNN(j) + nn->insert(v); - addFKPNode(i, graph, root, xi, &vertexIndexes, m); + auto neighbor = nn->get(v); + auto weight = distance(v, neighbor) + xi * hop; - // Step 3 + if (weight < minWeight) + { + minWeight = weight; + minVertex = neighbor; + minHop = hop; + } - addExtendedEdges(q, i, graph, root, r, &vertexIndexes); + nn->delete(v) + } - // Step 4 + auto nn = singleHopNN(minHop + 1); + nn->insert(v); - root = chooseNewRoot(i, t, root, vertexIndexes); - } - return graph; -} + // TODO: update Ti to Tr? + graph->addEdge(v, minVertex); -/** - The main Vertex is created, added to the graph and a position is generated -*/ -void GraphGenerator::addOriginalVertex(Graph* graph) -{ - Vertex* newVertex = new Vertex(1); - graph->addVertex(newVertex); - addVertexPosition(); -} + nn = doubleHopNN(minHop + 1, minHop + 3) + nn->insert(v); -/** - A new vertex is created and added. Then m edges are added according to the original FKP - function - - TODO: Optimize this function using Voronoi Diagrams -*/ -void GraphGenerator::addFKPNode( - unsigned int vertexIndex, - Graph* graph, - unsigned int root, - float xi, - std::vector* vertexIndexes, - unsigned int m) -{ - std::map distance; - - // Creation of vertex - Vertex* newVertex = new Vertex(vertexIndex); - graph->addVertex(newVertex); - addVertexPosition(); - - for (unsigned int j = 1; j < vertexIndex; j++) - { // this for evaluated "w" for each vertex already in the graph - unsigned hopsDistance = graph->hops( - graph->getVertexById(j), - graph->getVertexById(root) - ); // distance between vertex evaluated and root vertex - float euclidianDistance = distanceBetweenVertex(j, vertexIndex); // Distance between vertex evaluated and new vertex - - // Original FKP Algorithm chooses a new connection between the new vertex and the one with - // minimum W - - float w = euclidianDistance + xi * hopsDistance; - distance[w] = j; // stores 'w' as key of a map - } - addEdges( - graph, newVertex, distance, m, - vertexIndexes); // m edges are added acording to the minimum distances - distance.clear(); -} + nn = doubleHopNN(minHop - 1, minHop + 1) + nn->insert(v); -/** - q edges are added according to the function in the paper - - TODO: Optimize the complexity of the algorithm using Voronoi diagrams. -*/ -void GraphGenerator::addExtendedEdges( - unsigned int q, - unsigned int vertexIndex, - Graph* graph, - unsigned int root, - float r, - std::vector* vertexIndexes) -{ - // We will go through this function q times, adding q edges - for (unsigned int qfinal = 0; qfinal < q; qfinal++) - { - // At the end of the loop we only add one edge, so we save the minimum distance and the - // indexes of the nodes - float minDist = 0; - unsigned int finalJ = 0; - unsigned int finalK = 0; - - // We loop through every combination of nodes - for (unsigned int j = 1; j <= vertexIndex; j++) + std::pair minEdge; + minWeight = INFINITY; + minVertex = nullptr; + + v = nullptr; + + for (unsigned hop = 0; hop <= maxHop - 2; hop++) { - for (unsigned int k = 1; k <= vertexIndex; k++) + for (auto const& k : singleHopNN(hop)) { - // For each combination of nodes we calculate the function - float euclidianDistance = 0; - unsigned int HopsWithEdge = 0; - unsigned int HopsWithOutEdge = 0; - if (k != j && !graph->getVertexById(j)->isNeighbourOf(graph->getVertexById(k))) + nn = doubleHopNN(hop, hop + 2); + v = nn->get(k); + + auto weight = distance(k, v) - (r / n) * childCount(v); + if (weight < minWeight) { - for (unsigned int l = 1; l <= vertexIndex; l++) - { - // We calculate the hops to the root with and without the edge - HopsWithOutEdge = - graph->hops(graph->getVertexById(l), graph->getVertexById(root)) + - HopsWithOutEdge; // Hops between evaluated vertex and root vertex - // without new edge - graph->addEdge( - graph->getVertexById(j), - graph->getVertexById( - k)); // Add new edges only for evaluation, later will be removed - HopsWithEdge = - graph->hops(graph->getVertexById(l), graph->getVertexById(root)) + - HopsWithEdge; // Hops between evaluated vertex and root vertex with new - // edge - graph->removeEdge( - graph->getVertexById(j), - graph->getVertexById(k)); // remove the edge previously added - } - - euclidianDistance = distanceBetweenVertex(j, k); - float w = - euclidianDistance + (r / vertexIndex) * (HopsWithEdge - HopsWithOutEdge); - - // We save only the minimum - - if (minDist == 0 || w < minDist) - { - minDist = w; - finalJ = j; - finalK = k; - } + minWeight = weight; + minEdge = make_pair(k, v); + minVertex = v; } } } - // Finally, we add a new edge + graph->addEdge(minEdge.first, minEdge.second); - if (minDist != 0) + auto hp = 0; + + // TODO: see whiteboard + for (auto const& j : BFS(root)) { - vertexIndexes->push_back(finalJ); - vertexIndexes->push_back(finalK); - graph->addEdge(graph->getVertexById(finalJ), graph->getVertexById(finalK)); - } - } -} + auto hj = computeWeightChange(j); + if (hj > hp) + { + nn = doubleHopNN(hj - 2, hj); + nn->delete(j); -/** - A new root is choosen according to the parameter t and the indexes distribution -*/ -int GraphGenerator::chooseNewRoot( - unsigned int vertexIndex, - unsigned int t, - unsigned int root, - std::vector vertexIndexes) -{ - if ((vertexIndex - 1) % t == 0) - { - return vertexIndexes[rand() % vertexIndexes.size()]; - } - return root; -} + nn = doubleHopNN(hj, hj + 2); + nn->delete(j); -void GraphGenerator::addEdges( - Graph* graph, - Vertex* vertex, - std::map distance, - unsigned int q, - std::vector* vertexIndexes) -{ - for (unsigned int k = 0; k < q && !distance.empty(); k++) - { // Adding "q" new edges. The processes is similar to added vertex. - if (!graph->getVertexById(distance.begin()->second)->isNeighbourOf(vertex)) - { - vertexIndexes->push_back(distance.begin()->second); - vertexIndexes->push_back(vertex->getVertexId()); - graph->addEdge(graph->getVertexById(distance.begin()->second), vertex); - distance.erase(distance.begin()); // Remove the lowest value of w from the list, - // because was used previously. This process repeat - // "q" times. - if (distance.empty()) - break; - } - } -} + nn = singleHopNN(hj); + nn->delete(j); -float GraphGenerator::distanceBetweenVertex(unsigned int vertex1Id, unsigned int vertex2Id) -{ - return sqrt( - pow(vertexesPositions[vertex1Id - 1].x - vertexesPositions[vertex2Id - 1].x, 2) + - pow(vertexesPositions[vertex1Id - 1].y - vertexesPositions[vertex2Id - 1].y, 2)); -} + nn = doubleHopNN(hp - 2, hp); + nn->insert(j); -void GraphGenerator::addVertexPosition() -{ - vertexesPositions.push_back(Position()); - vertexesPositions.back().x = (float)rand() / RAND_MAX; - vertexesPositions.back().y = (float)rand() / RAND_MAX; + nn = doubleHopNN(hp, hp + 2); + nn->insert(j); + + nn = singleHopNN(hp); + nn->insert(j); + } + } + } + return graph; } Graph* GraphGenerator::generateMolloyReedGraph(std::string path) From 263814dbd97d1340bf9898f72902b9f86beb4aaf Mon Sep 17 00:00:00 2001 From: Federico Bond Date: Tue, 18 Jul 2017 04:07:46 -0300 Subject: [PATCH 3/5] Fix several problems and stub missing functions --- src/ComplexNets/GraphGenerator.cpp | 96 ++++++++++++++++++-------- src/ComplexNets/GraphGenerator.h | 58 ++++++---------- src/ComplexNets/NearestNeighbor.cpp | 21 ++++++ src/ComplexNets/NearestNeighbor.h | 14 ++++ src/ComplexNets/Position.h | 17 +++++ src/ComplexNetsGui.pro | 1 + src/ComplexNetsGui/inc/ui_mainwindow.h | 2 +- 7 files changed, 143 insertions(+), 66 deletions(-) create mode 100644 src/ComplexNets/NearestNeighbor.cpp create mode 100644 src/ComplexNets/NearestNeighbor.h create mode 100644 src/ComplexNets/Position.h diff --git a/src/ComplexNets/GraphGenerator.cpp b/src/ComplexNets/GraphGenerator.cpp index 5cd6432..37ffc1a 100644 --- a/src/ComplexNets/GraphGenerator.cpp +++ b/src/ComplexNets/GraphGenerator.cpp @@ -13,12 +13,6 @@ using namespace graphpp; -typedef struct Position -{ - float x; - float y; -} Position; - static const double PI = atan(1) * 4; std::vector vertexesPositions; @@ -200,15 +194,16 @@ Graph* GraphGenerator::generateHotExtendedGraph( auto minVertex = root; auto minHop = 0; - // TODO: consider how maxHop is computed + // TODO: where is maxHop updated? + double maxHop = 0; // for hop j from 1 to maxHop for (unsigned hop = 1; hop <= maxHop; hop++) { - auto nn = singleHopNN(j) - nn->insert(v); + auto nn = singleHopNN(hop); + insertNN(nn, v); - auto neighbor = nn->get(v); + auto neighbor = getNN(nn, v); auto weight = distance(v, neighbor) + xi * hop; if (weight < minWeight) @@ -218,22 +213,22 @@ Graph* GraphGenerator::generateHotExtendedGraph( minHop = hop; } - nn->delete(v) + removeNN(nn, v); } auto nn = singleHopNN(minHop + 1); - nn->insert(v); + insertNN(nn, v); // TODO: update Ti to Tr? graph->addEdge(v, minVertex); - nn = doubleHopNN(minHop + 1, minHop + 3) - nn->insert(v); + nn = doubleHopNN(minHop + 1, minHop + 3); + insertNN(nn, v); - nn = doubleHopNN(minHop - 1, minHop + 1) - nn->insert(v); + nn = doubleHopNN(minHop - 1, minHop + 1); + insertNN(nn, v); - std::pair minEdge; + std::pair minEdge; minWeight = INFINITY; minVertex = nullptr; @@ -244,13 +239,13 @@ Graph* GraphGenerator::generateHotExtendedGraph( for (auto const& k : singleHopNN(hop)) { nn = doubleHopNN(hop, hop + 2); - v = nn->get(k); + v = getNN(nn, k); auto weight = distance(k, v) - (r / n) * childCount(v); if (weight < minWeight) { minWeight = weight; - minEdge = make_pair(k, v); + minEdge = std::make_pair(k, v); minVertex = v; } } @@ -263,32 +258,77 @@ Graph* GraphGenerator::generateHotExtendedGraph( // TODO: see whiteboard for (auto const& j : BFS(root)) { - auto hj = computeWeightChange(j); + auto hj = weightChange(j); if (hj > hp) { nn = doubleHopNN(hj - 2, hj); - nn->delete(j); + removeNN(nn, j); nn = doubleHopNN(hj, hj + 2); - nn->delete(j); + removeNN(nn, j); nn = singleHopNN(hj); - nn->delete(j); + removeNN(nn, j); nn = doubleHopNN(hp - 2, hp); - nn->insert(j); + insertNN(nn, j); nn = doubleHopNN(hp, hp + 2); - nn->insert(j); + insertNN(nn, j); nn = singleHopNN(hp); - nn->insert(j); + insertNN(nn, j); } } } return graph; } +void GraphGenerator::addPosition(Vertex* v) +{ + // TODO: stub +} + +double GraphGenerator::distance(Vertex* v1, Vertex* v2) +{ + // TODO: stub + return 0; +} + +void GraphGenerator::insertNN(NearestNeighbor* nn, Vertex* v) +{ + // TODO: stub +} + +void GraphGenerator::removeNN(NearestNeighbor* nn, Vertex* v) +{ + // TODO: stub +} + +Vertex* GraphGenerator::getNN(NearestNeighbor* nn, Vertex* v) +{ + // TODO: stub + return nullptr; +} + +double GraphGenerator::weightChange(Vertex* v) +{ + // TODO: stub + return 0; +} + +unsigned GraphGenerator::childCount(Vertex* v) +{ + // TODO: stub + return 0; +} + +Position GraphGenerator::position(Vertex* v) +{ + // TODO: stub + return {0, 0}; +} + Graph* GraphGenerator::generateMolloyReedGraph(std::string path) { Graph* graph = new Graph(false, false); @@ -305,7 +345,7 @@ Graph* GraphGenerator::generateMolloyReedGraph(std::string path) * Computes the distance in a hiperbolic space between two points */ -inline double GraphGenerator::hiperbolicDistance(PolarPosition p1, PolarPosition p2) +double GraphGenerator::hiperbolicDistance(PolarPosition p1, PolarPosition p2) { return acosh( cosh(p1.r) * cosh(p2.r) - @@ -315,7 +355,7 @@ inline double GraphGenerator::hiperbolicDistance(PolarPosition p1, PolarPosition /* * Computes random polar hyperbolic coordinates */ -inline GraphGenerator::PolarPosition GraphGenerator::getRandomHyperbolicCoordinates( +PolarPosition GraphGenerator::getRandomHyperbolicCoordinates( float a, double maxr) { PolarPosition pos; diff --git a/src/ComplexNets/GraphGenerator.h b/src/ComplexNets/GraphGenerator.h index 0a3986c..e60cec7 100644 --- a/src/ComplexNets/GraphGenerator.h +++ b/src/ComplexNets/GraphGenerator.h @@ -5,54 +5,38 @@ #pragma once #include "ComplexNets/MolloyReedGraphReader.h" +#include "ComplexNets/NearestNeighbor.h" +#include "ComplexNets/Position.h" #include "ComplexNets/typedefs.h" class GraphGenerator { private: - typedef struct PolarPosition - { - double r; - double theta; - } PolarPosition; - GraphGenerator(); static GraphGenerator* instance; - float distanceBetweenVertex(unsigned int vertex1Id, unsigned int vertex2Id); - void addVertexPosition(); - void addEdges( - Graph* graph, - Vertex* vertex, - std::map distance, - unsigned int quant, - std::vector* vertexIndexes); - inline double hiperbolicDistance(PolarPosition p1, PolarPosition p2); - inline double getMaxRadius(int i, float a, float c); - inline PolarPosition getRandomHyperbolicCoordinates(float a, double maxr); + + // members related to hyperbolic graphs + double hiperbolicDistance(PolarPosition p1, PolarPosition p2); + double getMaxRadius(int i, float a, float c); + PolarPosition getRandomHyperbolicCoordinates(float a, double maxr); + + // members related to HOT Extended graphs + void addPosition(Vertex* v); + NearestNeighbor* singleHopNN(unsigned hop); + NearestNeighbor* doubleHopNN(unsigned hop1, unsigned hop2); + + void insertNN(NearestNeighbor* nn, Vertex *v); + void removeNN(NearestNeighbor* nn, Vertex *v); + Vertex* getNN(NearestNeighbor* nn, Vertex *v); + + double distance(Vertex* v1, Vertex* v2); + double weightChange(Vertex* v); + unsigned childCount(Vertex* v); + Position position(Vertex* v); public: static GraphGenerator* getInstance(); - void addOriginalVertex(Graph* graph); - void addFKPNode( - unsigned int vertexIndex, - Graph* graph, - unsigned int root, - float xi, - std::vector* vertexIndexes, - unsigned int m); - void addExtendedEdges( - unsigned int q, - unsigned int vertexIndex, - Graph* graph, - unsigned int root, - float r, - std::vector* vertexIndexes); - int chooseNewRoot( - unsigned int vertexIndex, - unsigned int t, - unsigned int root, - std::vector vertexIndexes); Graph* generateGraphFromFile(std::string path, bool directed, bool multigraph); DirectedGraph* generateDirectedGraphFromFile(std::string path, bool multigraph); diff --git a/src/ComplexNets/NearestNeighbor.cpp b/src/ComplexNets/NearestNeighbor.cpp new file mode 100644 index 0000000..c086ff9 --- /dev/null +++ b/src/ComplexNets/NearestNeighbor.cpp @@ -0,0 +1,21 @@ +// This toolbox is licensed under the Academic Free License 3.0. +// Instituto Tecnológico de Buenos Aires (ITBA). + +#include "NearestNeighbor.h" + + +void NearestNeighbor::insert(unsigned id, Position pos) +{ + // TODO: stub +} + +void NearestNeighbor::remove(unsigned id) +{ + // TODO: stub +} + +unsigned NearestNeighbor::insert(unsigned id, Position pos) +{ + // TODO: stub + return 0; +} diff --git a/src/ComplexNets/NearestNeighbor.h b/src/ComplexNets/NearestNeighbor.h new file mode 100644 index 0000000..1413ffa --- /dev/null +++ b/src/ComplexNets/NearestNeighbor.h @@ -0,0 +1,14 @@ +// This toolbox is licensed under the Academic Free License 3.0. +// Instituto Tecnológico de Buenos Aires (ITBA). + +#pragma once + +#include "ComplexNets/Position.h" + +class NearestNeighbor +{ +public: + void insert(unsigned id, Position pos); + void remove(unsigned id); + unsigned get(unsigned id); +}; diff --git a/src/ComplexNets/Position.h b/src/ComplexNets/Position.h new file mode 100644 index 0000000..e037be3 --- /dev/null +++ b/src/ComplexNets/Position.h @@ -0,0 +1,17 @@ +// This toolbox is licensed under the Academic Free License 3.0. +// Instituto Tecnológico de Buenos Aires (ITBA). + +#pragma once + +typedef struct Position +{ + // TODO: change to double? + float x; + float y; +} Position; + +typedef struct PolarPosition +{ + double r; + double theta; +} PolarPosition; diff --git a/src/ComplexNetsGui.pro b/src/ComplexNetsGui.pro index 71a0ae1..59285b7 100644 --- a/src/ComplexNetsGui.pro +++ b/src/ComplexNetsGui.pro @@ -8,6 +8,7 @@ SOURCES += ComplexNetsGui/src/*.cpp \ ComplexNets/*.cpp \ ComplexNetsCmd/*.cpp \ ComplexNetsCmd/*.c + vendor/ HEADERS += ComplexNetsGui/inc/*.h \ ComplexNets/*.h \ ComplexNetsCmd/*.h diff --git a/src/ComplexNetsGui/inc/ui_mainwindow.h b/src/ComplexNetsGui/inc/ui_mainwindow.h index 07c826f..e139fb4 100644 --- a/src/ComplexNetsGui/inc/ui_mainwindow.h +++ b/src/ComplexNetsGui/inc/ui_mainwindow.h @@ -1,7 +1,7 @@ /******************************************************************************** ** Form generated from reading UI file 'mainwindow.ui' ** -** Created by: Qt User Interface Compiler version 5.9.0 +** Created by: Qt User Interface Compiler version 5.9.1 ** ** WARNING! All changes made in this file will be lost when recompiling UI file! ********************************************************************************/ From 96b9f38c5f1f28494e0b5d186a3528052235ae2e Mon Sep 17 00:00:00 2001 From: Federico Bond Date: Wed, 19 Jul 2017 14:24:02 -0300 Subject: [PATCH 4/5] Fill more missing functions --- src/ComplexNets/GraphGenerator.cpp | 38 +++++++++++++++++------------- src/ComplexNets/GraphGenerator.h | 2 +- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/ComplexNets/GraphGenerator.cpp b/src/ComplexNets/GraphGenerator.cpp index 37ffc1a..d5ff283 100644 --- a/src/ComplexNets/GraphGenerator.cpp +++ b/src/ComplexNets/GraphGenerator.cpp @@ -203,7 +203,7 @@ Graph* GraphGenerator::generateHotExtendedGraph( auto nn = singleHopNN(hop); insertNN(nn, v); - auto neighbor = getNN(nn, v); + auto neighbor = getNN(graph, nn, v); auto weight = distance(v, neighbor) + xi * hop; if (weight < minWeight) @@ -239,7 +239,7 @@ Graph* GraphGenerator::generateHotExtendedGraph( for (auto const& k : singleHopNN(hop)) { nn = doubleHopNN(hop, hop + 2); - v = getNN(nn, k); + v = getNN(graph, nn, k); auto weight = distance(k, v) - (r / n) * childCount(v); if (weight < minWeight) @@ -286,29 +286,41 @@ Graph* GraphGenerator::generateHotExtendedGraph( void GraphGenerator::addPosition(Vertex* v) { - // TODO: stub + // assert(vertex.id == vertexesPositions.size()) + Position p = { + (float)rand() / RAND_MAX, + (float)rand() / RAND_MAX + }; + vertexesPositions.push_back(p); +} + +Position GraphGenerator::position(Vertex* v) +{ + return vertexesPositions[v->getVertexId()]; } double GraphGenerator::distance(Vertex* v1, Vertex* v2) { - // TODO: stub - return 0; + Position p1 = position(v1); + Position p2 = position(v2); + + return sqrt(pow(p2.x - p1.x, 2) + pow(p2.y - p1.y, 2)); } void GraphGenerator::insertNN(NearestNeighbor* nn, Vertex* v) { - // TODO: stub + nn->insert(v->getVertexId(), position(v)); } void GraphGenerator::removeNN(NearestNeighbor* nn, Vertex* v) { - // TODO: stub + nn->remove(v->getVertexId()); } -Vertex* GraphGenerator::getNN(NearestNeighbor* nn, Vertex* v) +Vertex* GraphGenerator::getNN(Graph *g, NearestNeighbor* nn, Vertex* v) { - // TODO: stub - return nullptr; + auto id = nn->get(v->getVertexId()); + return g->getVertexById(id); } double GraphGenerator::weightChange(Vertex* v) @@ -323,12 +335,6 @@ unsigned GraphGenerator::childCount(Vertex* v) return 0; } -Position GraphGenerator::position(Vertex* v) -{ - // TODO: stub - return {0, 0}; -} - Graph* GraphGenerator::generateMolloyReedGraph(std::string path) { Graph* graph = new Graph(false, false); diff --git a/src/ComplexNets/GraphGenerator.h b/src/ComplexNets/GraphGenerator.h index e60cec7..ff5d14a 100644 --- a/src/ComplexNets/GraphGenerator.h +++ b/src/ComplexNets/GraphGenerator.h @@ -28,7 +28,7 @@ class GraphGenerator void insertNN(NearestNeighbor* nn, Vertex *v); void removeNN(NearestNeighbor* nn, Vertex *v); - Vertex* getNN(NearestNeighbor* nn, Vertex *v); + Vertex* getNN(Graph* g, NearestNeighbor* nn, Vertex *v); double distance(Vertex* v1, Vertex* v2); double weightChange(Vertex* v); From 8a5c012fa3dbaa7ce8471de2a404c8ad804fafbf Mon Sep 17 00:00:00 2001 From: Federico Bond Date: Mon, 19 Feb 2018 09:28:57 -0300 Subject: [PATCH 5/5] Add python version of optimized hot --- src/__init__.py | 0 src/optimized_hot.py | 222 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 222 insertions(+) create mode 100644 src/__init__.py create mode 100644 src/optimized_hot.py diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/optimized_hot.py b/src/optimized_hot.py new file mode 100644 index 0000000..a07380c --- /dev/null +++ b/src/optimized_hot.py @@ -0,0 +1,222 @@ +# coding: utf-8 +from collections import defaultdict +from random import random +import math +import sys + +import logging as l +l.basicConfig(format="%(message)s", level=l.DEBUG) + + + +class Vertex(object): + + def __init__(self, id): + self.id = id + self.position = (random(), random()) + + def __repr__(self): + return "Vertex<%s>(%s, %s)" % (self.id, self.position[0], self.position[1]) + + +class Graph(object): + + def __init__(self): + self.vertices = {} + + def __repr__(self): + return "Graph(%s)" % self.vertices + + def add_vertex(self, v): + self.vertices[v] = [] + + def add_edge(self, v1, v2): + self.vertices[v1].append(v2) + self.vertices[v2].append(v1) + + def breadth_first_search(self, root): + visited = set() + q = [root] + + while q: + v = q.pop(0) + visited.add(v) + for j in self.vertices[v]: + if j not in visited: + q.append(j) + yield v + + +def export(graph, file_obj): + for v in graph.vertices: + for j in graph.vertices[v]: + file_obj.write("%s\t%s\n" % (v.id, j.id)) + + +# HOT Extended Model +# The Paper can be checked in: +# http://cnet.fi.uba.ar/ignacio.alvarez-hamelin/pdf/model_internet_jiah_ns.pdf +# +# m: +# number of edges in each new vertex (k in the paper) +# n: +# total number of nodes +# xi: +# parameter used to select the neighbors for new vertex. (theta in the paper) +# q: +# number of edges added in the graph after of connect a vertex. (q in the paper) +# r: +# parameter used to select the edges in the graph after connecting a vertex (γ in the paper) +# t: +# parameter that represents how many rounds to do until a new root selection (τ in the paper) + +def hot_extended(m, n, xi, q, r, t): + + graph = Graph() + + # first we add the root vertex + root = Vertex(0) + graph.add_vertex(root) + + # we then proceed to add the n-1 remaining nodes + for i in range(1, n): + + # we add the new vertex with a random position + v = Vertex(i) + graph.add_vertex(v) + + w_min = distance(v, root) + v_min = root + h_min = 0 + + h_max = 0; + + # for hop j from 1 to h_max + for j in range(1, h_max): + + # we insert our new vertex in the delaunay for each hop + d_j = delaunay(j) + d_j.insert(v) + + # we get the nearest neighbor of v in this hop + neighbor = d_j.nearest_neighbor(v) + + # we compute the weighted distance to this neighbor + w = distance(v, neighbor) + xi * j + + # if this is the nearest neighbor up to this hop, update the min neighbor + if w < w_min: + w_min = w + v_min = neighbor + h_min = j + + # leave delaunay for hop as we without changes + d_j.remove(v) + + # we will connect v to a neighbor that is at hop h_min, so add it to the next hop delaunay + delaunay(h_min + 1).insert(v) + + # connect v with its nearest weighted neighbor + # @question: why do we add a single edge here? + graph.add_edge(v, v_min) + + # this should end the step 1 described in the paper + # @question: shouldn't we add m new edges (q in the paper)? + + # now v should be available in the delaunay for hops pairs 1+ and 1- + delaunay(h_min + 1, h_min + 3).insert(v) + delaunay(h_min - 1, h_min + 1).insert(v) + + # this should be the start of step 2 described in the paper + e_min = None + w_min = float('inf') + v_min = None + + for j in range(0, h_max - 2): + + for k in delaunay(j): + + d_ = delaunay(hop, hop + 2) + v = d_.nearest_neighbor(k) + + # @question: how do we compute child count here? we need to mark the parent edge somehow to skip it + w = distance(k, v) - (r / n) * child_count(v); + + if w < w_min: + w_min = w + v_min = v + e_min = (k, v) + + # graph.add_edge(*e_min); + # @question: why do we add a single edge here instead of q? + + hp = 0 + + for j in graph.breadth_first_search(root): + # @question: is this where we compute T(j)? + + hj = weight_change(j); + + if (hj > hp): + delaunay(hj - 2, hj).remove(j) + delaunay(hj, hj + 2).remove(j) + delaunay(hj).remove(j) + + delaunay(hp - 2, hp).insert(j) + delaunay(hp, hp + 2).insert(j) + delaunay(hp).insert(j) + + # @question: shouldn't this be hp = hj? + hj = hp + + # @question: original algorithm should change root from time to time? this changes hop calculation + + return graph + +def distance(v1, v2): + return math.hypot(v2.position[0] - v1.position[0], v2.position[1] - v1.position[1]) + +def weight_change(v): + return 0 # stub + +def child_count(v): + return float('inf') # stub + + +class Delaunay(object): # stub for now + + def __init__(self): + self.vertices = [] + + def insert(self, v): + self.vertices.append(v) + + def remove(self, v): + self.vertices.remove(v) + + def nearest_neighbor(self, v): + min_d = float('inf') + min_w = None + + for w in self.vertices: + if v == w: + continue + + d = distance(v, w) + if d < min_d: + min_d = d + min_w = w + + return min_w + + +delaunay_map = defaultdict(Delaunay) + +def delaunay(hop, hop_s=None): + key = (hop, hop_s) + return delaunay_map[key] + + +if __name__ == "__main__": + g = hot_extended(2, 10, 0.3, 2, 0.2, 0.1) + # export(g, sys.stdout)