Commit 247ecf5c authored by Tiago Peixoto's avatar Tiago Peixoto

price_network(): Improve performance and clarify documentation

parent 9d1777af
......@@ -23,7 +23,8 @@
#include "graph_util.hh"
#include "random.hh"
#include "hash_map_wrap.hh"
#include "idx_map.hh"
#include "dynamic_sampler.hh"
#include <map>
#include <iostream>
......@@ -40,59 +41,49 @@ struct get_price
rng_t& rng) const
{
typedef typename mpl::if_<typename is_directed_::apply<Graph>::type,
in_degreeS, out_degreeS>::type DegSelector;
in_degreeS, out_degreeS>::type Deg;
map<double, typename graph_traits<Graph>::vertex_descriptor> probs;
DynamicSampler<typename graph_traits<Graph>::vertex_descriptor> sampler;
size_t n_possible = 0;
double cp = 0, p = 0;
typename graph_traits<Graph>::vertex_iterator vi, vi_end;
for (tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
double p;
for (auto v : vertices_range(g))
{
p = pow(DegSelector()(*vi, g) + c, gamma);
cp += p;
p = pow(Deg()(v, g) + c, gamma);
if (p < 0)
throw GraphException("Cannot connect edges: probabilities are negative");
if (p > 0)
{
probs.insert(make_pair(cp, *vi));
++n_possible;
}
sampler.insert(v, p);
}
if (probs.empty() || probs.rbegin()->first <= 0)
throw GraphException("Cannot connect edges: probabilities are <= 0!");
if (sampler.empty())
throw GraphException("Cannot connect edges: seed graph is empty, or has zero probability");
gt_hash_set<typename graph_traits<Graph>::vertex_descriptor> visited;
idx_set<typename graph_traits<Graph>::vertex_descriptor> visited;
for (size_t i = 0; i < N; ++i)
{
visited.clear();
typename graph_traits<Graph>::vertex_descriptor v = add_vertex(g);
for (size_t j = 0; j < min(m, n_possible); ++j)
auto v = add_vertex(g);
for (size_t j = 0; j < std::min(m, sampler.size()); ++j)
{
uniform_real_distribution<> sample(0, probs.rbegin()->first);
double r = sample(rng);
auto iter = probs.lower_bound(r);
typename graph_traits<Graph>::vertex_descriptor w =
iter->second;
auto w = sampler.sample(rng);
if (visited.find(w) != visited.end())
{
--j;
continue;
}
visited.insert(w);
add_edge(v, w, g);
p = abs(pow(DegSelector()(w, g) + c, gamma)
- pow(DegSelector()(w, g) + c - 1, gamma));
if (p > 0)
probs.insert(make_pair(probs.rbegin()->first + p, w));
p = pow(Deg()(w, g) + c, gamma);
sampler.remove(w);
sampler.insert(w, p);
}
p = pow(DegSelector()(v, g) + c, gamma);
p = pow(Deg()(v, g) + c, gamma);
if (p > 0)
{
probs.insert(make_pair(probs.rbegin()->first + p, v));
n_possible += 1;
}
sampler.insert(v, p);
}
}
};
......
......@@ -1743,7 +1743,7 @@ def price_network(N, m=1, c=None, gamma=1, directed=True, seed_graph=None):
Constant factor added to the probability of a vertex receiving an edge
(see notes below).
gamma : float (optional, default: ``1``)
Preferential attachment power (see notes below).
Preferential attachment exponent (see notes below).
directed : bool (optional, default: ``True``)
If ``True``, a Price network is generated. If ``False``, a
Barabási-Albert network is generated.
......@@ -1768,9 +1768,15 @@ def price_network(N, m=1, c=None, gamma=1, directed=True, seed_graph=None):
\pi \propto k^\gamma + c
where :math:`k` is the in-degree of the vertex (or simply the degree in the
undirected case). If :math:`\gamma=1`, the tail of resulting in-degree
distribution of the directed case is given by
where :math:`k` is the (in-)degree of the vertex (or simply the degree in
the undirected case).
Note that for directed graphs we must have :math:`c \ge 0`, and for
undirected graphs, :math:`c > -\min(k_{\text{min}}, m)^{\gamma}`, where
:math:`k_{\text{min}}` is the smallest degree in the seed graph.
If :math:`\gamma=1`, the tail of resulting in-degree distribution of the
directed case is given by
.. math::
......@@ -1786,7 +1792,7 @@ def price_network(N, m=1, c=None, gamma=1, directed=True, seed_graph=None):
scale-free (see [dorogovtsev-evolution]_ for details).
Note that if `seed_graph` is not given, the algorithm will *always* start
with one node if :math:`c > 0`, or with two nodes with a link between them
with one node if :math:`c > 0`, or with two nodes with an edge between them
otherwise. If :math:`m > 1`, the degree of the newly added vertices will be
vary dynamically as :math:`m'(t) = \min(m, V(t))`, where :math:`V(t)` is the
number of vertices added so far. If this behaviour is undesired, a proper
......@@ -1849,6 +1855,7 @@ def price_network(N, m=1, c=None, gamma=1, directed=True, seed_graph=None):
.. [dorogovtsev-evolution] S. N. Dorogovtsev and J. F. F. Mendes, "Evolution
of networks", Advances in Physics, 2002, Vol. 51, No. 4, 1079-1187,
:doi:`10.1080/00018730110112519`
"""
if c is None:
......@@ -1864,7 +1871,13 @@ def price_network(N, m=1, c=None, gamma=1, directed=True, seed_graph=None):
N -= g.num_vertices()
else:
g = seed_graph
if ((directed and c < 0) or
(not directed and c <= -min(g.degree_property_map("out").fa.min(), m) ** gamma)):
raise ValueError("Parameter 'c' is too small, and yields negative probabilities")
libgraph_tool_generation.price(g._Graph__graph, N, gamma, c, m, _get_rng())
return g
def condensation_graph(g, prop, vweight=None, eweight=None, avprops=None,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment