diff --git a/configure.in b/configure.in index 3171a074d9cba528b746eb44680426ff1c32667b..7da17ade9cf4db1cb155809a728499a82e92d322 100644 --- a/configure.in +++ b/configure.in @@ -1,6 +1,23 @@ dnl Process this file with autoconf to produce a configure script. -AC_INIT(graph-tool, 1.2.0devel, [http://graph-tool.forked.de]) +dnl graph-tool package version number +dnl An odd micro number indicates in-progress development. +dnl An even micro number indicates a released version. +m4_define(graph_tool_version_major, 1) +m4_define(graph_tool_version_minor, 9) +m4_define(graph_tool_version_micro, 0) + +AC_INIT([graph-tool], + [graph_tool_version_major().graph_tool_version_minor().graph_tool_version_micro()], + [http://graph-tool.forked.de]) + +GRAPH_TOOL_VERSION_MAJOR=graph_tool_version_major() +GRAPH_TOOL_VERSION_MINOR=graph_tool_version_minor() +GRAPH_TOOL_VERSION_MICRO=graph_tool_version_micro() +AC_SUBST(GRAPH_TOOL_VERSION_MAJOR) +AC_SUBST(GRAPH_TOOL_VERSION_MINOR) +AC_SUBST(GRAPH_TOOL_VERSION_MICRO) + AC_CONFIG_SRCDIR(src/graph-tool) AM_INIT_AUTOMAKE AM_PROG_CC_C_O @@ -74,19 +91,19 @@ AC_ARG_ENABLE([visibility], [AC_HELP_STRING([--disable-visibility], ) -AC_MSG_CHECKING(whether to enable graph range filtering...) -AC_ARG_ENABLE([range-filtering], [AC_HELP_STRING([--disable-range-filtering], - [disable range filtering [default=enabled] ])], +AC_MSG_CHECKING(whether to enable graph filtering...) +AC_ARG_ENABLE([graph-filtering], [AC_HELP_STRING([--disable-graph-filtering], + [disable graph filtering [default=enabled] ])], if test $enableval = no; then [AC_MSG_RESULT(no)] - [AC_DEFINE([NO_RANGE_FILTERING], 1, [disable range filtering])] - NO_RANGE_FILTERING=yes + [AC_DEFINE([NO_GRAPH_FILTERING], 1, [disable graph filtering])] + NO_GRAPH_FILTERING=yes else [AC_MSG_RESULT(yes)] fi , [AC_MSG_RESULT(yes)] - NO_RANGE_FILTERING=no + NO_GRAPH_FILTERING=no ) AC_MSG_CHECKING(whether to enable parallel algorithms with openmp...) @@ -126,8 +143,8 @@ dnl AX_BOOST_PYTHON dnl expat AC_CHECK_LIB(expat,main) -AM_PATH_PYTHON([2.4]) -AC_PYTHON_DEVEL(>= '2.4') +AM_PATH_PYTHON([2.5]) +AC_PYTHON_DEVEL(>= '2.5') dnl Checks for header files. AC_CHECK_HEADER([expat.h]) diff --git a/ltmain.sh b/ltmain.sh index d74b5a67afb39d1e0ff7fcfeb85b119125ece0f3..e589475dd924ea209ba3a6489f6b7221c6e78e5e 100644 --- a/ltmain.sh +++ b/ltmain.sh @@ -2,7 +2,7 @@ # NOTE: Changing this file will not affect anything until you rerun configure. # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, -# 2007 Free Software Foundation, Inc. +# 2007, 2008 Free Software Foundation, Inc. # Originally by Gordon Matzigkeit , 1996 # # This program is free software; you can redistribute it and/or modify @@ -43,8 +43,8 @@ EXIT_FAILURE=1 PROGRAM=ltmain.sh PACKAGE=libtool -VERSION=1.5.24 -TIMESTAMP=" (1.1220.2.456 2007/06/24 02:25:32)" +VERSION=1.5.26 +TIMESTAMP=" (1.1220.2.493 2008/02/01 16:58:18)" # Be Bourne compatible (taken from Autoconf:_AS_BOURNE_COMPATIBLE). if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then @@ -113,15 +113,21 @@ esac # These must not be set unconditionally because not all systems understand # e.g. LANG=C (notably SCO). # We save the old values to restore during execute mode. -for lt_var in LANG LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES +lt_env= +for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${$lt_var+set}\" = set; then save_$lt_var=\$$lt_var + lt_env=\"$lt_var=\$$lt_var \$lt_env\" $lt_var=C export $lt_var fi" done +if test -n "$lt_env"; then + lt_env="env $lt_env" +fi + # Make sure IFS has a sensible default lt_nl=' ' @@ -499,7 +505,7 @@ do echo "\ $PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP -Copyright (C) 2007 Free Software Foundation, Inc. +Copyright (C) 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." exit $? @@ -802,6 +808,7 @@ if test -z "$show_help"; then *.for) xform=for ;; *.java) xform=java ;; *.obj) xform=obj ;; + *.sx) xform=sx ;; esac libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"` @@ -970,7 +977,7 @@ EOF $run $rm "$lobj" "$output_obj" $show "$command" - if $run eval "$command"; then : + if $run eval $lt_env "$command"; then : else test -n "$output_obj" && $run $rm $removelist exit $EXIT_FAILURE @@ -1042,7 +1049,7 @@ EOF command="$command$suppress_output" $run $rm "$obj" "$output_obj" $show "$command" - if $run eval "$command"; then : + if $run eval $lt_env "$command"; then : else $run $rm $removelist exit $EXIT_FAILURE @@ -1175,6 +1182,7 @@ EOF thread_safe=no vinfo= vinfo_number=no + single_module="${wl}-single_module" func_infer_tag $base_compile @@ -1660,6 +1668,11 @@ EOF continue ;; + -multi_module) + single_module="${wl}-multi_module" + continue + ;; + -module) module=yes continue @@ -2163,7 +2176,12 @@ EOF continue fi name=`$echo "X$deplib" | $Xsed -e 's/^-l//'` - for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do + if test "$linkmode" = lib; then + searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" + else + searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" + fi + for searchdir in $searchdirs; do for search_ext in .la $std_shrext .so .a; do # Search the libtool library lib="$searchdir/lib${name}${search_ext}" @@ -2959,12 +2977,18 @@ EOF # we do not want to link against static libs, # but need to link against shared eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + eval deplibdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` if test -n "$deplibrary_names" ; then for tmp in $deplibrary_names ; do depdepl=$tmp done - if test -f "$path/$depdepl" ; then + if test -f "$deplibdir/$depdepl" ; then + depdepl="$deplibdir/$depdepl" + elif test -f "$path/$depdepl" ; then depdepl="$path/$depdepl" + else + # Can't find it, oh well... + depdepl= fi # do not add paths which are already there case " $newlib_search_path " in @@ -3112,9 +3136,10 @@ EOF case $linkmode in oldlib) - if test -n "$deplibs"; then - $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2 - fi + case " $deplibs" in + *\ -l* | *\ -L*) + $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2 ;; + esac if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2 @@ -4251,9 +4276,10 @@ EOF ;; obj) - if test -n "$deplibs"; then - $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 - fi + case " $deplibs" in + *\ -l* | *\ -L*) + $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 ;; + esac if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2 @@ -5688,53 +5714,9 @@ fi\ $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 exit $EXIT_FAILURE fi - if test "X$EGREP" = X ; then - EGREP=egrep - fi - # We do not want portage's install root ($D) present. Check only for - # this if the .la is being installed. - if test "$installed" = yes && test "$D"; then - eval mynewdependency_lib=`echo "$libdir/$name" |sed -e "s:$D:/:g" -e 's:/\+:/:g'` - else - mynewdependency_lib="$libdir/$name" - fi - # Do not add duplicates - if test "$mynewdependency_lib"; then - my_little_ninja_foo_1=`echo $newdependency_libs |$EGREP -e "$mynewdependency_lib"` - if test -z "$my_little_ninja_foo_1"; then - newdependency_libs="$newdependency_libs $mynewdependency_lib" - fi - fi - ;; - *) - if test "$installed" = yes; then - # Rather use S=WORKDIR if our version of portage supports it. - # This is because some ebuild (gcc) do not use $S as buildroot. - if test "$PWORKDIR"; then - S="$PWORKDIR" - fi - # We do not want portage's build root ($S) present. - my_little_ninja_foo_2=`echo $deplib |$EGREP -e "$S"` - # We do not want portage's install root ($D) present. - my_little_ninja_foo_3=`echo $deplib |$EGREP -e "$D"` - if test -n "$my_little_ninja_foo_2" && test "$S"; then - mynewdependency_lib="" - elif test -n "$my_little_ninja_foo_3" && test "$D"; then - eval mynewdependency_lib=`echo "$deplib" |sed -e "s:$D:/:g" -e 's:/\+:/:g'` - else - mynewdependency_lib="$deplib" - fi - else - mynewdependency_lib="$deplib" - fi - # Do not add duplicates - if test "$mynewdependency_lib"; then - my_little_ninja_foo_4=`echo $newdependency_libs |$EGREP -e "$mynewdependency_lib"` - if test -z "$my_little_ninja_foo_4"; then - newdependency_libs="$newdependency_libs $mynewdependency_lib" - fi - fi + newdependency_libs="$newdependency_libs $libdir/$name" ;; + *) newdependency_libs="$newdependency_libs $deplib" ;; esac done dependency_libs="$newdependency_libs" @@ -5786,10 +5768,6 @@ fi\ case $host,$output,$installed,$module,$dlname in *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; esac - # Do not add duplicates - if test "$installed" = yes && test "$D"; then - install_libdir=`echo "$install_libdir" |sed -e "s:$D:/:g" -e 's:/\+:/:g'` - fi $echo > $output "\ # $outputname - a libtool library file # Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP @@ -6545,7 +6523,7 @@ relink_command=\"$relink_command\"" fi # Restore saved environment variables - for lt_var in LANG LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES + for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${save_$lt_var+set}\" = set; then $lt_var=\$save_$lt_var; export $lt_var diff --git a/src/graph/Makefile.am b/src/graph/Makefile.am index d3165d1ff813c1eedaac54100fc088c999c47859..3cd64079d918cc6b1cfa36f5f38615f4f928ac83 100644 --- a/src/graph/Makefile.am +++ b/src/graph/Makefile.am @@ -19,30 +19,47 @@ libgraph_tool_LTLIBRARIES = libgraph_tool.la libgraph_tool_la_includedir = $(pythondir)/graph_tool/include libgraph_tool_la_SOURCES = \ - graph.hh\ - graph.cc\ - graph_python_interface.cc\ - graph_properties.cc\ - graph_correlations.cc\ - graph_edge_correlations.cc\ - graph_correlations_combined.cc\ - graph_correlations_neighbours.cc\ - graph_assortativity.cc\ - graph_clustering.cc\ - graph_extended_clustering.cc\ - graph_generation.cc\ - graph_distance.cc\ - graph_distance_sampled.cc\ - graph_reciprocity.cc\ - graph_minimum_spanning_tree.cc\ - graph_community.cc\ - graph_community_network.cc\ - graph_line_graph.cc\ - graph_betweenness.cc\ - graph_rewiring.cc\ - graph_layout.cc\ - graph_io.cc\ - graph_bind.cc\ + graph_assortativity.cc \ + graph_betweenness.cc \ + graph_bind.cc \ + graph.cc \ + graph_clustering.cc \ + graph_community.cc \ + graph_community_network.cc \ + graph_correlations.cc \ + graph_correlations_combined.cc \ + graph_correlations_combined_corr.cc \ + graph_correlations_imp1.cc \ + graph_correlations_imp2.cc \ + graph_correlations_imp3.cc \ + graph_correlations_neighbours.cc \ + graph_correlations_neighbours_imp1.cc \ + graph_correlations_neighbours_imp2.cc \ + graph_correlations_neighbours_imp3.cc \ + graph_correlations_neighbours_imp4.cc \ + graph_correlations_neighbours_imp5.cc \ + graph_correlations_neighbours_imp6.cc \ + graph_distance.cc \ + graph_distance_sampled.cc \ + graph_edge_correlations.cc \ + graph_edge_correlations_imp1.cc \ + graph_edge_correlations_imp2.cc \ + graph_edge_correlations_imp3.cc \ + graph_edge_correlations_imp4.cc \ + graph_edge_correlations_imp5.cc \ + graph_extended_clustering.cc \ + graph_filtering.cc \ + graph_generation.cc \ + graph_io.cc \ + graph_layout.cc \ + graph_line_graph.cc \ + graph_minimum_spanning_tree.cc \ + graph_properties.cc \ + graph_python_interface.cc \ + graph_python_interface_export.cc \ + graph_reciprocity.cc \ + graph_rewiring.cc \ + graph_selectors.cc \ graphml.cpp\ read_graphviz_spirit.cpp\ ../boost-workaround/boost/graph/filtered_graph.hpp\ @@ -50,16 +67,42 @@ libgraph_tool_la_SOURCES = \ ../boost-workaround/boost/graph/graphml.hpp libgraph_tool_la_include_HEADERS = \ - graph_adaptor.hh\ - graph.hh\ - graph_filtering.hh\ - graph_python_interface.hh\ - graph_selectors.hh\ - graph_properties.hh\ - shared_map.hh\ - histogram.hh\ + graph_adaptor.hh \ + graph_assortativity.hh \ + graph_clustering.hh \ + graph_community.hh \ + graph_community_network.hh \ + graph_correlations_combined.hh \ + graph_correlations.hh \ + graph_correlations_neighbours.hh \ + graph_distance.hh \ + graph_distance_sampled.hh \ + graph_edge_correlations.hh \ + graph_extended_clustering.hh \ + graph_filtering.hh \ + graph.hh \ + graph_properties.hh \ + graph_python_interface.hh \ + graph_rewiring.hh \ + graph_selectors.hh \ + graph_util.hh \ + histogram.hh \ + mpl_nested_loop.hh \ + shared_map.hh \ ../../config.h +BUILT_SOURCES = \ + graph_filtering.hh.gch + +## Header precompilation +## FIXME: need a better way to convince libtool to let us do this. +$(libgraph_tool_la_include_HEADERS): + +$(BUILT_SOURCES): + $(CXXCOMPILE) $(CXXFLAGS) $(AM_CXXFLAGS) $(AM_CPPFLAGS) -fPIC -DPIC -x c++-header `basename $@ .gch` +mostlyclean-local: + -rm -f *.gch + libgraph_tool_la_LIBADD = \ $(PYTHON_LDFLAGS) \ $(BOOST_LDFLAGS) \ diff --git a/src/graph/graph.cc b/src/graph/graph.cc index 0e8aa96ed442c7fcfc4d30d0650d50708d91170e..df131e4219ccfb37d0818e1592fbabef460f5a03 100644 --- a/src/graph/graph.cc +++ b/src/graph/graph.cc @@ -35,6 +35,7 @@ #include "graph_filtering.hh" #include "graph_selectors.hh" #include "graph_properties.hh" +#include "graph_util.hh" #include "shared_map.hh" using namespace std; @@ -42,24 +43,6 @@ using namespace boost; using namespace boost::lambda; using namespace graph_tool; -// this will return the degree type contained in 'degree' or the name of the -// scalar property. -pair -graph_tool::get_degree_type(GraphInterface::deg_t degree) -{ - GraphInterface::degree_t deg; - string name; - try - { - deg = boost::get(degree); - } - catch (bad_get) - { - name = boost::get(degree); - deg = GraphInterface::SCALAR; - } - return make_pair(deg,name); -} // this is the constructor for the graph interface GraphInterface::GraphInterface() @@ -69,13 +52,11 @@ GraphInterface::GraphInterface() _vertex_index(get(vertex_index,_mg)), _edge_index(get(edge_index_t(),_mg)), _vertex_filter_map(_vertex_index), - _vertex_range(make_pair(0.0, numeric_limits::max())), - _vertex_range_include(make_pair(true, true)), - _vertex_range_invert(false), + _vertex_filter_invert(false), + _vertex_filter_active(false), _edge_filter_map(_edge_index), - _edge_range(make_pair(0.0, numeric_limits::max())), - _edge_range_include(make_pair(true, true)), - _edge_range_invert(false) + _edge_filter_invert(false), + _edge_filter_active(false) { } @@ -85,313 +66,15 @@ GraphInterface::~GraphInterface() { } -// these test whether or not the vertex and filter are active, by checking the -// corresponding property value -bool GraphInterface::IsVertexFilterActive() const -{ return _vertex_filter_property != ""; } - -bool GraphInterface::IsEdgeFilterActive() const -{ return _edge_filter_property != ""; } - -// this function will get a dynamic property map, and return its static type, if -// it matches a couple of possibilities that have 'double' as value -// type. Otherwise it wraps it around a DynamicPropertyMapWrap -template -FilterMap choose_filter_map(string property, dynamic_properties& dp) -{ - FilterMap filter_map; - try - { - dynamic_property_map& pmap = - find_property_map(dp, property, typeid(Descriptor)); - - try - { - return get_static_property_map - >(pmap); - } - catch(bad_cast){} - - try - { - return get_static_property_map - >(pmap); - } - catch(bad_cast){} - - try - { - return get_static_property_map - >(pmap); - } - catch(bad_cast){} - - try - { - return get_static_property_map - >(pmap); - } - catch(bad_cast){} - - try - { - return get_static_property_map(pmap); - } - catch(bad_cast){} - - return DynamicPropertyMapWrap(pmap); - } - catch (property_not_found) - { - throw GraphException("property " + property + " not found"); - } - -} - -// this will set enable the vertex filter, according to the given property. If -// property is an empty string, this will disable the filter -void GraphInterface::SetVertexFilterProperty(string property) -{ -#ifndef NO_RANGE_FILTERING - _vertex_filter_property = property; - - if (property != "") - { - _vertex_filter_map = choose_filter_map - (property, _properties); - } - else - { - _vertex_filter_map = _vertex_index; - _vertex_range = make_pair(0.0, numeric_limits::max()); - _vertex_range_include = make_pair(true, true); - _vertex_range_invert = false; - } -#else - if (property != "") - throw GraphException("support for graph range filtering was not enabled" - " during compilation."); -#endif -} - -// this will set enable the edge filter, according to the given property. If -// property is an empty string, this will disable the filter -void GraphInterface::SetEdgeFilterProperty(string property) -{ -#ifndef NO_RANGE_FILTERING - _edge_filter_property = property; - - if (property != "") - { - _edge_filter_map = choose_filter_map - (property, _properties); - } - else - { - _edge_filter_map = _edge_index; - _edge_range = make_pair(0.0, numeric_limits::max()); - _edge_range_include = make_pair(true, true); - _edge_range_invert = false; - } -#else - if (property != "") - throw GraphException("support for graph range filtering was not enabled" - " during compilation."); -#endif -} - - -void GraphInterface::SetVertexFilterRange(pair allowed_range, - pair include, bool invert) -{ -#ifndef NO_RANGE_FILTERING - if (isinf(allowed_range.first) == 1) - allowed_range.first = numeric_limits::max(); - else if (isinf(allowed_range.first) == -1) - allowed_range.first = -numeric_limits::max(); - if (isinf(allowed_range.second) == 1) - allowed_range.second = numeric_limits::max(); - else if (isinf(allowed_range.second) == -1) - allowed_range.second = -numeric_limits::max(); - - _vertex_range = allowed_range; - _vertex_range_include = include; - _vertex_range_invert = invert; -#else - throw GraphException("support for graph range filtering was not enabled" - " during compilation."); -#endif -} - -void GraphInterface::SetEdgeFilterRange(pair allowed_range, - pair include, bool invert) -{ -#ifndef NO_RANGE_FILTERING - if (isinf(allowed_range.first) == 1) - allowed_range.first = numeric_limits::max(); - else if (isinf(allowed_range.first) == -1) - allowed_range.first = -numeric_limits::max(); - if (isinf(allowed_range.second) == 1) - allowed_range.second = numeric_limits::max(); - else if (isinf(allowed_range.second) == -1) - allowed_range.second = -numeric_limits::max(); - - _edge_range = allowed_range; - _edge_range_include = include; - _edge_range_invert = invert; -#else - throw GraphException("support for graph range filtering was not enabled" - " during compilation."); -#endif -} - - -// this function will reindex all the edges, in the order in which they are -// found, taking care of preserving all the properties -void GraphInterface::ReIndexEdges() -{ - size_t n_edges = num_edges(_mg); - if (n_edges == 0) - return; - vector > edge_map - (n_edges, make_pair(edge_t(), false)); - graph_traits::vertex_iterator v, v_end; - graph_traits::out_edge_iterator e, e_end; - for (tie(v, v_end) = vertices(_mg); v != v_end; ++v) - for (tie(e, e_end) = out_edges(*v, _mg); e != e_end; ++e) - { - size_t index = _edge_index[*e]; - if (index >= edge_map.size()) - edge_map.resize(index+1); - edge_map[index] = make_pair(*e, true); - } - size_t new_index = 0; - for (tie(v, v_end) = vertices(_mg); v != v_end; ++v) - for (tie(e, e_end) = out_edges(*v, _mg); e != e_end; ++e) - { - edge_t old_edge = edge_map[new_index].first; - if (edge_map[new_index].second) - { - // another edge exists with the same index; indexes - // must be swapped, as well as the properties - _edge_index[old_edge] = _edge_index[*e]; - edge_map[_edge_index[*e]] = make_pair(old_edge, true); - _edge_index[*e] = new_index; - edge_map[new_index] = make_pair(*e, true); - for (typeof(_properties.begin()) p = _properties.begin(); - p != _properties.end(); ++p) - if (p->second->key() == typeid(edge_t)) - { - boost::any temp = p->second->get(*e); - p->second->put(*e, p->second->get(old_edge)); - p->second->put(old_edge, temp); - } - } - else - { - // no other edge has this index; it must be then - // assigned for this edge, and the properties must be - // copied over - size_t old_index = _edge_index[*e]; - for (typeof(_properties.begin()) p = _properties.begin(); - p != _properties.end(); ++p) - if (p->second->key() == typeid(edge_t)) - { - _edge_index[*e] = old_index; - boost::any val = p->second->get(*e); - _edge_index[*e] = new_index; - p->second->put(*e, val); - } - } - ++new_index; - } -} - -// this will definitively remove all the edges from the graph, which are being -// currently filtered out. This will also disable the edge filter -void GraphInterface::PurgeEdges() -{ - if (!IsEdgeFilterActive()) - return; - - RangeFilter filter(_edge_filter_map, _edge_range, - _edge_range_include, - _edge_range_invert); - graph_traits::vertex_iterator v, v_end; - graph_traits::out_edge_iterator e, e_end; - vector::edge_descriptor> deleted_edges; - for (tie(v, v_end) = vertices(_mg); v != v_end; ++v) - { - for (tie(e, e_end) = out_edges(*v, _mg); e != e_end; ++e) - if (!filter(*e)) - deleted_edges.push_back(*e); - for (typeof(deleted_edges.begin()) iter = deleted_edges.begin(); - iter != deleted_edges.end(); ++iter) - remove_edge(*iter, _mg); - deleted_edges.clear(); - } - ReIndexEdges(); -} - - -// this will definitively remove all the verticess from the graph, which are -// being currently filtered out. This will also disable the vertex filter -void GraphInterface::PurgeVertices() -{ - if (!IsVertexFilterActive()) - return; - - RangeFilter filter(_vertex_filter_map, _vertex_range, - _vertex_range_include, - _vertex_range_invert); - size_t N = num_vertices(_mg); - vector deleted(N, false); - for (size_t i = 0; i < N; ++i) - deleted[i] = !filter(vertex(i, _mg)); - - //migrate properties - size_t last = 0; - for (size_t i = 0; i < N; ++i) - { - graph_traits::vertex_descriptor v = vertex(i, _mg); - if (filter(v)) - { - for (typeof(_properties.begin()) p = _properties.begin(); - p != _properties.end(); ++p) - if (p->second->key() == typeid(vertex_t)) - try - { - p->second->put(vertex(last, _mg), p->second->get(v)); - } - catch (dynamic_const_put_error) {} // index prop. is const - last++; - } - } - - //remove vertices - for (size_t i = N-1; i < N; --i) - { - if (deleted[i]) - { - graph_traits::vertex_descriptor v = vertex(i, _mg); - clear_vertex(v, _mg); - remove_vertex(v, _mg); - } - } - ReIndexEdges(); -} - // this will get the number of vertices, either the "soft" O(1) way, or the hard // O(V) way, which is necessary if the graph is filtered size_t GraphInterface::GetNumberOfVertices() const { size_t n = 0; if (IsVertexFilterActive()) - run_action(*this,var(n)=bind(HardNumVertices(),_1)); + run_action<>()(*this, var(n)=bind(HardNumVertices(),_1))(); else - run_action(*this,var(n)=bind(SoftNumVertices(),_1)); + run_action<>()(*this, var(n)=bind(SoftNumVertices(),_1))(); return n; } @@ -402,21 +85,19 @@ size_t GraphInterface::GetNumberOfEdges() const { size_t n = 0; if (IsEdgeFilterActive() || IsVertexFilterActive()) - run_action(*this,var(n)=bind(HardNumEdges(),_1)); + run_action<>()(*this, var(n)=bind(HardNumEdges(),_1))(); else - run_action(*this,var(n)=bind(SoftNumEdges(),_1)); + run_action<>()(*this, var(n)=bind(SoftNumEdges(),_1))(); return n; } - // generalized functor to obtain histogram of different types of "degrees" -template struct get_vertex_histogram { - get_vertex_histogram(DegreeSelector& deg): _degree(deg) {} - template - void operator()(const Graph& g, Hist& hist) const + template + void operator()(const Graph* gp, DegreeSelector deg, Hist& hist) const { + const Graph& g = *gp; SharedMap s_hist(hist); int i, N = num_vertices(g); #pragma omp parallel for default(shared) private(i) \ @@ -426,36 +107,10 @@ struct get_vertex_histogram typename graph_traits::vertex_descriptor v = vertex(i, g); if (v == graph_traits::null_vertex()) continue; - s_hist[_degree(v,g)]++; + s_hist[deg(v,g)]++; } s_hist.Gather(); } - DegreeSelector& _degree; -}; - -// used to cycle through the different types of histograms -struct choose_vertex_histogram -{ - choose_vertex_histogram(const GraphInterface& g, GraphInterface::deg_t deg, - hist_t& hist) - : _g(g), _hist(hist) - { - tie(_deg, _deg_name) = get_degree_type(deg); - } - template - void operator()(DegreeSelector) - { - if (mpl::at::type::value == _deg) - { - DegreeSelector selector(_deg_name, _g, true); - run_action(_g, bind(get_vertex_histogram - (selector), _1, var(_hist))); - } - } - const GraphInterface &_g; - hist_t &_hist; - GraphInterface::degree_t _deg; - string _deg_name; }; @@ -464,13 +119,12 @@ hist_t GraphInterface::GetVertexHistogram(GraphInterface::deg_t deg) const { hist_t hist; + try { - mpl::for_each > - (choose_vertex_histogram(*this, deg, hist)); + run_action<>()(*this, bind(get_vertex_histogram(), _1, _2, + var(hist)), + all_selectors())(degree_selector(deg, _properties)); } catch (dynamic_get_failure &e) { @@ -484,12 +138,10 @@ GraphInterface::GetVertexHistogram(GraphInterface::deg_t deg) const // generalized functor to obtain histogram of edge properties struct get_edge_histogram { - get_edge_histogram(scalarS& prop): _prop(prop) {} - template - void operator()(const Graph& g, Hist& hist) const - { - typedef typename graph_traits::directed_category - directed_category; + template + void operator()(const Graph* gp, Prop eprop, Hist& hist) const + { + const Graph& g = *gp; SharedMap s_hist(hist); int i, N = num_vertices(g); @@ -504,28 +156,34 @@ struct get_edge_histogram typename graph_traits::out_edge_iterator e, e_begin, e_end; tie(e_begin,e_end) = out_edges(v,g); for(e = e_begin; e != e_end; ++e) - if(is_convertible::value) - s_hist[_prop(*e,g)] += 0.5; - else - s_hist[_prop(*e,g)]++; + s_hist[eprop[*e]]++; } s_hist.Gather(); + + typedef typename graph_traits::directed_category + directed_category; + if(is_convertible::value) + { + for (typeof(s_hist.begin()) iter = s_hist.begin(); + iter != s_hist.end(); ++iter) + iter->second /= typename Hist::value_type::second_type(2); + } } - scalarS& _prop; }; - // returns the histogram of a given edge property hist_t GraphInterface::GetEdgeHistogram(string property) const { hist_t hist; try { - scalarS prop(property, *this, false); - run_action(*this, bind(get_edge_histogram(prop), _1, var(hist))); + run_action<>()(*this, bind(get_edge_histogram(), _1, _2, + var(hist)), + edge_scalar_properties()) + (prop(property, _edge_index, _properties)); } - catch (dynamic_get_failure &e) + catch (dynamic_get_failure& e) { throw GraphException("error getting scalar property: " + string(e.what())); @@ -540,8 +198,9 @@ hist_t GraphInterface::GetEdgeHistogram(string property) const struct label_components { template - void operator()(const Graph &g, CompMap comp_map) const + void operator()(const Graph* gp, CompMap comp_map) const { + const Graph& g = *gp; typedef typename graph_traits::directed_category directed_category; get_components(g, comp_map, @@ -567,28 +226,28 @@ struct label_components void GraphInterface::LabelComponents(string prop) { - typedef vector_property_map comp_map_t; - comp_map_t comp_map(_vertex_index); - - run_action(*this, bind(label_components(), _1, comp_map)); - try { - find_property_map(_properties, prop, typeid(vertex_t)); - RemoveVertexProperty(prop); + run_action<>()(*this, label_components(), _1, vertex_scalar_selectors()) + (degree_selector(prop, _properties)); + } + catch (property_not_found) + { + typedef vector_property_map comp_map_t; + comp_map_t comp_map(_vertex_index); + _properties.property(prop, comp_map); + run_action<>()(*this, bind(label_components(), _1, comp_map))(); } - catch (property_not_found) {} - - _properties.property(prop, comp_map); } // label parallel edges in the order they are found, starting from 0 struct label_parallel_edges { template - void operator()(const Graph& g, EdgeIndexMap edge_index, + void operator()(const Graph* gp, EdgeIndexMap edge_index, ParallelMap parallel) const { + const Graph& g = *gp; typedef typename graph_traits::edge_descriptor edge_t; int i, N = num_vertices(g); @@ -623,20 +282,19 @@ struct label_parallel_edges void GraphInterface::LabelParallelEdges(string property) { try - { - DynamicPropertyMapWrap - parallel_map(find_property_map(_properties, property, - typeid(edge_t))); - run_action(*this, bind(label_parallel_edges(), _1, _edge_index, - parallel_map)); + { + run_action<>()(*this, bind(label_parallel_edges(), _1, + _edge_index, _2), + edge_scalar_properties()) + (prop(property, _edge_index, _properties)); } catch (property_not_found) { - typedef vector_property_map parallel_map_t; + typedef vector_property_map parallel_map_t; parallel_map_t parallel_map(_edge_index); - run_action(*this, bind(label_parallel_edges(), _1, _edge_index, - parallel_map)); _properties.property(property, parallel_map); + run_action<>()(*this, bind(label_parallel_edges(), _1, + _edge_index, parallel_map))(); } } diff --git a/src/graph/graph.hh b/src/graph/graph.hh index 804f301bddc6039961d30f839ad8ad765a7a9a7b..5966f5489add3942a6d4930f9cb89be2c8d82c6b 100644 --- a/src/graph/graph.hh +++ b/src/graph/graph.hh @@ -21,12 +21,16 @@ #include #include + +#include + #include #include #include #include #include #include +#include #include "histogram.hh" #include "config.h" #include "graph_properties.hh" @@ -41,6 +45,15 @@ using namespace boost; // the external world will manipulate the graph. All the algorithms should be // registered here. This class will be exported to python in graph_bind.hh +namespace detail +{ +// Generic graph_action functor. See graph_filtering.hh for details. +template , class TR2=boost::mpl::vector<>, + class TR3=boost::mpl::vector<>, class TR4=boost::mpl::vector<> > +struct graph_action; +} + // default visibility is necessary for related typeinfo objects to work across // DSO boundaries #pragma GCC visibility push(default) @@ -56,7 +69,6 @@ public: IN_DEGREE, OUT_DEGREE, TOTAL_DEGREE, // in + out - SCALAR // scalar vertex property }; typedef variant deg_t; // useful when function also expects @@ -73,16 +85,10 @@ public: void SetReversed(bool reversed) {_reversed = reversed;} bool GetReversed() const {return _reversed;} - // graph filtering - void SetVertexFilterProperty(string property); - void SetVertexFilterRange(pair allowed_range, - pair include, bool invert); + void SetVertexFilterProperty(string property, bool invert); bool IsVertexFilterActive() const; - - void SetEdgeFilterProperty(string property); - void SetEdgeFilterRange(pair allowed_range, - pair include, bool invert); + void SetEdgeFilterProperty(string property, bool invert); bool IsEdgeFilterActive() const; @@ -92,15 +98,13 @@ public: void RemoveGraphProperty(string property); void InsertEdgeIndexProperty(string property); void InsertVertexIndexProperty(string property); - void EditVertexProperty(string property, string type, python::object op, - python::object g); - void EditEdgeProperty(string property, string type, python::object op, - python::object g); - void EditGraphProperty(string property, string type, python::object op, - python::object g); + void AddVertexProperty(string property, string type); + void AddEdgeProperty(string property, string type); + void AddGraphProperty(string property, string type); void ReIndexEdges(); void PurgeVertices(); // removes filtered vertices void PurgeEdges(); // removes filtered edges + void Clear(); void RandomRewire(std::string strat, bool self_loops, bool parallel_edges, size_t seed); @@ -183,10 +187,13 @@ public: void ComputeGraphLayoutGursoy(string prop, string weight, string topology, size_t iter = 0, size_t seed = 4357); void ComputeGraphLayoutSpringBlock(string prop, string weight, string type, - size_t iter = 0, size_t seed = 4357); + size_t iter = 0, + bool progressive = false, + size_t seed = 4357); // python interface python::object Vertices() const; + python::object Vertex(size_t i) const; python::object Edges() const; python::object AddVertex(); @@ -231,75 +238,51 @@ public: typedef graph_traits::vertex_descriptor vertex_t; typedef graph_traits::edge_descriptor edge_t; -private: - - // The following function is very central to the implementation of the above - // member functions. Most of the algorithms are implemented as template - // functors, which must be run on the correct version of the graph, i.e., - // filtered, unfiltered, directed, undirected, etc. The functor in question - // must be fed to the function below as the "a" variable, which will take - // care of business, selection the correct implementation. The ReverseCheck - // and DirectedCheck below are utility types which allow for limiting the - // implementation generation when you want it to be confined for only - // specific graph types. See graph_filtering.hh for details. + typedef property_map::type vertex_index_map_t; + typedef property_map::type edge_index_map_t; - template - friend void run_action(GraphInterfaceType &g, Action a, - ReverseCheck, DirectedCheck, bool run_all=false); + size_t GetEdgeHash(const edge_t& e) const; - // useful overload for common case where all graph types should be probed - template - friend void run_action(GraphInterfaceType &g, Action a); +private: + // Gets the encapsulated graph view. See graph_filtering.cc for details + boost::any GetGraphView() const; - friend class scalarS; + // Generic graph_action functor. See graph_filtering.hh for details. + template , class TR2=boost::mpl::vector<>, + class TR3=boost::mpl::vector<>, class TR4=boost::mpl::vector<> > + friend struct detail::graph_action; // this is the main graph multigraph_t _mg; + // this will hold an instance of the graph views at run time + vector _graph_views; + // reverse and directed states bool _reversed; bool _directed; // vertex index map - typedef property_map::type vertex_index_map_t; vertex_index_map_t _vertex_index; // edge index map - typedef property_map::type edge_index_map_t; edge_index_map_t _edge_index; // graph properties dynamic_properties _properties; // vertex filter - string _vertex_filter_property; - typedef variant, - HashedDescriptorMap, - vector_property_map, - HashedDescriptorMap, - vertex_index_map_t, - DynamicPropertyMapWrap > - vertex_filter_map_t; - vertex_filter_map_t _vertex_filter_map; - pair _vertex_range; - pair _vertex_range_include; - bool _vertex_range_invert; + typedef vector_property_map vertex_filter_t; + vertex_filter_t _vertex_filter_map; + bool _vertex_filter_invert; + bool _vertex_filter_active; // edge filter - string _edge_filter_property; - typedef variant, - HashedDescriptorMap, - vector_property_map, - HashedDescriptorMap, - edge_index_map_t, - DynamicPropertyMapWrap > - edge_filter_map_t; - edge_filter_map_t _edge_filter_map; - pair _edge_range; - pair _edge_range_include; - bool _edge_range_invert; - + typedef vector_property_map edge_filter_t; + edge_filter_t _edge_filter_map; + bool _edge_filter_invert; + bool _edge_filter_active; }; #pragma GCC visibility pop diff --git a/src/graph/graph_adaptor.hh b/src/graph/graph_adaptor.hh index f1d72e0106b1687eef1a6b663819377e6d6eeb77..c8032cc311d261cbadf34efaeda1acb0aef53ecb 100644 --- a/src/graph/graph_adaptor.hh +++ b/src/graph/graph_adaptor.hh @@ -18,6 +18,8 @@ #ifndef GRAPH_ADAPTOR_HH #define GRAPH_ADAPTOR_HH +#include + #include #include #include diff --git a/src/graph/graph_assortativity.cc b/src/graph/graph_assortativity.cc index ab86c9078ab90a9590bf2eec69bd1f8e2723537f..c8e5911aeb3a640372388ef55dad9ddd74fb17d5 100644 --- a/src/graph/graph_assortativity.cc +++ b/src/graph/graph_assortativity.cc @@ -16,135 +16,18 @@ // along with this program. If not, see . -#include -#include -#include -#include -#include - -#include "graph.hh" -#include "histogram.hh" #include "graph_filtering.hh" #include "graph_selectors.hh" #include "graph_properties.hh" -#include "shared_map.hh" +#include "graph.hh" + +#include "graph_assortativity.hh" using namespace std; using namespace boost; using namespace boost::lambda; using namespace graph_tool; -// this will calculate the assortativity coefficient, based on the property -// pointed by 'deg' - -template -struct get_assortativity_coefficient -{ - get_assortativity_coefficient(DegreeSelector& deg): _deg(deg) {} - - template - void operator()(const Graph& g, double& r, double& r_err) const - { - size_t n_edges = 0; - int e_kk = 0; - tr1::unordered_map a, b; - SharedMap > sa(a), sb(b); - - int i, N = num_vertices(g); - #pragma omp parallel for default(shared) private(i) firstprivate(sa,sb)\ - schedule(dynamic) reduction(+:e_kk, n_edges) - for (i = 0; i < N; ++i) - { - typename graph_traits::vertex_descriptor v = vertex(i, g); - if (v == graph_traits::null_vertex()) - continue; - - double k1 = _deg(v, g); - typename graph_traits::out_edge_iterator e, e_end; - for (tie(e,e_end) = out_edges(v, g); e != e_end; ++e) - { - double k2 = _deg(target(*e, g), g); - sa[k1]++; - sb[k2]++; - if (k1 == k2) - e_kk++; - n_edges++; - } - } - - sa.Gather(); - sb.Gather(); - - double t1=double(e_kk)/n_edges, t2=0.0; - - for (typeof(a.begin()) iter = a.begin(); iter != a.end(); ++iter) - if (b.find(iter->second) != b.end()) - t2 += double(iter->second * b[iter->first]); - t2 /= n_edges*n_edges; - - r = (t1 - t2)/(1.0 - t2); - - // "jackknife" variance - double err = 0.0; - #pragma omp parallel for default(shared) private(i) schedule(dynamic)\ - reduction(+:err) - for (i = 0; i < N; ++i) - { - typename graph_traits::vertex_descriptor v = vertex(i, g); - if (v == graph_traits::null_vertex()) - continue; - - double k1 = _deg(v, g); - typename graph_traits::out_edge_iterator e, e_end; - for (tie(e,e_end) = out_edges(v, g); e != e_end; ++e) - { - double k2 = _deg(target(*e,g),g); - double tl2 = (t2*(n_edges*n_edges) - b[k1] - a[k2])/ - ((n_edges-1)*(n_edges-1)); - double tl1 = t1*n_edges; - if (k1 == k2) - tl1 -= 1; - tl1 /= n_edges - 1; - double rl = (tl1 - tl2)/(1.0 - tl2); - err += (r-rl)*(r-rl); - } - } - r_err = sqrt(err); - } - - DegreeSelector& _deg; -}; - -struct choose_assortativity_coefficient -{ - choose_assortativity_coefficient(const GraphInterface& g, - GraphInterface::deg_t deg, - double& a, double& a_err) - : _g(g), _a(a), _a_err(a_err) - { - tie(_deg, _deg_name) = get_degree_type(deg); - } - - - template - void operator()(DegreeSelector) - { - if (mpl::at::type::value == _deg) - { - DegreeSelector deg(_deg_name, _g, true); - run_action(_g, bind(get_assortativity_coefficient - (deg), - _1, var(_a), var(_a_err))); - } - } - - const GraphInterface& _g; - double& _a; - double& _a_err; - GraphInterface::degree_t _deg; - string _deg_name; -}; - pair GraphInterface::GetAssortativityCoefficient(GraphInterface::deg_t deg) const @@ -152,10 +35,10 @@ GraphInterface::GetAssortativityCoefficient(GraphInterface::deg_t deg) const double a, a_err; try { - typedef mpl::vector - degrees; - mpl::for_each(choose_assortativity_coefficient(*this, deg, a, - a_err)); + run_action<>()(*this, + bind(get_assortativity_coefficient(), _1, _2, + var(a), var(a_err)), all_selectors()) + (degree_selector(deg, _properties)); } catch (dynamic_get_failure &e) { @@ -166,130 +49,6 @@ GraphInterface::GetAssortativityCoefficient(GraphInterface::deg_t deg) const return make_pair(a, a_err); } -// this will calculate the _scalar_ assortativity coefficient, based on the -// scalar property pointed by 'deg' - -template -struct get_scalar_assortativity_coefficient -{ - get_scalar_assortativity_coefficient(DegreeSelector& deg): _deg(deg) {} - - template - void operator()(const Graph& g, double& r, double& r_err) const - { - size_t n_edges = 0; - double e_xy = 0.0; - tr1::unordered_map a, b; - SharedMap > sa(a), sb(b); - - int i, N = num_vertices(g); - #pragma omp parallel for default(shared) private(i) firstprivate(sa,sb)\ - schedule(dynamic) reduction(+:e_xy, n_edges) - for (i = 0; i < N; ++i) - { - typename graph_traits::vertex_descriptor v = vertex(i, g); - if (v == graph_traits::null_vertex()) - continue; - - double k1 = _deg(v, g); - typename graph_traits::out_edge_iterator e, e_end; - for (tie(e,e_end) = out_edges(v, g); e != e_end; ++e) - { - double k2 = _deg(target(*e,g),g); - sa[k1]++; - sb[k2]++; - e_xy += k1*k2; - n_edges++; - } - } - - sa.Gather(); - sb.Gather(); - - double t1 = e_xy/n_edges; - double avg_a = GetHistogramMean(a), avg_b = GetHistogramMean(b); - double da = GetHistogramDeviation(a,avg_a), db = - GetHistogramDeviation(b,avg_b); - - if (da*db > 0) - r = (t1 - avg_a*avg_b)/(da*db); - else - r = (t1 - avg_a*avg_b); - - // "jackknife" variance - r_err = 0.0; - double diff_a = 0.0, diff_b = 0.0; - for (typeof(a.begin()) iter = a.begin(); iter != a.end(); ++iter) - diff_a += (iter->first - avg_a)*iter->second; - for (typeof(b.begin()) iter = b.begin(); iter != b.end(); ++iter) - diff_b += (iter->first - avg_b)*iter->second; - - double err = 0.0; - #pragma omp parallel for default(shared) private(i) schedule(dynamic)\ - reduction(+:err) - for (i = 0; i < N; ++i) - { - typename graph_traits::vertex_descriptor v = vertex(i, g); - if (v == graph_traits::null_vertex()) - continue; - - double k1 = _deg(v, g); - typename graph_traits::out_edge_iterator e, e_end; - for (tie(e,e_end) = out_edges(v, g); e != e_end; ++e) - { - double k2 = _deg(target(*e, g), g); - double t1l = (e_xy - k1*k2)/(n_edges-1); - double avg_al = (avg_a*n_edges - k1)/(n_edges-1); - double avg_bl = (avg_b*n_edges - k2)/(n_edges-1); - double dal = da - 2*diff_a*(avg_al-avg_a) + - (avg_al-avg_a)*(avg_al-avg_a); - double dbl = db - 2*diff_b*(avg_bl-avg_b) + - (avg_bl-avg_b)*(avg_bl-avg_b); - double rl; - if (dal*dbl > 0) - rl = (t1l - avg_al*avg_bl)/(dal*dbl); - else - rl = (t1l - avg_al*avg_bl); - err += (r-rl)*(r-rl); - } - } - r_err = sqrt(err); - } - - DegreeSelector& _deg; -}; - -struct choose_scalar_assortativity_coefficient -{ - choose_scalar_assortativity_coefficient(const GraphInterface& g, - GraphInterface::deg_t deg, - double& a, double& a_err) - : _g(g), _a(a), _a_err(a_err) - { - tie(_deg, _deg_name) = get_degree_type(deg); - } - - - template - void operator()(DegreeSelector) - { - if (mpl::at::type::value == _deg) - { - DegreeSelector deg(_deg_name, _g, true); - run_action(_g, bind(get_scalar_assortativity_coefficient - (deg), - _1, var(_a), var(_a_err))); - } - } - - const GraphInterface& _g; - double& _a; - double& _a_err; - GraphInterface::degree_t _deg; - string _deg_name; -}; - - pair GraphInterface::GetScalarAssortativityCoefficient(GraphInterface::deg_t deg) const @@ -297,10 +56,10 @@ GraphInterface::GetScalarAssortativityCoefficient(GraphInterface::deg_t deg) double a, a_err; try { - typedef mpl::vector - degrees; - mpl::for_each - (choose_scalar_assortativity_coefficient(*this,deg, a, a_err)); + run_action<>()(*this, bind(get_scalar_assortativity_coefficient(), + _1, _2, var(a), var(a_err)), + all_selectors()) + (degree_selector(deg, _properties)); } catch (dynamic_get_failure &e) { diff --git a/src/graph/graph_assortativity.hh b/src/graph/graph_assortativity.hh new file mode 100644 index 0000000000000000000000000000000000000000..e91cf8bc2ffd321776d647bf198709fbc7e39820 --- /dev/null +++ b/src/graph/graph_assortativity.hh @@ -0,0 +1,199 @@ +// graph-tool -- a general graph modification and manipulation thingy +// +// 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 . + +#ifndef GRAPH_ASSORTATIVITY_HH +#define GRAPH_ASSORTATIVITY_HH + +#include +#include "shared_map.hh" + +namespace graph_tool +{ +using namespace std; +using namespace boost; + +// this will calculate the assortativity coefficient, based on the property +// pointed by 'deg' + +struct get_assortativity_coefficient +{ + template + void operator()(const Graph* gp, DegreeSelector deg, double& r, + double& r_err) const + { + const Graph& g = *gp; + size_t n_edges = 0; + int e_kk = 0; + tr1::unordered_map a, b; + SharedMap > sa(a), sb(b); + + int i, N = num_vertices(g); + #pragma omp parallel for default(shared) private(i) firstprivate(sa,sb)\ + schedule(dynamic) reduction(+:e_kk, n_edges) + for (i = 0; i < N; ++i) + { + typename graph_traits::vertex_descriptor v = vertex(i, g); + if (v == graph_traits::null_vertex()) + continue; + + double k1 = deg(v, g); + typename graph_traits::out_edge_iterator e, e_end; + for (tie(e,e_end) = out_edges(v, g); e != e_end; ++e) + { + double k2 = deg(target(*e, g), g); + sa[k1]++; + sb[k2]++; + if (k1 == k2) + e_kk++; + n_edges++; + } + } + + sa.Gather(); + sb.Gather(); + + double t1=double(e_kk)/n_edges, t2=0.0; + + for (typeof(a.begin()) iter = a.begin(); iter != a.end(); ++iter) + if (b.find(iter->second) != b.end()) + t2 += double(iter->second * b[iter->first]); + t2 /= n_edges*n_edges; + + r = (t1 - t2)/(1.0 - t2); + + // "jackknife" variance + double err = 0.0; + #pragma omp parallel for default(shared) private(i) schedule(dynamic)\ + reduction(+:err) + for (i = 0; i < N; ++i) + { + typename graph_traits::vertex_descriptor v = vertex(i, g); + if (v == graph_traits::null_vertex()) + continue; + + double k1 = deg(v, g); + typename graph_traits::out_edge_iterator e, e_end; + for (tie(e,e_end) = out_edges(v, g); e != e_end; ++e) + { + double k2 = deg(target(*e,g),g); + double tl2 = (t2*(n_edges*n_edges) - b[k1] - a[k2])/ + ((n_edges-1)*(n_edges-1)); + double tl1 = t1*n_edges; + if (k1 == k2) + tl1 -= 1; + tl1 /= n_edges - 1; + double rl = (tl1 - tl2)/(1.0 - tl2); + err += (r-rl)*(r-rl); + } + } + r_err = sqrt(err); + } +}; + +// this will calculate the _scalar_ assortativity coefficient, based on the +// scalar property pointed by 'deg' + +struct get_scalar_assortativity_coefficient +{ + template + void operator()(const Graph* gp, DegreeSelector deg, double& r, + double& r_err) const + { + const Graph& g = *gp; + size_t n_edges = 0; + double e_xy = 0.0; + tr1::unordered_map a, b; + SharedMap > sa(a), sb(b); + + int i, N = num_vertices(g); + #pragma omp parallel for default(shared) private(i) firstprivate(sa,sb)\ + schedule(dynamic) reduction(+:e_xy, n_edges) + for (i = 0; i < N; ++i) + { + typename graph_traits::vertex_descriptor v = vertex(i, g); + if (v == graph_traits::null_vertex()) + continue; + + double k1 = deg(v, g); + typename graph_traits::out_edge_iterator e, e_end; + for (tie(e,e_end) = out_edges(v, g); e != e_end; ++e) + { + double k2 = deg(target(*e,g),g); + sa[k1]++; + sb[k2]++; + e_xy += k1*k2; + n_edges++; + } + } + + sa.Gather(); + sb.Gather(); + + double t1 = e_xy/n_edges; + double avg_a = GetHistogramMean(a), avg_b = GetHistogramMean(b); + double da = GetHistogramDeviation(a,avg_a), db = + GetHistogramDeviation(b,avg_b); + + if (da*db > 0) + r = (t1 - avg_a*avg_b)/(da*db); + else + r = (t1 - avg_a*avg_b); + + // "jackknife" variance + r_err = 0.0; + double diff_a = 0.0, diff_b = 0.0; + for (typeof(a.begin()) iter = a.begin(); iter != a.end(); ++iter) + diff_a += (iter->first - avg_a)*iter->second; + for (typeof(b.begin()) iter = b.begin(); iter != b.end(); ++iter) + diff_b += (iter->first - avg_b)*iter->second; + + double err = 0.0; + #pragma omp parallel for default(shared) private(i) schedule(dynamic)\ + reduction(+:err) + for (i = 0; i < N; ++i) + { + typename graph_traits::vertex_descriptor v = vertex(i, g); + if (v == graph_traits::null_vertex()) + continue; + + double k1 = deg(v, g); + typename graph_traits::out_edge_iterator e, e_end; + for (tie(e,e_end) = out_edges(v, g); e != e_end; ++e) + { + double k2 = deg(target(*e, g), g); + double t1l = (e_xy - k1*k2)/(n_edges-1); + double avg_al = (avg_a*n_edges - k1)/(n_edges-1); + double avg_bl = (avg_b*n_edges - k2)/(n_edges-1); + double dal = da - 2*diff_a*(avg_al-avg_a) + + (avg_al-avg_a)*(avg_al-avg_a); + double dbl = db - 2*diff_b*(avg_bl-avg_b) + + (avg_bl-avg_b)*(avg_bl-avg_b); + double rl; + if (dal*dbl > 0) + rl = (t1l - avg_al*avg_bl)/(dal*dbl); + else + rl = (t1l - avg_al*avg_bl); + err += (r-rl)*(r-rl); + } + } + r_err = sqrt(err); + } +}; + +} // graph_tool namespace + +#endif //GRAPH_ASSORTATIVITY_HH diff --git a/src/graph/graph_betweenness.cc b/src/graph/graph_betweenness.cc index f04b25c5710219c3bfb4e155cd2588a23ec9735d..76d0fc9e8c1996bb32b03615b75e86f38fefa162 100644 --- a/src/graph/graph_betweenness.cc +++ b/src/graph/graph_betweenness.cc @@ -15,31 +15,25 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +#include "graph_filtering.hh" -#include #include -#include +#include #include "graph.hh" -#include "histogram.hh" -#include "graph_filtering.hh" #include "graph_selectors.hh" -#include "graph_properties.hh" -#include "graph_adaptor.hh" - -#include - using namespace std; using namespace boost; using namespace boost::lambda; using namespace graph_tool; -template -void normalize_betweenness(const Graph& g, VertexBetweenness vertex_betweenness, - EdgeBetweenness edge_betweenness) +template +void normalize_betweenness(const Graph& g, + EdgeBetweenness edge_betweenness, + VertexBetweenness vertex_betweenness) { - size_t n = HardNumVertices()(g); + size_t n = HardNumVertices()(&g); double factor = 2.0/(n*n - 3*n + 2); typename graph_traits::vertex_iterator v, v_end; @@ -59,170 +53,147 @@ struct get_betweenness { template - void operator()(Graph& g, VertexIndexMap index_map, + void operator()(const Graph* gp, VertexIndexMap index_map, EdgeBetweenness edge_betweenness, VertexBetweenness vertex_betweenness) const { - brandes_betweenness_centrality(g, vertex_index_map(index_map). - edge_centrality_map(edge_betweenness). - centrality_map(vertex_betweenness)); - normalize_betweenness(g, vertex_betweenness, edge_betweenness); + vector::edge_descriptor> > + incoming_map(num_vertices(*gp)); + vector distance_map(num_vertices(*gp)); + vector::value_type> + dependency_map(num_vertices(*gp)); + vector path_count_map(num_vertices(*gp)); + + brandes_betweenness_centrality + (*gp, vertex_betweenness,edge_betweenness, + make_iterator_property_map(incoming_map.begin(), index_map), + make_iterator_property_map(distance_map.begin(), index_map), + make_iterator_property_map(dependency_map.begin(), index_map), + make_iterator_property_map(path_count_map.begin(), index_map), + index_map); + normalize_betweenness(*gp, edge_betweenness, vertex_betweenness); } }; -template +template struct get_weighted_betweenness { - get_weighted_betweenness(Graph& g, VertexIndexMap vertex_index, - EdgeIndexMap edge_index, string& weight, - dynamic_properties& dp, - EdgeBetweenness edge_betweenness, - VertexBetweenness vertex_betweenness, bool& found) - :_g(g), _vertex_index(vertex_index), _edge_index(edge_index), - _weight(weight), _dp(dp), _edge_betweenness(edge_betweenness), - _vertex_betweenness(vertex_betweenness), _found(found) {} - - template - void operator()(WeightType) - { - try - { - typedef vector_property_map weight_map_t; - weight_map_t weight_map(_edge_index); - weight_map = get_static_property_map - (find_property_map(_dp, _weight, - typeid(GraphInterface::edge_t))); - brandes_betweenness_centrality - (_g, vertex_index_map(_vertex_index).weight_map(weight_map). - edge_centrality_map(_edge_betweenness). - centrality_map(_vertex_betweenness)); - normalize_betweenness(_g, _vertex_betweenness, _edge_betweenness); - _found = true; - } - catch (property_not_found) {} - catch (bad_cast) {} - } - - Graph& _g; - VertexIndexMap _vertex_index; - EdgeIndexMap _edge_index; - string& _weight; - dynamic_properties& _dp; - EdgeBetweenness _edge_betweenness; - VertexBetweenness _vertex_betweenness; - bool& _found; -}; + get_weighted_betweenness(VertexIndexMap index): _vertex_index(index) {} -struct choose_weight_map -{ - template - void operator()(Graph& g, VertexIndexMap vertex_index, - EdgeIndexMap edge_index, string& weight, - dynamic_properties& dp, - EdgeBetweenness edge_betweenness, - VertexBetweenness vertex_betweenness, bool& found) const + template + void operator()(const Graph* gp, EdgeBetweenness edge_betweenness, + VertexBetweenness vertex_betweenness, + WeightMap weight_map) const { - mpl::for_each - (get_weighted_betweenness - (g, vertex_index, edge_index, weight, dp, edge_betweenness, - vertex_betweenness, found)); + vector::edge_descriptor> > + incoming_map(num_vertices(*gp)); + vector::value_type> + distance_map(num_vertices(*gp)); + vector::value_type> + dependency_map(num_vertices(*gp)); + vector path_count_map(num_vertices(*gp)); + + brandes_betweenness_centrality + (*gp, vertex_betweenness,edge_betweenness, + make_iterator_property_map(incoming_map.begin(), _vertex_index), + make_iterator_property_map(distance_map.begin(), _vertex_index), + make_iterator_property_map(dependency_map.begin(), _vertex_index), + make_iterator_property_map(path_count_map.begin(), _vertex_index), + _vertex_index, weight_map); + normalize_betweenness(*gp, edge_betweenness, vertex_betweenness); } + + VertexIndexMap _vertex_index; }; void GraphInterface::GetBetweenness(string weight, string edge_betweenness, string vertex_betweenness) { - typedef vector_property_map - vertex_betweenness_map_t; - vertex_betweenness_map_t vertex_betweenness_map(_vertex_index); - - typedef vector_property_map - edge_betweenness_map_t; - edge_betweenness_map_t edge_betweenness_map(_edge_index); + boost::any edge_prop, vertex_prop; - if (weight != "") + try { - bool found = false; - run_action(*this, bind(choose_weight_map(), _1, - var(_vertex_index), var(_edge_index), - var(weight), var(_properties), - var(edge_betweenness_map), - var(vertex_betweenness_map), - var(found))); - if (!found) - throw GraphException("error getting scalar property: " + weight); + find_property_map(_properties, edge_betweenness, typeid(edge_t)); + edge_prop = prop(edge_betweenness, _edge_index, _properties); + if (!belongs()(edge_prop)) + throw GraphException("edge property " + edge_betweenness + + " is not of floating type"); } - else + catch (property_not_found) { - run_action(*this, bind(get_betweenness(), _1, - var(_vertex_index), - var(edge_betweenness_map), - var(vertex_betweenness_map)), - reverse_check(), directed_check()); - } - - if (vertex_betweenness != "") - { - try - { - find_property_map(_properties, vertex_betweenness, - typeid(vertex_t)); - RemoveVertexProperty(vertex_betweenness); - } - catch (property_not_found) {} + typedef vector_property_map + edge_betweenness_map_t; + edge_betweenness_map_t edge_betweenness_map(_edge_index); + edge_prop = edge_betweenness_map; + } - _properties.property(vertex_betweenness, vertex_betweenness_map); + try + { + find_property_map(_properties, vertex_betweenness, typeid(vertex_t)); + vertex_prop = prop(vertex_betweenness, _vertex_index, _properties); + if (!belongs()(vertex_prop)) + throw GraphException("vertex property " + vertex_betweenness + + " is not of floating type"); + } + catch (property_not_found) + { + typedef vector_property_map + vertex_betweenness_map_t; + vertex_betweenness_map_t vertex_betweenness_map(_vertex_index); + vertex_prop = vertex_betweenness_map; } - if (edge_betweenness != "") + if (weight != "") { try { - find_property_map(_properties, edge_betweenness, - typeid(edge_t)); - RemoveEdgeProperty(edge_betweenness); + run_action<>() + (*this, + get_weighted_betweenness(_vertex_index), + edge_floating_properties(), vertex_floating_properties(), + edge_scalar_properties())(edge_prop, vertex_prop, + prop(weight, _edge_index, + _properties)); + } + catch (property_not_found& e) + { + throw GraphException("edge property " + weight + " not found"); } - catch (property_not_found) {} - - _properties.property(edge_betweenness, edge_betweenness_map); } - + else + { + run_action<>()(*this, bind(get_betweenness(), _1, + _vertex_index, _2, _3), + edge_floating_properties(), vertex_floating_properties()) + (edge_prop, vertex_prop); + } } struct get_central_point_dominance { template - void operator()(Graph& g, VertexBetweenness vertex_betweenness, double& c) + void operator()(Graph* g, VertexBetweenness vertex_betweenness, double& c) const { - c = central_point_dominance(g, vertex_betweenness); + c = central_point_dominance(*g, vertex_betweenness); } }; - double GraphInterface::GetCentralPointDominance(string vertex_betweenness) { try { - typedef DynamicPropertyMapWrap betweenness_map_t; - betweenness_map_t betweenness(find_property_map(_properties, - vertex_betweenness, - typeid(vertex_t))); double c = 0.0; - bool reversed = this->GetReversed(); bool directed = this->GetDirected(); + bool reversed = this->GetReversed(); this->SetReversed(false); this->SetDirected(true); - run_action(*this, bind(get_central_point_dominance(), _1, - var(betweenness), var(c)), - never_reversed(), always_directed()); + run_action() + (*this, bind(get_central_point_dominance(), _1, _2, + var(c)), vertex_scalar_properties()) + (prop(vertex_betweenness, _vertex_index, _properties)); this->SetReversed(reversed); this->SetDirected(directed); return c; diff --git a/src/graph/graph_bind.cc b/src/graph/graph_bind.cc index 3810d34b6af0ebaa6b86269315f0772c5a13edae..2c221cb5bc9312adb41e6c334f0bd170cce9c727 100644 --- a/src/graph/graph_bind.cc +++ b/src/graph/graph_bind.cc @@ -16,6 +16,7 @@ // along with this program. If not, see . +#include "graph_filtering.hh" #include #include #include "graph.hh" @@ -174,56 +175,13 @@ 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()); - } - - static void* convertible(PyObject* obj_ptr) - { - handle<> x(borrowed(obj_ptr)); - object o(x); - extract first(o[0]); - extract 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(o[0]); - value.y = extract(o[1]); - void* storage = - ( (boost::python::converter::rvalue_from_python_storage - *) data)->storage.bytes; - new (storage) pos_t(value); - data->convertible = storage; - } -}; - struct LibInfo { string GetName() const {return PACKAGE_NAME;} string GetAuthor() const {return AUTHOR;} string GetCopyright() const {return COPYRIGHT;} - string GetVersion() const {return VERSION " (commit " GIT_COMMIT ", " GIT_COMMIT_DATE ")";} + string GetVersion() const {return VERSION " (commit " GIT_COMMIT + ", " GIT_COMMIT_DATE ")";} string GetLicense() const {return "GPL version 3 or above";} string GetCXXFLAGS() const {return CXXFLAGS;} string GetInstallPrefix() const {return INSTALL_PREFIX;} @@ -293,15 +251,13 @@ BOOST_PYTHON_MODULE(libgraph_tool) .def("GetReversed", &GraphInterface::GetReversed) .def("SetVertexFilterProperty", &GraphInterface::SetVertexFilterProperty) - .def("SetVertexFilterRange", &GraphInterface::SetVertexFilterRange) .def("IsVertexFilterActive", &GraphInterface::IsVertexFilterActive) .def("SetEdgeFilterProperty", &GraphInterface::SetEdgeFilterProperty) - .def("SetEdgeFilterRange", &GraphInterface::SetEdgeFilterRange) .def("IsEdgeFilterActive", &GraphInterface::IsEdgeFilterActive) - .def("EditEdgeProperty", &GraphInterface::EditEdgeProperty) - .def("EditVertexProperty", &GraphInterface::EditVertexProperty) - .def("EditGraphProperty", &GraphInterface::EditGraphProperty) + .def("AddEdgeProperty", &GraphInterface::AddEdgeProperty) + .def("AddVertexProperty", &GraphInterface::AddVertexProperty) + .def("AddGraphProperty", &GraphInterface::AddGraphProperty) .def("RemoveEdgeProperty", &GraphInterface::RemoveEdgeProperty) .def("RemoveVertexProperty", &GraphInterface::RemoveVertexProperty) .def("RemoveGraphProperty", &GraphInterface::RemoveGraphProperty) @@ -320,11 +276,13 @@ BOOST_PYTHON_MODULE(libgraph_tool) .def("ReadFromFile", ReadFromFile1) .def("ReadFromFile", ReadFromFile2) .def("Vertices", &GraphInterface::Vertices) + .def("Vertex", &GraphInterface::Vertex) .def("Edges", &GraphInterface::Edges) .def("AddVertex", &GraphInterface::AddVertex) .def("AddEdge", &GraphInterface::AddEdge) .def("RemoveVertex", &GraphInterface::RemoveVertex) .def("RemoveEdge", &GraphInterface::RemoveEdge) + .def("Clear", &GraphInterface::Clear) .def("GetVertexProperties", &GraphInterface::GetVertexProperties) .def("GetEdgeProperties", &GraphInterface::GetEdgeProperties) .def("GetGraphProperties", &GraphInterface::GetGraphProperties) @@ -347,8 +305,6 @@ BOOST_PYTHON_MODULE(libgraph_tool) to_python_converter, tuple_to_tuple >(); tuple_from_tuple(); - to_python_converter(); - pos_t_from_tuple(); pair_from_tuple(); to_python_converter >(); to_python_converter >(); diff --git a/src/graph/graph_clustering.cc b/src/graph/graph_clustering.cc index 44dc95d4ce595b9a953251749f45289fa84b2bb8..470bdbd0969f74f522676c35b8834ee6712db6c0 100644 --- a/src/graph/graph_clustering.cc +++ b/src/graph/graph_clustering.cc @@ -15,204 +15,54 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . - -#include -#include -#include -#include -#include -#include +#include "graph_filtering.hh" #include "graph.hh" -#include "histogram.hh" -#include "graph_filtering.hh" #include "graph_selectors.hh" #include "graph_properties.hh" +#include "graph_clustering.hh" + using namespace std; using namespace boost; using namespace boost::lambda; using namespace graph_tool; -// calculates the number of triangles to which v belongs -template -pair -get_triangles(typename graph_traits::vertex_descriptor v, const Graph &g) -{ - tr1::unordered_set::vertex_descriptor> - neighbour_set1, neighbour_set2, neighbour_set3; - - size_t triangles = 0, k = 0; - - typename graph_traits::adjacency_iterator n1_begin, n1_end, n1; - tie(n1_begin, n1_end) = adjacent_vertices(v, g); - for (n1 = n1_begin; n1 != n1_end; ++n1) - { - if (*n1 == v) // no self-loops - continue; - if (neighbour_set1.find(*n1) != neighbour_set1.end()) - continue; - else - neighbour_set1.insert(*n1); - - typename graph_traits::adjacency_iterator n2_begin, n2_end, n2; - tie(n2_begin, n2_end) = adjacent_vertices(*n1, g); - for (n2 = n2_begin; n2 != n2_end; ++n2) - { - if (*n2 == *n1) // no self-loops - continue; - if (neighbour_set2.find(*n2) != neighbour_set2.end()) - continue; - else - neighbour_set2.insert(*n2); - - typename graph_traits::adjacency_iterator - n3_begin, n3_end, n3; - tie(n3_begin, n3_end) = adjacent_vertices(*n2, g); - for (n3 = n3_begin; n3 != n3_end; ++n3) - { - if (*n3 == *n2) // no self-loops - continue; - if (neighbour_set3.find(*n3) != neighbour_set3.end()) - continue; - else - neighbour_set3.insert(*n3); - - if (*n3 == v) //found a triangle - triangles++; - } - neighbour_set3.clear(); - } - neighbour_set2.clear(); - k++; - } - neighbour_set1.clear(); - return make_pair(triangles/2,(k*(k-1))/2); -} - - -// retrieves the global clustering coefficient -struct get_global_clustering -{ - template - void operator()(const Graph &g, double &c, double &c_err) const - { - size_t triangles = 0, n = 0; - pair temp; - - int i, N = num_vertices(g); - - #pragma omp parallel for default(shared) private(i,temp) \ - schedule(dynamic) - for (i = 0; i < N; ++i) - { - typename graph_traits::vertex_descriptor v = vertex(i, g); - if (v == graph_traits::null_vertex()) - continue; - - temp = get_triangles(v, g); - - #pragma omp critical - { - triangles += temp.first; - n += temp.second; - } - } - c = double(triangles)/n; - - // "jackknife" variance - c_err = 0.0; - - #pragma omp parallel for default(shared) private(i,temp) \ - schedule(dynamic) - for (i = 0; i < N; ++i) - { - typename graph_traits::vertex_descriptor v = vertex(i, g); - if (v == graph_traits::null_vertex()) - continue; - - temp = get_triangles(v, g); - double cl = double(triangles - temp.first)/(n - temp.second); - - #pragma omp atomic - c_err += (c - cl)*(c - cl); - } - c_err = sqrt(c_err); - } -}; - - pair GraphInterface::GetGlobalClustering() { double c, c_err; bool directed = _directed; _directed = false; - run_action(*this, bind(get_global_clustering(), _1, var(c), - var(c_err)), - reverse_check(), always_undirected()); + run_action() + (*this, bind(get_global_clustering(), _1, var(c), var(c_err)))(); _directed = directed; return make_pair(c,c_err); } -// sets the local clustering coefficient to a property -struct set_clustering_to_property -{ - template - void operator()(const Graph& g, ClustMap& clust_map) const - { - typename get_undirected_graph::type ug(g); - 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::vertex_descriptor v = vertex(i, g); - if (v == graph_traits::null_vertex()) - continue; - - pair triangles = get_triangles(v,ug); // get from ug - double clustering = (triangles.second > 0) ? - double(triangles.first)/triangles.second : - 0.0; - - #pragma omp critical - { - clust_map[v] = clustering; - } - } - } - - template - struct get_undirected_graph - { - typedef typename mpl::if_ - < is_convertible::directed_category, - directed_tag>, - const UndirectedAdaptor, - const Graph& >::type type; - }; -}; - - void GraphInterface::SetLocalClusteringToProperty(string property) { - typedef vector_property_map clust_map_t; - clust_map_t clust_map(num_vertices(_mg), _vertex_index); - - bool directed = _directed; - _directed = false; - run_action(*this, bind(set_clustering_to_property(), _1, - var(clust_map)), - reverse_check(), always_undirected()); - _directed = directed; + boost::any vertex_prop; try { find_property_map(_properties, property, typeid(vertex_t)); - RemoveVertexProperty(property); + vertex_prop = prop(property, _vertex_index, _properties); + if (!belongs()(vertex_prop)) + throw GraphException("vertex property " + property + + " is not of floating type"); + } + catch (property_not_found) + { + typedef vector_property_map clust_map_t; + clust_map_t clust_map(num_vertices(_mg), _vertex_index); + _properties.property(property, clust_map); + vertex_prop = clust_map; } - catch (property_not_found) {} - _properties.property(property, clust_map); + bool directed = _directed; + _directed = false; + run_action() + (*this, bind(set_clustering_to_property(), _1, _2))(vertex_prop); + _directed = directed; } diff --git a/src/graph/graph_clustering.hh b/src/graph/graph_clustering.hh new file mode 100644 index 0000000000000000000000000000000000000000..de6ce48ccd1f74d098f60e93b6ecfd356c81574e --- /dev/null +++ b/src/graph/graph_clustering.hh @@ -0,0 +1,174 @@ +// graph-tool -- a general graph modification and manipulation thingy +// +// 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 . + +#ifndef GRAPH_CLUSTERING_HH +#define GRAPH_CLUSTERING_HH + +#include +#include + +namespace graph_tool +{ +using namespace boost; + +// calculates the number of triangles to which v belongs +template +pair +get_triangles(typename graph_traits::vertex_descriptor v, const Graph &g) +{ + tr1::unordered_set::vertex_descriptor> + neighbour_set1, neighbour_set2, neighbour_set3; + + size_t triangles = 0, k = 0; + + typename graph_traits::adjacency_iterator n1_begin, n1_end, n1; + tie(n1_begin, n1_end) = adjacent_vertices(v, g); + for (n1 = n1_begin; n1 != n1_end; ++n1) + { + if (*n1 == v) // no self-loops + continue; + if (neighbour_set1.find(*n1) != neighbour_set1.end()) + continue; + else + neighbour_set1.insert(*n1); + + typename graph_traits::adjacency_iterator n2_begin, n2_end, n2; + tie(n2_begin, n2_end) = adjacent_vertices(*n1, g); + for (n2 = n2_begin; n2 != n2_end; ++n2) + { + if (*n2 == *n1) // no self-loops + continue; + if (neighbour_set2.find(*n2) != neighbour_set2.end()) + continue; + else + neighbour_set2.insert(*n2); + + typename graph_traits::adjacency_iterator + n3_begin, n3_end, n3; + tie(n3_begin, n3_end) = adjacent_vertices(*n2, g); + for (n3 = n3_begin; n3 != n3_end; ++n3) + { + if (*n3 == *n2) // no self-loops + continue; + if (neighbour_set3.find(*n3) != neighbour_set3.end()) + continue; + else + neighbour_set3.insert(*n3); + + if (*n3 == v) //found a triangle + triangles++; + } + neighbour_set3.clear(); + } + neighbour_set2.clear(); + k++; + } + neighbour_set1.clear(); + return make_pair(triangles/2,(k*(k-1))/2); +} + + +// retrieves the global clustering coefficient +struct get_global_clustering +{ + template + void operator()(const Graph* gp, double& c, double& c_err) const + { + const Graph& g = *gp; + size_t triangles = 0, n = 0; + pair temp; + + int i, N = num_vertices(g); + + #pragma omp parallel for default(shared) private(i,temp) \ + schedule(dynamic) reduction(+:triangles) + for (i = 0; i < N; ++i) + { + typename graph_traits::vertex_descriptor v = vertex(i, g); + if (v == graph_traits::null_vertex()) + continue; + + temp = get_triangles(v, g); + triangles += temp.first; + n += temp.second; + } + c = double(triangles)/n; + + // "jackknife" variance + c_err = 0.0; + + #pragma omp parallel for default(shared) private(i,temp) \ + schedule(dynamic) reduction(+|c_err) + for (i = 0; i < N; ++i) + { + typename graph_traits::vertex_descriptor v = vertex(i, g); + if (v == graph_traits::null_vertex()) + continue; + + temp = get_triangles(v, g); + double cl = double(triangles - temp.first)/(n - temp.second); + + c_err += (c - cl)*(c - cl); + } + c_err = sqrt(c_err); + } +}; + + +// sets the local clustering coefficient to a property +struct set_clustering_to_property +{ + template + void operator()(const Graph* gp, ClustMap clust_map) const + { + const Graph& g = *gp; + typename get_undirected_graph::type ug(g); + 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::vertex_descriptor v = vertex(i, g); + if (v == graph_traits::null_vertex()) + continue; + + pair triangles = get_triangles(v,ug); // get from ug + double clustering = (triangles.second > 0) ? + double(triangles.first)/triangles.second : + 0.0; + + #pragma omp critical + { + clust_map[v] = clustering; + } + } + } + + template + struct get_undirected_graph + { + typedef typename mpl::if_ + < is_convertible::directed_category, + directed_tag>, + const UndirectedAdaptor, + const Graph& >::type type; + }; +}; + +} //graph-tool namespace + +#endif // GRAPH_CLUSTERING_HH diff --git a/src/graph/graph_community.cc b/src/graph/graph_community.cc index ee9057a6dd020fd3515f04e4f7f5d6fd81a07e2c..a48b51149eae723bb07bfda3ab3613c24b98f4c6 100644 --- a/src/graph/graph_community.cc +++ b/src/graph/graph_community.cc @@ -15,675 +15,21 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . - -#include -#include -#include -#include -#include -#include - -#include "graph.hh" -#include "histogram.hh" #include "graph_filtering.hh" +#include "graph.hh" #include "graph_selectors.hh" #include "graph_properties.hh" +#include +#include + +#include "graph_community.hh" + using namespace std; using namespace boost; using namespace boost::lambda; using namespace graph_tool; -using std::tr1::unordered_map; -using std::tr1::unordered_set; - -typedef boost::mt19937 rng_t; - -template -size_t out_degree_no_loops(typename graph_traits::vertex_descriptor v, - const Graph &g) -{ - size_t k = 0; - typename graph_traits::adjacency_iterator a,a_end; - for (tie(a,a_end) = adjacent_vertices(v,g); a != a_end; ++a) - if (*a != v) - k++; - return k; -} - - -// computes the community structure through a spin glass system with -// simulated annealing - -template