From 4cfd772d07c70ef3d887dc95770d7538e6638ea7 Mon Sep 17 00:00:00 2001 From: Tiago de Paula Peixoto Date: Mon, 13 Oct 2008 18:09:23 +0200 Subject: [PATCH] Added util sub-module This contains at the moment functions to perform basic vertex and edge searches. --- configure.ac | 1 + src/graph/Makefile.am | 2 +- src/graph/util/Makefile.am | 38 ++++++++ src/graph/util/graph_search.cc | 70 ++++++++++++++ src/graph/util/graph_search.hh | 154 ++++++++++++++++++++++++++++++ src/graph/util/graph_util_bind.cc | 25 +++++ src/graph_tool/Makefile.am | 8 +- src/graph_tool/util/__init__.py | 60 ++++++++++++ 8 files changed, 356 insertions(+), 2 deletions(-) create mode 100644 src/graph/util/Makefile.am create mode 100644 src/graph/util/graph_search.cc create mode 100644 src/graph/util/graph_search.hh create mode 100644 src/graph/util/graph_util_bind.cc create mode 100644 src/graph_tool/util/__init__.py diff --git a/configure.ac b/configure.ac index b5a53f51..75f652a7 100644 --- a/configure.ac +++ b/configure.ac @@ -250,6 +250,7 @@ src/graph/correlations/Makefile src/graph/generation/Makefile src/graph/stats/Makefile src/graph/clustering/Makefile +src/graph/util/Makefile src/graph_tool/Makefile ]) diff --git a/src/graph/Makefile.am b/src/graph/Makefile.am index 1c9acb94..9db5824a 100644 --- a/src/graph/Makefile.am +++ b/src/graph/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in -SUBDIRS = generation correlations stats clustering +SUBDIRS = generation correlations stats clustering util AM_CPPFLAGS =\ -I$(srcdir)/.. \ diff --git a/src/graph/util/Makefile.am b/src/graph/util/Makefile.am new file mode 100644 index 00000000..180b876c --- /dev/null +++ b/src/graph/util/Makefile.am @@ -0,0 +1,38 @@ +## Process this file with automake to produce Makefile.in + +AM_CPPFLAGS =\ + -I$(srcdir) -I$(srcdir)/.. \ + -I$(srcdir)/../boost-workaround \ + -DHAVE_CONFIG_H + +AM_CFLAGS=$(AM_CXXFLAGS) + +libgraph_tool_utildir = $(pythondir)/graph_tool/util + +libgraph_tool_util_LTLIBRARIES = libgraph_tool_util.la + +libgraph_tool_util_la_includedir = $(pythondir)/graph_tool/include + +libgraph_tool_util_la_SOURCES = \ + graph_search.cc \ + graph_util_bind.cc + +libgraph_tool_util_la_include_HEADERS = \ + graph_search.hh + +libgraph_tool_util_la_LIBADD = \ + $(PYTHON_LDFLAGS) \ + $(BOOST_LDFLAGS) \ + $(OPENMP_LDFLAGS) \ + -lboost_python \ + -lboost_iostreams \ + -lexpat + +# needed for typeinfo objects to work across DSO boundaries. +# see http://gcc.gnu.org/faq.html#dso +libgraph_tool_util_la_LDFLAGS = \ + -module \ + -avoid-version \ + -export-dynamic \ + -no-undefined \ + -Wl,-E diff --git a/src/graph/util/graph_search.cc b/src/graph/util/graph_search.cc new file mode 100644 index 00000000..cd3a0748 --- /dev/null +++ b/src/graph/util/graph_search.cc @@ -0,0 +1,70 @@ +// Copyright (C) 2008 Tiago de Paula Peixoto +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "graph.hh" +#include "graph_filtering.hh" +#include "graph_properties.hh" + +#include "graph_search.hh" + +#include + +using namespace std; +using namespace boost; +using namespace graph_tool; + +// find vertices which match a certain (inclusive) property range +python::list +find_vertex_range(const GraphInterface& gi, GraphInterface::deg_t deg, + python::tuple range) +{ + python::list ret; + + run_action<>()(gi, lambda::bind(find_vertices(), lambda::_1, + lambda::var(gi), lambda::_2, + lambda::var(range), lambda::var(ret)), + all_selectors())(degree_selector(deg)); + return ret; +} + +// find vertices which match a certain (inclusive) property range +python::list +find_edge_range(GraphInterface& gi, boost::any eprop, + python::tuple range) +{ + python::list ret; + typedef property_map_types::apply >::type + all_edge_props; + + GraphInterface::edge_index_map_t eindex = + any_cast(gi.GetEdgeIndex()); + run_action<>()(gi, lambda::bind(find_edges(), lambda::_1, + lambda::var(gi), eindex, + lambda::_2, lambda::var(range), + lambda::var(ret)), + all_edge_props())(eprop); + return ret; +} + + +using namespace boost::python; + +void export_search() +{ + def("find_vertex_range", &find_vertex_range); + def("find_edge_range", &find_edge_range); +} diff --git a/src/graph/util/graph_search.hh b/src/graph/util/graph_search.hh new file mode 100644 index 00000000..b64248fd --- /dev/null +++ b/src/graph/util/graph_search.hh @@ -0,0 +1,154 @@ +// Copyright (C) 2008 Tiago de Paula Peixoto +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef GRAPH_SEARCH_HH +#define GRAPH_SEARCH_HH + +#include "graph_python_interface.hh" +#include "graph_util.hh" + +#include + +namespace graph_tool +{ +using namespace std; +using namespace boost; + +// less than or equal for vectors. Compare sizes, or distance from origin. +template +bool operator<=(const vector& v1, const vector& v2) +{ + if (v1.size() < v2.size()) + return true; + if (v1.size() > v2.size()) + return false; + long double d1, d2; + for (size_t i; i < v1.size(); ++i) + { + d1 += v1[i]*v1[i]; + d2 += v2[i]*v2[i]; + } + return (d1 <= d2); +} + +// sort strings in alphabetical (ASCII) order +bool operator<=(const string s1, const string s2) +{ + for (size_t i; i < s1.size(); ++i) + { + if (s1[i] != s1[i]) + return (s1[i] < s1[i]); + } + return (s1.size() == s2.size()); +} + +// vector of strings. compare element by element +bool operator<=(const vector& v1, const vector& v2) +{ + if (v1.size() < v2.size()) + return true; + if (v1.size() > v2.size()) + return false; + for (size_t i; i < v1.size(); ++i) + { + if (v1[i] > v2[i]) + return false; + } + return true; +} + +// find vertices which match a certain (inclusive) property range +struct find_vertices +{ + template + void operator()(Graph* gp, const GraphInterface& gi, DegreeSelector deg, + python::tuple& prange, python::list& ret) const + { + Graph& g = *gp; + + typedef typename DegreeSelector::value_type value_type; + pair range; + range.first = python::extract(prange[0]); + range.second = python::extract(prange[1]); + + int i, N = num_vertices(g); + #pragma omp parallel for default(shared) private(i) \ + firstprivate(s_vertices) schedule(dynamic) + for (i = 0; i < N; ++i) + { + typename graph_traits::vertex_descriptor v = vertex(i, g); + if (v == graph_traits::null_vertex()) + continue; + value_type val = deg(v, g); + if (val >= range.first && val <= range.second) + { + #pragma omp atomic + ret.append(PythonVertex(gi, v)); + } + } + } +}; + +// find edges which match a certain (inclusive) property range +struct find_edges +{ + template + void operator()(Graph* gp, const GraphInterface& gi, EdgeIndex eindex, + EdgeProperty prop, python::tuple& prange, python::list& ret) + const + { + Graph& g = *gp; + + typedef typename property_traits::value_type value_type; + pair range; + range.first = python::extract(prange[0]); + range.second = python::extract(prange[1]); + + tr1::unordered_set edge_set; + + int i, N = num_vertices(g); + #pragma omp parallel for default(shared) private(i) \ + firstprivate(s_vertices) schedule(dynamic) + for (i = 0; i < N; ++i) + { + typename graph_traits::vertex_descriptor v = vertex(i, g); + if (v == graph_traits::null_vertex()) + continue; + typename graph_traits::out_edge_iterator e, e_end; + for (tie(e, e_end) = out_edges(v, g); e != e_end; ++e) + { + if (!is_directed::apply::type::value) + { + if (edge_set.find(eindex[*e]) == edge_set.end()) + edge_set.insert(eindex[*e]); + else + continue; + } + + value_type val = get(prop, *e); + if (val >= range.first && val <= range.second) + { + #pragma omp atomic + ret.append(PythonEdge(gi, *e)); + } + } + } + } +}; + + +} // graph_tool namespace + +#endif // GRAPH_SEARCH_HH diff --git a/src/graph/util/graph_util_bind.cc b/src/graph/util/graph_util_bind.cc new file mode 100644 index 00000000..c9146a26 --- /dev/null +++ b/src/graph/util/graph_util_bind.cc @@ -0,0 +1,25 @@ +// Copyright (C) 2008 Tiago de Paula Peixoto +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include + +using namespace boost; + +void export_search(); + +BOOST_PYTHON_MODULE(libgraph_tool_util) +{ + export_search(); +} diff --git a/src/graph_tool/Makefile.am b/src/graph_tool/Makefile.am index 5d8b1c7e..4b7b1786 100644 --- a/src/graph_tool/Makefile.am +++ b/src/graph_tool/Makefile.am @@ -4,7 +4,9 @@ graph_tool_PYTHON = \ __init__.py \ core.py \ decorators.py \ - io.py + io.py \ + all.py + graph_tooldir = $(pythondir)/graph_tool graph_tool_run_action_PYTHON = \ @@ -38,3 +40,7 @@ graph_tool_clusteringdir = $(pythondir)/graph_tool/clustering graph_tool_draw_PYTHON = \ draw/__init__.py graph_tool_drawdir = $(pythondir)/graph_tool/draw + +graph_tool_util_PYTHON = \ + util/__init__.py +graph_tool_utildir = $(pythondir)/graph_tool/util diff --git a/src/graph_tool/util/__init__.py b/src/graph_tool/util/__init__.py new file mode 100644 index 00000000..a5f4a8de --- /dev/null +++ b/src/graph_tool/util/__init__.py @@ -0,0 +1,60 @@ +#! /usr/bin/env python +# graph_tool.py -- a general graph manipulation python module +# +# Copyright (C) 2007 Tiago de Paula Peixoto +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import sys +# RTLD_GLOBAL needs to be set in dlopen() if we want typeinfo and friends to +# work properly across DSO boundaries. See http://gcc.gnu.org/faq.html#dso + +# The "except" is because the dl module raises a system error on ia64 and x86_64 +# systems because "int" and addresses are different sizes. +try: + from dl import RTLD_LAZY, RTLD_NOW, RTLD_GLOBAL +except ImportError: + RTLD_LAZY = 1 + RTLD_NOW = 2 + RTLD_GLOBAL = 256 +_orig_dlopen_flags = sys.getdlopenflags() + +sys.setdlopenflags(RTLD_LAZY|RTLD_GLOBAL) +import libgraph_tool_util +sys.setdlopenflags(_orig_dlopen_flags) # reset it to normal case to avoid + # unnecessary symbol collision + +from .. core import _degree, _prop + +__all__ = ["find_vertex", "find_vertex_range", "find_edge", "find_edge_range"] + +def find_vertex(g, deg, match): + ret = libgraph_tool_util.\ + find_vertex_range(g._Graph__graph, _degree(deg), (match, match)) + return ret + +def find_vertex_range(g, deg, range): + ret = libgraph_tool_util.\ + find_vertex_range(g._Graph__graph, _degree(deg), range) + return ret + +def find_edge(g, prop, match): + ret = libgraph_tool_util.\ + find_edge_range(g._Graph__graph, _prop(prop,"e"), (match, match)) + return ret + +def find_edge_range(g, prop, range): + ret = libgraph_tool_util.\ + find_edge_range(g._Graph__graph, _prop(prop,"e"), range) + return ret -- GitLab