2010-07-09 05:05:40 -04:00
|
|
|
/*
|
2013-10-14 07:42:28 -04:00
|
|
|
|
|
|
|
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
|
|
|
|
All rights reserved.
|
|
|
|
|
|
|
|
Redistribution and use in source and binary forms, with or without modification,
|
|
|
|
are permitted provided that the following conditions are met:
|
|
|
|
|
|
|
|
Redistributions of source code must retain the above copyright notice, this list
|
|
|
|
of conditions and the following disclaimer.
|
|
|
|
Redistributions in binary form must reproduce the above copyright notice, this
|
|
|
|
list of conditions and the following disclaimer in the documentation and/or
|
|
|
|
other materials provided with the distribution.
|
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
|
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
|
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
|
|
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
|
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
|
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
|
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
*/
|
2010-07-09 05:05:40 -04:00
|
|
|
|
2014-05-07 12:39:16 -04:00
|
|
|
#ifndef DYNAMICGRAPH_H
|
|
|
|
#define DYNAMICGRAPH_H
|
2010-07-09 05:05:40 -04:00
|
|
|
|
2013-06-24 17:02:28 -04:00
|
|
|
#include "../DataStructures/DeallocatingVector.h"
|
|
|
|
|
2013-06-26 09:50:06 -04:00
|
|
|
#include <boost/assert.hpp>
|
2014-05-13 10:56:30 -04:00
|
|
|
#include <boost/range/irange.hpp>
|
2014-05-07 08:44:18 -04:00
|
|
|
|
|
|
|
#include <cstdint>
|
2013-06-24 17:02:28 -04:00
|
|
|
|
2010-07-09 05:05:40 -04:00
|
|
|
#include <algorithm>
|
2010-09-13 10:16:07 -04:00
|
|
|
#include <limits>
|
2013-06-24 17:02:28 -04:00
|
|
|
#include <vector>
|
2014-05-20 17:58:32 -04:00
|
|
|
#include <atomic>
|
2012-11-15 07:39:23 -05:00
|
|
|
|
2014-05-07 12:39:16 -04:00
|
|
|
template <typename EdgeDataT> class DynamicGraph
|
|
|
|
{
|
|
|
|
public:
|
2014-05-13 10:56:30 -04:00
|
|
|
typedef decltype(boost::irange(0u,0u)) EdgeRange;
|
2014-05-07 12:39:16 -04:00
|
|
|
typedef EdgeDataT EdgeData;
|
|
|
|
typedef unsigned NodeIterator;
|
|
|
|
typedef unsigned EdgeIterator;
|
|
|
|
|
|
|
|
class InputEdge
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
NodeIterator source;
|
|
|
|
NodeIterator target;
|
|
|
|
EdgeDataT data;
|
|
|
|
bool operator<(const InputEdge &right) const
|
|
|
|
{
|
|
|
|
if (source != right.source)
|
|
|
|
return source < right.source;
|
|
|
|
return target < right.target;
|
2011-10-10 12:56:01 -04:00
|
|
|
}
|
2014-05-07 12:39:16 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
// Constructs an empty graph with a given number of nodes.
|
2014-07-02 09:27:09 -04:00
|
|
|
explicit DynamicGraph(int32_t nodes) : number_of_nodes(nodes), number_of_edges(0)
|
2014-05-07 12:39:16 -04:00
|
|
|
{
|
2014-07-02 09:27:09 -04:00
|
|
|
m_nodes.reserve(number_of_nodes);
|
|
|
|
m_nodes.resize(number_of_nodes);
|
2014-05-07 12:39:16 -04:00
|
|
|
|
2014-07-02 09:27:09 -04:00
|
|
|
m_edges.reserve(number_of_nodes * 1.1);
|
|
|
|
m_edges.resize(number_of_nodes);
|
2014-05-07 12:39:16 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class ContainerT> DynamicGraph(const int32_t nodes, const ContainerT &graph)
|
|
|
|
{
|
2014-07-02 09:27:09 -04:00
|
|
|
number_of_nodes = nodes;
|
|
|
|
number_of_edges = (EdgeIterator)graph.size();
|
|
|
|
m_nodes.reserve(number_of_nodes + 1);
|
|
|
|
m_nodes.resize(number_of_nodes + 1);
|
2014-05-07 12:39:16 -04:00
|
|
|
EdgeIterator edge = 0;
|
|
|
|
EdgeIterator position = 0;
|
2014-07-02 09:27:09 -04:00
|
|
|
for (NodeIterator node = 0; node < number_of_nodes; ++node)
|
2014-05-07 12:39:16 -04:00
|
|
|
{
|
|
|
|
EdgeIterator lastEdge = edge;
|
2014-07-02 09:27:09 -04:00
|
|
|
while (edge < number_of_edges && graph[edge].source == node)
|
2014-05-07 12:39:16 -04:00
|
|
|
{
|
|
|
|
++edge;
|
2010-07-09 05:05:40 -04:00
|
|
|
}
|
2014-05-07 12:39:16 -04:00
|
|
|
m_nodes[node].firstEdge = position;
|
|
|
|
m_nodes[node].edges = edge - lastEdge;
|
|
|
|
position += m_nodes[node].edges;
|
|
|
|
}
|
|
|
|
m_nodes.back().firstEdge = position;
|
2014-06-17 10:00:42 -04:00
|
|
|
m_edges.reserve(static_cast<std::size_t>(position * 1.1));
|
2014-05-07 12:39:16 -04:00
|
|
|
m_edges.resize(position);
|
|
|
|
edge = 0;
|
2014-07-02 09:27:09 -04:00
|
|
|
for (NodeIterator node = 0; node < number_of_nodes; ++node)
|
2014-05-07 12:39:16 -04:00
|
|
|
{
|
|
|
|
for (EdgeIterator i = m_nodes[node].firstEdge,
|
|
|
|
e = m_nodes[node].firstEdge + m_nodes[node].edges;
|
|
|
|
i != e;
|
|
|
|
++i)
|
|
|
|
{
|
|
|
|
m_edges[i].target = graph[edge].target;
|
|
|
|
m_edges[i].data = graph[edge].data;
|
2014-07-02 08:36:20 -04:00
|
|
|
// BOOST_ASSERT_MSG(graph[edge].data.distance > 0, "edge distance invalid");
|
2014-05-07 12:39:16 -04:00
|
|
|
++edge;
|
2010-07-09 05:05:40 -04:00
|
|
|
}
|
|
|
|
}
|
2014-05-07 12:39:16 -04:00
|
|
|
}
|
2010-09-13 10:16:07 -04:00
|
|
|
|
2014-05-07 12:39:16 -04:00
|
|
|
~DynamicGraph() {}
|
2010-09-13 10:16:07 -04:00
|
|
|
|
2014-07-02 09:27:09 -04:00
|
|
|
unsigned GetNumberOfNodes() const { return number_of_nodes; }
|
2010-09-13 10:16:07 -04:00
|
|
|
|
2014-07-02 09:27:09 -04:00
|
|
|
unsigned GetNumberOfEdges() const { return number_of_edges; }
|
2010-09-13 10:16:07 -04:00
|
|
|
|
2014-05-07 12:39:16 -04:00
|
|
|
unsigned GetOutDegree(const NodeIterator n) const { return m_nodes[n].edges; }
|
2010-09-13 10:16:07 -04:00
|
|
|
|
2014-05-20 09:40:14 -04:00
|
|
|
unsigned GetDirectedOutDegree(const NodeIterator n) const
|
|
|
|
{
|
|
|
|
unsigned degree = 0;
|
|
|
|
for(EdgeIterator edge = BeginEdges(n); edge < EndEdges(n); ++edge)
|
|
|
|
{
|
|
|
|
if (GetEdgeData(edge).forward)
|
|
|
|
{
|
|
|
|
++degree;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return degree;
|
|
|
|
}
|
|
|
|
|
2014-05-07 12:39:16 -04:00
|
|
|
NodeIterator GetTarget(const EdgeIterator e) const { return NodeIterator(m_edges[e].target); }
|
2010-09-13 10:16:07 -04:00
|
|
|
|
2014-05-07 12:39:16 -04:00
|
|
|
void SetTarget(const EdgeIterator e, const NodeIterator n) { m_edges[e].target = n; }
|
2013-12-12 18:32:12 -05:00
|
|
|
|
2014-05-07 12:39:16 -04:00
|
|
|
EdgeDataT &GetEdgeData(const EdgeIterator e) { return m_edges[e].data; }
|
2010-09-13 10:16:07 -04:00
|
|
|
|
2014-05-07 12:39:16 -04:00
|
|
|
const EdgeDataT &GetEdgeData(const EdgeIterator e) const { return m_edges[e].data; }
|
2010-09-13 10:16:07 -04:00
|
|
|
|
2014-05-07 12:39:16 -04:00
|
|
|
EdgeIterator BeginEdges(const NodeIterator n) const
|
|
|
|
{
|
|
|
|
return EdgeIterator(m_nodes[n].firstEdge);
|
|
|
|
}
|
2010-09-13 10:16:07 -04:00
|
|
|
|
2014-05-07 12:39:16 -04:00
|
|
|
EdgeIterator EndEdges(const NodeIterator n) const
|
|
|
|
{
|
|
|
|
return EdgeIterator(m_nodes[n].firstEdge + m_nodes[n].edges);
|
|
|
|
}
|
2010-09-13 10:16:07 -04:00
|
|
|
|
2014-05-19 07:00:27 -04:00
|
|
|
EdgeRange GetAdjacentEdgeRange(const NodeIterator node) const
|
2014-05-13 10:56:30 -04:00
|
|
|
{
|
|
|
|
return boost::irange(BeginEdges(node), EndEdges(node));
|
|
|
|
}
|
|
|
|
|
2014-07-02 09:27:09 -04:00
|
|
|
NodeIterator InsertNode()
|
|
|
|
{
|
|
|
|
m_nodes.emplace_back(m_nodes.back());
|
|
|
|
number_of_nodes +=1;
|
|
|
|
|
|
|
|
return number_of_nodes;
|
|
|
|
}
|
|
|
|
|
2014-05-07 12:39:16 -04:00
|
|
|
// adds an edge. Invalidates edge iterators for the source node
|
|
|
|
EdgeIterator InsertEdge(const NodeIterator from, const NodeIterator to, const EdgeDataT &data)
|
|
|
|
{
|
|
|
|
Node &node = m_nodes[from];
|
|
|
|
EdgeIterator newFirstEdge = node.edges + node.firstEdge;
|
|
|
|
if (newFirstEdge >= m_edges.size() || !isDummy(newFirstEdge))
|
|
|
|
{
|
|
|
|
if (node.firstEdge != 0 && isDummy(node.firstEdge - 1))
|
|
|
|
{
|
|
|
|
node.firstEdge--;
|
|
|
|
m_edges[node.firstEdge] = m_edges[node.firstEdge + node.edges];
|
2010-07-09 05:05:40 -04:00
|
|
|
}
|
2014-05-07 12:39:16 -04:00
|
|
|
else
|
|
|
|
{
|
|
|
|
EdgeIterator newFirstEdge = (EdgeIterator)m_edges.size();
|
|
|
|
unsigned newSize = node.edges * 1.1 + 2;
|
|
|
|
EdgeIterator requiredCapacity = newSize + m_edges.size();
|
|
|
|
EdgeIterator oldCapacity = m_edges.capacity();
|
|
|
|
if (requiredCapacity >= oldCapacity)
|
|
|
|
{
|
|
|
|
m_edges.reserve(requiredCapacity * 1.1);
|
2010-09-13 10:16:07 -04:00
|
|
|
}
|
2014-05-07 12:39:16 -04:00
|
|
|
m_edges.resize(m_edges.size() + newSize);
|
|
|
|
for (EdgeIterator i = 0; i < node.edges; ++i)
|
|
|
|
{
|
|
|
|
m_edges[newFirstEdge + i] = m_edges[node.firstEdge + i];
|
|
|
|
makeDummy(node.firstEdge + i);
|
2010-07-09 05:05:40 -04:00
|
|
|
}
|
2014-05-07 12:39:16 -04:00
|
|
|
for (EdgeIterator i = node.edges + 1; i < newSize; ++i)
|
|
|
|
makeDummy(newFirstEdge + i);
|
|
|
|
node.firstEdge = newFirstEdge;
|
2010-07-09 05:05:40 -04:00
|
|
|
}
|
|
|
|
}
|
2014-05-07 12:39:16 -04:00
|
|
|
Edge &edge = m_edges[node.firstEdge + node.edges];
|
|
|
|
edge.target = to;
|
|
|
|
edge.data = data;
|
2014-07-02 09:27:09 -04:00
|
|
|
++number_of_edges;
|
2014-05-07 12:39:16 -04:00
|
|
|
++node.edges;
|
|
|
|
return EdgeIterator(node.firstEdge + node.edges);
|
|
|
|
}
|
|
|
|
|
|
|
|
// removes an edge. Invalidates edge iterators for the source node
|
|
|
|
void DeleteEdge(const NodeIterator source, const EdgeIterator e)
|
|
|
|
{
|
|
|
|
Node &node = m_nodes[source];
|
2014-07-02 09:27:09 -04:00
|
|
|
--number_of_edges;
|
2014-05-07 12:39:16 -04:00
|
|
|
--node.edges;
|
|
|
|
BOOST_ASSERT(std::numeric_limits<unsigned>::max() != node.edges);
|
|
|
|
const unsigned last = node.firstEdge + node.edges;
|
|
|
|
BOOST_ASSERT(std::numeric_limits<unsigned>::max() != last);
|
|
|
|
// swap with last edge
|
|
|
|
m_edges[e] = m_edges[last];
|
|
|
|
makeDummy(last);
|
|
|
|
}
|
|
|
|
|
|
|
|
// removes all edges (source,target)
|
|
|
|
int32_t DeleteEdgesTo(const NodeIterator source, const NodeIterator target)
|
|
|
|
{
|
|
|
|
int32_t deleted = 0;
|
|
|
|
for (EdgeIterator i = BeginEdges(source), iend = EndEdges(source); i < iend - deleted; ++i)
|
|
|
|
{
|
|
|
|
if (m_edges[i].target == target)
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
|
|
|
deleted++;
|
|
|
|
m_edges[i] = m_edges[iend - deleted];
|
|
|
|
makeDummy(iend - deleted);
|
|
|
|
} while (i < iend - deleted && m_edges[i].target == target);
|
|
|
|
}
|
2010-09-13 10:16:07 -04:00
|
|
|
}
|
2010-07-09 05:05:40 -04:00
|
|
|
|
2014-07-02 09:27:09 -04:00
|
|
|
number_of_edges -= deleted;
|
2014-05-07 12:39:16 -04:00
|
|
|
m_nodes[source].edges -= deleted;
|
|
|
|
|
|
|
|
return deleted;
|
|
|
|
}
|
|
|
|
|
|
|
|
// searches for a specific edge
|
|
|
|
EdgeIterator FindEdge(const NodeIterator from, const NodeIterator to) const
|
|
|
|
{
|
|
|
|
for (EdgeIterator i = BeginEdges(from), iend = EndEdges(from); i != iend; ++i)
|
|
|
|
{
|
|
|
|
if (to == m_edges[i].target)
|
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
2010-09-13 10:16:07 -04:00
|
|
|
}
|
2014-05-07 12:39:16 -04:00
|
|
|
return EndEdges(from);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
bool isDummy(const EdgeIterator edge) const
|
|
|
|
{
|
|
|
|
return m_edges[edge].target == (std::numeric_limits<NodeIterator>::max)();
|
|
|
|
}
|
|
|
|
|
|
|
|
void makeDummy(const EdgeIterator edge)
|
|
|
|
{
|
|
|
|
m_edges[edge].target = (std::numeric_limits<NodeIterator>::max)();
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Node
|
|
|
|
{
|
|
|
|
// index of the first edge
|
|
|
|
EdgeIterator firstEdge;
|
|
|
|
// amount of edges
|
|
|
|
unsigned edges;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Edge
|
|
|
|
{
|
|
|
|
NodeIterator target;
|
|
|
|
EdgeDataT data;
|
|
|
|
};
|
|
|
|
|
2014-07-02 09:27:09 -04:00
|
|
|
NodeIterator number_of_nodes;
|
|
|
|
std::atomic_uint number_of_edges;
|
2014-05-07 12:39:16 -04:00
|
|
|
|
|
|
|
std::vector<Node> m_nodes;
|
|
|
|
DeallocatingVector<Edge> m_edges;
|
2010-07-09 05:05:40 -04:00
|
|
|
};
|
|
|
|
|
2014-05-07 12:39:16 -04:00
|
|
|
#endif // DYNAMICGRAPH_H
|