Commit c3a6567d authored by Tiago Peixoto's avatar Tiago Peixoto

* src/graph-tool: change layout and community graph options.

	* src/boost-workaround/boost/graph/kamada_kawai_spring_layout.hpp: annotated code with openmp constructs.

	* src/graph/graph_adaptor.hh: graph_type should be a typedef to the original graph.

	* src/graph/graph_properties.hh, src/graph/graph_properties.cc: added pos_t type.

	* src/boost-workaround/boost/graph/fruchterman_reingold.hpp: annotated code with openmp constructs.

	* src/graph/graph_layout.cc: new file with graph layout routines.

	* src/graph/graph.cc: removed graph layout routines.

	* src/graph/graph_community_network.cc (struct get_community_network): fixed inversion of directedness test.

	* src/graph/graph.cc (GraphInterface::LabelComponents): use vector_property_map instead of HashedDescriptor. Don't use a static map!

	* src/graph/graph_adaptor.hh: fixed edge descriptor equality comparison, which must rely on underlying edge, regardless of whether it's inverted or not.


git-svn-id: https://svn.forked.de/graph-tool/trunk@121 d4600afd-f417-0410-95de-beed9576f240
parent d997442a
2007-08-08 Tiago de Paula Peixoto <tiago@forked.de>
* src/graph-tool: change layout and community graph options.
* src/boost-workaround/boost/graph/kamada_kawai_spring_layout.hpp: annotated code with openmp constructs.
* src/graph/graph_adaptor.hh: graph_type should be a typedef to the original graph.
* src/graph/graph_properties.hh, src/graph/graph_properties.cc: added pos_t type.
* src/boost-workaround/boost/graph/fruchterman_reingold.hpp: annotated code with openmp constructs.
* src/graph/graph_layout.cc: new file with graph layout routines.
* src/graph/graph.cc: removed graph layout routines.
2007-08-06 Tiago de Paula Peixoto <tiago@forked.de>
* src/graph/graph_community_network.cc (struct get_community_network): fixed inversion of directedness test.
2007-08-05 Tiago de Paula Peixoto <tiago@forked.de>
* src/graph/graph.cc (GraphInterface::LabelComponents): use vector_property_map instead of HashedDescriptor. Don't use a static map!
2007-08-01 Tiago de Paula Peixoto <tiago@forked.de>
* src/graph/graph_adaptor.hh: fixed edge descriptor equality comparison, which must rely on underlying edge, regardless of whether it's inverted or not.
* src/graph/graph_rewiring.cc: fixed possible infinite loop in correlated rewiring without self-loops and parallel edges.
* src/graph/graph.cc (GraphInterface::LabelParallelEdges): use long instead of size_t for parallel edges property.
* src/graph/graph_properties.cc: call size_t by "size_t" not "long", since those are not the same type. This removes a bug where it is impossible to create/edit properties with type long.
......
// Copyright 2004 The Trustees of Indiana University.
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// Authors: Douglas Gregor
......@@ -73,12 +73,20 @@ struct all_force_pairs
void operator()(const Graph& g, ApplyForce apply_force)
{
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
vertex_iterator v, end;
for (tie(v, end) = vertices(g); v != end; ++v) {
vertex_iterator u = v;
for (++u; u != end; ++u) {
apply_force(*u, *v);
apply_force(*v, *u);
int i, N = num_vertices(g);
#pragma omp parallel for default(shared) private(i) schedule(dynamic)
for (i = 0; i < N; ++i)
{
typename graph_traits<Graph>::vertex_descriptor v = vertex(i, g);
if (v == graph_traits<Graph>::null_vertex())
continue;
for (int j = i+1; j < N; ++j)
{
typename graph_traits<Graph>::vertex_descriptor u = vertex(j, g);
if (u == graph_traits<Graph>::null_vertex())
continue;
apply_force(u, v);
apply_force(v, u);
}
}
}
......@@ -109,18 +117,31 @@ struct grid_force_pairs
std::size_t columns = std::size_t(width / two_k + Dim(1));
std::size_t rows = std::size_t(height / two_k + Dim(1));
buckets_t buckets(rows * columns);
vertex_iterator v, v_end;
for (tie(v, v_end) = vertices(g); v != v_end; ++v) {
std::size_t column = std::size_t((position[*v].x + width / 2) / two_k);
std::size_t row = std::size_t((position[*v].y + height / 2) / two_k);
int i, N = num_vertices(g);
#pragma omp parallel for default(shared) private(i) schedule(dynamic)
for (i = 0; i < N; ++i)
{
typename graph_traits<Graph>::vertex_descriptor v = vertex(i, g);
if (v == graph_traits<Graph>::null_vertex())
continue;
std::size_t column = std::size_t((position[v].x + width / 2) / two_k);
std::size_t row = std::size_t((position[v].y + height / 2) / two_k);
if (column >= columns) column = columns - 1;
if (row >= rows) row = rows - 1;
buckets[row * columns + column].push_back(*v);
#pragma omp critical
{
buckets[row * columns + column].push_back(v);
}
}
for (std::size_t row = 0; row < rows; ++row)
for (std::size_t column = 0; column < columns; ++column) {
N = rows * columns;
#pragma omp parallel for default(shared) private(i) schedule(dynamic)
for (i = 0; i < N; ++i)
{
std::size_t row = i / rows;
std::size_t column = i % rows;
bucket_t& bucket = buckets[row * columns + column];
typedef typename bucket_t::iterator bucket_iterator;
for (bucket_iterator u = bucket.begin(); u != bucket.end(); ++u) {
......@@ -223,8 +244,14 @@ namespace detail {
Dim delta_y = position[v].y - position[u].y;
Dim dist = sqrt(delta_x * delta_x + delta_y * delta_y);
Dim fr = repulsive_force(u, v, k, dist, g);
displacement[v].x += delta_x / dist * fr;
displacement[v].y += delta_y / dist * fr;
Dim dx = delta_x / dist * fr;
Dim dy = delta_y / dist * fr;
Dim& x = displacement[v].x;
Dim& y = displacement[v].y;
#pragma omp atomic
x += dx;
#pragma omp atomic
y += dy;
}
}
......@@ -256,6 +283,7 @@ fruchterman_reingold_force_directed_layout
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef typename graph_traits<Graph>::edge_iterator edge_iterator;
typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
#ifndef BOOST_NO_STDC_NAMESPACE
using std::sqrt;
......@@ -269,25 +297,39 @@ fruchterman_reingold_force_directed_layout
RepulsiveForce, Dim, Graph>
apply_force(position, displacement, repulsive_force, k, g);
std::vector<edge_descriptor> edge_list;
edge_list.reserve(num_edges(g));
edge_iterator e, e_end;
for (tie(e, e_end) = edges(g); e != e_end; ++e)
edge_list.push_back(*e);
Dim temp = cool();
if (temp) do {
// Calculate repulsive forces
vertex_iterator v, v_end;
for (tie(v, v_end) = vertices(g); v != v_end; ++v) {
displacement[*v].x = 0;
displacement[*v].y = 0;
int i, N = num_vertices(g);
#pragma omp parallel for default(shared) private(i) schedule(dynamic)
for (i = 0; i < N; ++i)
{
typename graph_traits<Graph>::vertex_descriptor v = vertex(i, g);
if (v == graph_traits<Graph>::null_vertex())
continue;
displacement[v].x = 0;
displacement[v].y = 0;
}
force_pairs(g, apply_force);
// Calculate attractive forces
edge_iterator e, e_end;
for (tie(e, e_end) = edges(g); e != e_end; ++e) {
vertex_descriptor v = source(*e, g);
vertex_descriptor u = target(*e, g);
N = edge_list.size();
#pragma omp parallel for default(shared) private(i) schedule(dynamic)
for (i = 0; i < N; ++i)
{
edge_descriptor e = edge_list[i];
vertex_descriptor v = source(e, g);
vertex_descriptor u = target(e, g);
Dim delta_x = position[v].x - position[u].x;
Dim delta_y = position[v].y - position[u].y;
Dim dist = sqrt(delta_x * delta_x + delta_y * delta_y);
Dim fa = attractive_force(*e, k, dist, g);
Dim fa = attractive_force(e, k, dist, g);
displacement[v].x -= delta_x / dist * fa;
displacement[v].y -= delta_y / dist * fa;
......@@ -296,25 +338,32 @@ fruchterman_reingold_force_directed_layout
}
// Update positions
for (tie(v, v_end) = vertices(g); v != v_end; ++v) {
N = num_vertices(g);
#pragma omp parallel for default(shared) private(i) schedule(dynamic)
for (i = 0; i < N; ++i)
{
typename graph_traits<Graph>::vertex_descriptor v = vertex(i, g);
if (v == graph_traits<Graph>::null_vertex())
continue;
BOOST_USING_STD_MIN();
BOOST_USING_STD_MAX();
Dim disp_size = sqrt(displacement[*v].x * displacement[*v].x
+ displacement[*v].y * displacement[*v].y);
position[*v].x += displacement[*v].x / disp_size
Dim disp_size = sqrt(displacement[v].x * displacement[v].x
+ displacement[v].y * displacement[v].y);
position[v].x += displacement[v].x / disp_size
* min BOOST_PREVENT_MACRO_SUBSTITUTION (disp_size, temp);
position[*v].y += displacement[*v].y / disp_size
position[v].y += displacement[v].y / disp_size
* min BOOST_PREVENT_MACRO_SUBSTITUTION (disp_size, temp);
position[*v].x = min BOOST_PREVENT_MACRO_SUBSTITUTION
position[v].x = min BOOST_PREVENT_MACRO_SUBSTITUTION
(width / 2,
max BOOST_PREVENT_MACRO_SUBSTITUTION(-width / 2,
position[*v].x));
position[*v].y = min BOOST_PREVENT_MACRO_SUBSTITUTION
position[v].x));
position[v].y = min BOOST_PREVENT_MACRO_SUBSTITUTION
(height / 2,
max BOOST_PREVENT_MACRO_SUBSTITUTION(-height / 2,
position[*v].y));
position[v].y));
}
} while ((temp = cool()));
} while ( (temp = cool()) );
}
namespace detail {
......@@ -362,7 +411,7 @@ namespace detail {
error_property_not_found,
const bgl_named_params<Param, Tag, Rest>& params)
{
std::vector<simple_point<double> > displacements(num_vertices(g));
std::vector<simple_point<Dim> > displacements(num_vertices(g));
fruchterman_reingold_force_directed_layout
(g, position, width, height, attractive_force, repulsive_force,
force_pairs, cool,
......@@ -370,7 +419,7 @@ namespace detail {
(displacements.begin(),
choose_const_pmap(get_param(params, vertex_index), g,
vertex_index),
simple_point<double>()));
simple_point<Dim>()));
}
};
......@@ -398,7 +447,7 @@ fruchterman_reingold_force_directed_layout
choose_param(get_param(params, force_pairs_t()),
make_grid_force_pairs(width, height, position, g)),
choose_param(get_param(params, cooling_t()),
linear_cooling<double>(100)),
linear_cooling<Dim>(100)),
get_param(params, vertex_displacement_t()),
params);
}
......
......@@ -140,18 +140,18 @@ clustering.add_option("--global-clustering-coefficient", action="callback", call
clustering.add_option("--extended-clustering-coefficient", action="callback", callback=push_option, type="string", metavar="PREFIX|MAX", help="set the extended clustering coefficients c1 to cMAX to vertex properties PREFIX1 to PREFIXMAX")
layout = parser.add_option_group("Layout")
layout.add_option("--compute-spring-block-layout", action="callback", callback=push_option, type="string", metavar="ITERATIONS[|SEED]", help="compute the spring block layout")
layout.add_option("--compute-gursoy-atun-layout", action="callback", callback=push_option, type="string", metavar="ITERATIONS[|SEED]", help="compute the Gursoy-Atun layout")
layout.add_option("--spring-block-layout", action="callback", callback=push_option, type="string", metavar="POS-PROPERTY|TYPE|ITERATIONS[|WEIGHT[|SEED]]", help="compute the spring block layout. TYPE can be 'kw', for Kamada-Kawai, 'fg-grid' for Fruchterman-Reingold with a grid, and 'fg-all-pairs' for Fruchterman-Reingold with all pairs. The positions will be stored in POS-PROPERTY.")
layout.add_option("--gursoy-atun-layout", action="callback", callback=push_option, type="string", metavar="POS-PROPERTY|TOPOLOGY|ITERATIONS[|WEIGHT[|SEED]]", help="compute the Gursoy-Atun layout. TOPOLOGY can be 'square', 'circle', or 'heart'. The positions will be stored in POS-PROPERTY.")
community = parser.add_option_group("Community")
community.add_option("--community-structure", action="callback", callback=push_option, type="string", metavar="PROPERTY|OPTIONS", help="calculate the community structure and assign it to PROPERTY. Options are: g (default: 1.0), N (default: 1000), Tmin (default: 0.01), Tmax (default: 1.0), spins (default: number of vertices), corr_type (default: uncorrelated), weight, seed (default: from clock), verbose, history. The value of corr_type can be 'random', 'uncorrelated' or 'correlated'.")
community.add_option("--modularity", action="callback", callback=push_option, type="string", metavar="PROPERTY[|WEIGHT]|FILE", help="calculate the modularity, given a community partition specified by PROPERTY")
community.add_option("--community-graph", action="callback", callback=push_option, type="string", metavar="PROPERTY|FILE[|FORMAT]", help="obtain the graph of communities, given a community partition specified by PROPERTY")
community.add_option("--community-graph", action="callback", callback=push_option, type="string", metavar="PROPERTY|SIZE-PROPERTY|FILE[|FORMAT]", help="obtain the graph of communities, given a community partition specified by PROPERTY. The resulting graph will have a vertex property named SIZE-PROPERTY, which will contain the size of the corresponding communities.")
layout = parser.add_option_group("History")
layout.add_option("--for", action="callback", callback=push_option, type="string", metavar="INIT|CONDITION|STEP", help="simplified scripting")
layout.add_option("--history", action="callback", callback=push_option, type="string", metavar="INIT|CONDITION|STEP", help="simplified scripting (does not overwrite previous results)")
layout.add_option("--refresh-rate", type="string", metavar="TIME", default="1h", help="for/history files refresh rate")
history = parser.add_option_group("History")
history.add_option("--for", action="callback", callback=push_option, type="string", metavar="INIT|CONDITION|STEP", help="simplified scripting")
history.add_option("--history", action="callback", callback=push_option, type="string", metavar="INIT|CONDITION|STEP", help="simplified scripting (does not overwrite previous results)")
history.add_option("--refresh-rate", type="string", metavar="TIME", default="1h", help="for/history files refresh rate")
try:
import optcomplete
......@@ -720,54 +720,60 @@ def parse_option(opt, just_file=False):
if get_suboption("seed", values[0]) != False:
seed = int(get_suboption("seed", values[0]))
else:
seed = seed = int(time())
seed = int(time())
if just_file:
return
graph.RandomRewire(strat, self_loops, parallel, seed)
elif opt.name == "community-graph":
values = parse_values(opt.value)
if len(values) < 2 or len(values) > 3:
if len(values) < 3 or len(values) > 4:
raise OptionError(opt.name, "invalid value '%s'" % opt.value)
prop, file_name = values[0], values[1]
if len(values) > 2:
format = values[2]
prop, size_prop, file_name = values[0], values[1], values[2]
if len(values) > 3:
format = values[3]
else:
format = ""
if just_file:
return
return (graph.GetCommunityNetwork(prop, file_name, format))
elif opt.name == "compute-spring-block-layout":
return (graph.GetCommunityNetwork(prop, size_prop, file_name, format))
elif opt.name == "spring-block-layout":
if just_file:
return None
values = parse_values(opt.value)
if len(values) == 0 or len(values) > 2:
raise OptionError(opt.name, "invalid value '%s'" % opt.value)
iterations,seed = 0,0
try:
iterations = int(values[0])
if len(values) > 1:
seed = int(values[1])
else:
seed = int(time())
except ValueError:
if len(values) < 3 or len(values) > 5:
raise OptionError(opt.name, "invalid value '%s'" % opt.value)
graph.ComputeGraphLayoutSpringBlock(iterations,seed)
elif opt.name == "compute-gursoy-atun-layout":
(prop, type, iter) = values[0:3]
if len(values) > 3:
weight = values[3]
else:
weight = ""
if len(values) > 4:
try:
seed = int(values[4])
except ValueError:
raise OptionError(opt.name, "invalid seed value '%s'" % values[4])
else:
seed = int(time())
graph.ComputeGraphLayoutSpringBlock(prop, weight, type, int(iter), seed)
elif opt.name == "gursoy-atun-layout":
if just_file:
return None
values = parse_values(opt.value)
if len(values) == 0 or len(values) > 2:
raise OptionError(opt.name, "invalid value '%s'" % opt.value)
iterations,seed = 0,0
try:
iterations = int(values[0])
if len(values) > 1:
seed = int(values[1])
else:
seed = int(time())
except ValueError:
if len(values) < 3 or len(values) > 5:
raise OptionError(opt.name, "invalid value '%s'" % opt.value)
graph.ComputeGraphLayoutGursoy(iterations,seed)
(prop, top, iter) = values[0:3]
if len(values) > 3:
weight = values[3]
else:
weight = ""
if len(values) > 4:
try:
seed = int(values[4])
except ValueError:
raise OptionError(opt.name, "invalid seed value '%s'" % values[4])
else:
seed = int(time())
graph.ComputeGraphLayoutGursoy(prop, weight, top, int(iter), seed)
elif opt.name == "vertex-filter" or opt.name == "edge-filter":
if just_file:
return None
......
......@@ -42,6 +42,7 @@ libgraph_tool_la_SOURCES = \
graph_line_graph.cc\
graph_betweenness.cc\
graph_rewiring.cc\
graph_layout.cc\
graph_io.cc\
graph_bind.cc\
graphml.cpp\
......
......@@ -24,9 +24,6 @@
#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/strong_components.hpp>
#include <boost/graph/connected_components.hpp>
#include <boost/graph/gursoy_atun_layout.hpp>
#include <boost/graph/fruchterman_reingold.hpp>
#include <boost/graph/random_layout.hpp>
#include <boost/random.hpp>
#include <boost/python/make_function.hpp>
......@@ -369,8 +366,8 @@ struct label_components
void GraphInterface::LabelComponents(string prop)
{
typedef HashedDescriptorMap<vertex_index_map_t, size_t> comp_map_t;
static comp_map_t comp_map(_vertex_index);
typedef vector_property_map<size_t, vertex_index_map_t> comp_map_t;
comp_map_t comp_map(_vertex_index);
check_filter(*this, bind<void>(label_components(), _1, comp_map), reverse_check(), directed_check());
......@@ -456,86 +453,6 @@ void GraphInterface::InsertVertexIndexProperty(string property)
_properties.property(property, _vertex_index);
}
//==============================================================================
// ComputeGraphLayoutGursoy(iter, seed)
//==============================================================================
struct compute_gursoy
{
template <class Graph, class PosMap, class IndexMap>
void operator()(Graph &g, size_t iter, size_t seed, PosMap pos, IndexMap index_map) const
{
mt19937 rng(static_cast<mt19937::result_type>(seed));
size_t n = HardNumVertices()(g);
vector_property_map<square_topology<mt19937>::point_type, IndexMap> position_map(index_map);
if (iter == 0)
iter = n;
square_topology<mt19937> topology(rng, n);
gursoy_atun_layout(g, topology, position_map, iterations(iter).
diameter_range(make_pair(sqrt(double(n)), 1.0)).
learning_constant_range(make_pair(0.8, 0.2)).
vertex_index_map(index_map));
typename graph_traits<Graph>::vertex_iterator v, v_begin, v_end;
tie(v_begin, v_end) = vertices(g);
for(v = v_begin; v != v_end; ++v)
{
pos[*v].x = position_map[*v][0];
pos[*v].y = position_map[*v][1];
}
}
};
typedef struct { double x; double y; } pos_t;
ostream& operator<<(ostream &o, const pos_t &p ) { o << p.x << "," << p.y; return o;}
istream& operator>>(istream &o, pos_t &p ) { char c; o >> p.x >> c >> p.y; return o;}
void GraphInterface::ComputeGraphLayoutGursoy(size_t iter, size_t seed)
{
// vertex postion map
typedef HashedDescriptorMap<vertex_index_map_t, pos_t> pos_map_t;
pos_map_t pos_map(_vertex_index);
check_filter(*this,bind<void>(compute_gursoy(),_1,iter,seed,var(pos_map),var(_vertex_index)),reverse_check(),directed_check());
_properties.property("pos", pos_map);
}
//==============================================================================
// ComputeGraphLayoutSpringBlock(iter,seed)
//==============================================================================
struct compute_spring_block
{
template <class Graph, class PosMap, class IndexMap>
void operator()(Graph &g, size_t iter, size_t seed, PosMap pos, IndexMap index_map) const
{
mt19937 rng(static_cast<mt19937::result_type>(seed));
size_t n = HardNumVertices()(g);
if (iter == 0)
iter = 100;
double radius = n*iter;
random_graph_layout(g, pos, -radius/2, radius/2, -radius/2, radius/2, rng);
fruchterman_reingold_force_directed_layout(g, pos, radius, radius,
cooling(linear_cooling<double>(iter)).
vertex_index_map(index_map));
}
};
void GraphInterface::ComputeGraphLayoutSpringBlock(size_t iter, size_t seed)
{
// vertex postion map
typedef HashedDescriptorMap<vertex_index_map_t,pos_t> pos_map_t;
pos_map_t pos_map(_vertex_index);
check_filter(*this,bind<void>(compute_spring_block(),_1,iter,seed,var(pos_map),var(_vertex_index)),reverse_check(),directed_check());
_properties.property("pos", pos_map);
}
//==============================================================================
// InitSignalHandling()
//==============================================================================
......
......@@ -110,7 +110,7 @@ public:
void GetCommunityStructure(double gamma, comm_corr_t corr, size_t n_iter, double Tmin, double Tmax, size_t Nseeds, size_t seed, bool verbose, std::string history_file, std::string weight, std::string property);
double GetModularity(std::string weight, std::string property);
void GetCommunityNetwork(std::string property, std::string out_file, std::string format) const;
void GetCommunityNetwork(std::string property, std::string size_property, std::string out_file, std::string format) const;
// graph random rewiring (shuffling)
enum rewire_strat_t
......@@ -155,8 +155,8 @@ public:
void ListProperties() const;
// layout
void ComputeGraphLayoutGursoy(size_t iter = 0, size_t seed = 4357);
void ComputeGraphLayoutSpringBlock(size_t iter = 0, size_t seed = 4357);
void ComputeGraphLayoutGursoy(std::string prop, std::string weight, std::string topology, size_t iter = 0, size_t seed = 4357);
void ComputeGraphLayoutSpringBlock(std::string prop, std::string weight, std::string type, size_t iter = 0, size_t seed = 4357);
// i/o
void WriteToFile(std::string s);
......
......@@ -52,7 +52,7 @@ public:
typedef typename Graph::vertex_property_type vertex_property_type;
typedef typename Graph::edge_property_type edge_property_type;
typedef typename Graph::graph_tag graph_tag;
typedef typename Graph::graph_type graph_type;
typedef Graph graph_type;
class EdgeDescriptor;
typedef Graph original_graph_t;
......@@ -100,7 +100,9 @@ public:
EdgeDescriptor(const original_edge_t &e, bool inverted): original_edge_t(e), _inverted(inverted) {}
bool IsInverted() const {return _inverted;}
bool operator==(const EdgeDescriptor& e) const { return original_edge_t(e) == original_edge_t(*this); }
private:
bool _inverted;
};
......
......@@ -158,6 +158,46 @@ struct hist_to_dict
}
};
struct pos_t_to_tuple
{
static PyObject* convert(const pos_t& p)
{
boost::python::tuple t = boost::python::make_tuple(p.x,p.y);
return incref(t.ptr());
}
};
struct pos_t_from_tuple
{
pos_t_from_tuple()
{
converter::registry::push_back(&convertible, &construct, boost::python::type_id<pos_t>());
}
static void* convertible(PyObject* obj_ptr)
{
handle<> x(borrowed(obj_ptr));
object o(x);
extract<double> first(o[0]);
extract<double> second(o[1]);
if (!first.check() || !second.check())
return 0;
return obj_ptr;
}
static void construct(PyObject* obj_ptr, converter::rvalue_from_python_stage1_data* data)
{
handle<> x(borrowed(obj_ptr));
object o(x);
pos_t value;
value.x = extract<double>(o[0]);
value.y = extract<double>(o[1]);
void* storage = ( (boost::python::converter::rvalue_from_python_storage<pos_t>*) data)->storage.bytes;
new (storage) pos_t(value);
data->convertible = storage;
}
};
class GraphInterfaceWrap: public GraphInterface
{
......@@ -299,6 +339,8 @@ BOOST_PYTHON_MODULE(libgraph_tool)
pair_from_tuple<double,double>();
to_python_converter<boost::tuple<double,double,double>, tuple_to_tuple<double,double,double> >();
tuple_from_tuple<double,double,double>();
to_python_converter<pos_t, pos_t_to_tuple>();
pos_t_from_tuple();
to_python_converter<GraphInterfaceWrap::hist_t, hist_to_dict<GraphInterfaceWrap::hist_t> >();
to_python_converter<GraphInterfaceWrap::hist2d_t, hist_to_dict<GraphInterfaceWrap::hist2d_t> >();
to_python_converte