Commit 1a0e9b5f authored by Tiago Peixoto's avatar Tiago Peixoto
Browse files

Further improvements of the python interface

Property maps can now be obtained as such:

         weight = g.edge_properties['weight']
         print weight[v] # v is a Vertex object
         weight[v] = 2.0
         # and so on...

The list of properties is obtained from g.vertex_properties,
g.edge_properties and g.graph_properties, which can be read as
dictionaries. The last can be set also, as such:

         g.graph_properties = {foo:"bar", baz:42}

Functions to add and remove vertices or adges were also added
(add_{vertex|edge}, remove_{vertex|edgge}).

Vertex and Edge types can also now be printed for convenience, as such:

       for v in g.vertices():
           print v
       for e in g.edges():
           print e

which results, for example, in:
0
1
2
3
4
5
6
(0,1)
(1,2)
(2,6)
(3,4)
(4,5)
(4,2)
(5,6)
(6,1)

(this also adds the forgotten graph_tool.py file, which was previously
on .gitignore)
parent e1375c3c
...@@ -152,6 +152,8 @@ def _main(): ...@@ -152,6 +152,8 @@ def _main():
underlying function""" underlying function"""
# Parameter regexp # Parameter regexp
p = re.compile(r"((('[^']*')|(\"[^\"']*\"))|([^\|]+)|(^(?=[^$]))(?=\||$))") p = re.compile(r"((('[^']*')|(\"[^\"']*\"))|([^\|]+)|(^(?=[^$]))(?=\||$))")
if arg == None:
arg = ""
values = [x[0].strip() for x in p.findall(arg)] values = [x[0].strip() for x in p.findall(arg)]
n_min = len([x for x in self.positional \ n_min = len([x for x in self.positional \
...@@ -233,10 +235,11 @@ def _main(): ...@@ -233,10 +235,11 @@ def _main():
# point to the corresponding method in the Graph class, through an # point to the corresponding method in the Graph class, through an
# instance of an OptionMask class. # instance of an OptionMask class.
option_groups = [ [x] for x in Graph._Graph__groups ] option_groups = [ [x] for x in graph._Graph__groups ]
functions = [ getattr(graph, f) for f in dir(graph) ] functions = [ getattr(graph, f) for f in dir(graph) ]
functions = [ f for f in functions if callable(f) and \ functions = [ f for f in functions if callable(f) and \
f.func_dict.has_key("opt_group") ] "opt_group" in dir(f) ]
for g in option_groups: for g in option_groups:
g.extend([OptionMask(f) for f in functions \ g.extend([OptionMask(f) for f in functions \
if f.func_dict["opt_group"] == g[0]]) if f.func_dict["opt_group"] == g[0]])
......
...@@ -250,40 +250,38 @@ void GraphInterface::SetEdgeFilterRange(pair<double,double> allowed_range, ...@@ -250,40 +250,38 @@ void GraphInterface::SetEdgeFilterRange(pair<double,double> allowed_range,
// this function will reindex all the edges, in the order in which they are // this function will reindex all the edges, in the order in which they are
// found, taking care of preserving all the properties // found, taking care of preserving all the properties
template<class Graph, class EdgeIndex> void GraphInterface::ReIndexEdges()
void reindex_edges(Graph &g, EdgeIndex edge_index, dynamic_properties& dp) {
{ size_t n_edges = num_edges(_mg);
typedef typename graph_traits<Graph>::edge_descriptor edge_t;
size_t n_edges = num_edges(g);
if (n_edges == 0) if (n_edges == 0)
return; return;
vector<pair<edge_t,bool> > edge_map vector<pair<edge_t,bool> > edge_map
(n_edges, make_pair(edge_t(), false)); (n_edges, make_pair(edge_t(), false));
typename graph_traits<Graph>::vertex_iterator v, v_end; graph_traits<multigraph_t>::vertex_iterator v, v_end;
typename graph_traits<Graph>::out_edge_iterator e, e_end; graph_traits<multigraph_t>::out_edge_iterator e, e_end;
for (tie(v, v_end) = vertices(g); v != v_end; ++v) for (tie(v, v_end) = vertices(_mg); v != v_end; ++v)
for (tie(e, e_end) = out_edges(*v, g); e != e_end; ++e) for (tie(e, e_end) = out_edges(*v, _mg); e != e_end; ++e)
{ {
size_t index = edge_index[*e]; size_t index = _edge_index[*e];
if (index >= edge_map.size()) if (index >= edge_map.size())
edge_map.resize(index+1); edge_map.resize(index+1);
edge_map[index] = make_pair(*e, true); edge_map[index] = make_pair(*e, true);
} }
size_t new_index = 0; size_t new_index = 0;
for (tie(v, v_end) = vertices(g); v != v_end; ++v) for (tie(v, v_end) = vertices(_mg); v != v_end; ++v)
for (tie(e, e_end) = out_edges(*v, g); e != e_end; ++e) for (tie(e, e_end) = out_edges(*v, _mg); e != e_end; ++e)
{ {
edge_t old_edge = edge_map[new_index].first; edge_t old_edge = edge_map[new_index].first;
if (edge_map[new_index].second) if (edge_map[new_index].second)
{ {
// another edge exists with the same index; indexes // another edge exists with the same index; indexes
// must be swapped, as well as the properties // must be swapped, as well as the properties
edge_index[old_edge] = edge_index[*e]; _edge_index[old_edge] = _edge_index[*e];
edge_map[edge_index[*e]] = make_pair(old_edge, true); edge_map[_edge_index[*e]] = make_pair(old_edge, true);
edge_index[*e] = new_index; _edge_index[*e] = new_index;
edge_map[new_index] = make_pair(*e, true); edge_map[new_index] = make_pair(*e, true);
for (typeof(dp.begin()) p = dp.begin(); p != dp.end(); ++p) for (typeof(_properties.begin()) p = _properties.begin();
p != _properties.end(); ++p)
if (p->second->key() == typeid(edge_t)) if (p->second->key() == typeid(edge_t))
{ {
boost::any temp = p->second->get(*e); boost::any temp = p->second->get(*e);
...@@ -296,13 +294,14 @@ void reindex_edges(Graph &g, EdgeIndex edge_index, dynamic_properties& dp) ...@@ -296,13 +294,14 @@ void reindex_edges(Graph &g, EdgeIndex edge_index, dynamic_properties& dp)
// no other edge has this index; it must be then // no other edge has this index; it must be then
// assigned for this edge, and the properties must be // assigned for this edge, and the properties must be
// copied over // copied over
size_t old_index = edge_index[*e]; size_t old_index = _edge_index[*e];
for (typeof(dp.begin()) p = dp.begin(); p != dp.end(); ++p) for (typeof(_properties.begin()) p = _properties.begin();
p != _properties.end(); ++p)
if (p->second->key() == typeid(edge_t)) if (p->second->key() == typeid(edge_t))
{ {
edge_index[*e] = old_index; _edge_index[*e] = old_index;
boost::any val = p->second->get(*e); boost::any val = p->second->get(*e);
edge_index[*e] = new_index; _edge_index[*e] = new_index;
p->second->put(*e, val); p->second->put(*e, val);
} }
} }
...@@ -333,9 +332,10 @@ void GraphInterface::PurgeEdges() ...@@ -333,9 +332,10 @@ void GraphInterface::PurgeEdges()
remove_edge(*iter, _mg); remove_edge(*iter, _mg);
deleted_edges.clear(); deleted_edges.clear();
} }
reindex_edges(_mg, _edge_index, _properties); ReIndexEdges();
} }
// this will definitively remove all the verticess from the graph, which are // this will definitively remove all the verticess from the graph, which are
// being currently filtered out. This will also disable the vertex filter // being currently filtered out. This will also disable the vertex filter
void GraphInterface::PurgeVertices() void GraphInterface::PurgeVertices()
...@@ -380,7 +380,7 @@ void GraphInterface::PurgeVertices() ...@@ -380,7 +380,7 @@ void GraphInterface::PurgeVertices()
remove_vertex(v, _mg); remove_vertex(v, _mg);
} }
} }
reindex_edges(_mg, _edge_index, _properties); ReIndexEdges();
} }
// this will get the number of vertices, either the "soft" O(1) way, or the hard // this will get the number of vertices, either the "soft" O(1) way, or the hard
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <boost/dynamic_property_map.hpp> #include <boost/dynamic_property_map.hpp>
#include <boost/variant.hpp> #include <boost/variant.hpp>
#include <boost/python/object.hpp> #include <boost/python/object.hpp>
#include <boost/python/dict.hpp>
#include "histogram.hh" #include "histogram.hh"
#include "config.h" #include "config.h"
#include "graph_properties.hh" #include "graph_properties.hh"
...@@ -155,7 +156,7 @@ public: ...@@ -155,7 +156,7 @@ public:
void EditVertexProperty(string property, string type, python::object op); void EditVertexProperty(string property, string type, python::object op);
void EditEdgeProperty(string property, string type, python::object op); void EditEdgeProperty(string property, string type, python::object op);
void EditGraphProperty(string property, string type, python::object op); void EditGraphProperty(string property, string type, python::object op);
void ListProperties() const; void ReIndexEdges();
void PurgeVertices(); void PurgeVertices();
void PurgeEdges(); void PurgeEdges();
...@@ -175,6 +176,18 @@ public: ...@@ -175,6 +176,18 @@ public:
python::object Vertices() const; python::object Vertices() const;
python::object Edges() const; python::object Edges() const;
python::object AddVertex();
void RemoveVertex(python::object v);
python::object AddEdge(python::object s, python::object t);
void RemoveEdge(python::object e);
python::dict GetVertexProperties() const;
python::dict GetEdgeProperties() const;
python::dict GetGraphProperties() const;
// used for graph properties
graph_property_tag GetDescriptor() const { return graph_property_tag(); }
void ExportPythonInterface() const; void ExportPythonInterface() const;
// signal handling // signal handling
...@@ -193,8 +206,9 @@ public: ...@@ -193,8 +206,9 @@ public:
typedef graph_traits<multigraph_t>::edge_descriptor edge_t; typedef graph_traits<multigraph_t>::edge_descriptor edge_t;
private: private:
template <class Action, class ReverseCheck, class DirectedCheck> template <class GraphInterfaceType, class Action, class ReverseCheck,
friend void check_filter(const GraphInterface &g, Action a, class DirectedCheck>
friend void check_filter(GraphInterfaceType &g, Action a,
ReverseCheck, DirectedCheck, bool run_all=false); ReverseCheck, DirectedCheck, bool run_all=false);
friend class scalarS; friend class scalarS;
......
...@@ -301,7 +301,6 @@ BOOST_PYTHON_MODULE(libgraph_tool) ...@@ -301,7 +301,6 @@ BOOST_PYTHON_MODULE(libgraph_tool)
.def("RemoveEdgeProperty", &GraphInterface::RemoveEdgeProperty) .def("RemoveEdgeProperty", &GraphInterface::RemoveEdgeProperty)
.def("RemoveVertexProperty", &GraphInterface::RemoveVertexProperty) .def("RemoveVertexProperty", &GraphInterface::RemoveVertexProperty)
.def("RemoveGraphProperty", &GraphInterface::RemoveGraphProperty) .def("RemoveGraphProperty", &GraphInterface::RemoveGraphProperty)
.def("ListProperties", &GraphInterface::ListProperties)
.def("PurgeVertices", &GraphInterface::PurgeVertices) .def("PurgeVertices", &GraphInterface::PurgeVertices)
.def("PurgeEdges", &GraphInterface::PurgeEdges) .def("PurgeEdges", &GraphInterface::PurgeEdges)
.def("InsertEdgeIndexProperty", .def("InsertEdgeIndexProperty",
...@@ -316,8 +315,15 @@ BOOST_PYTHON_MODULE(libgraph_tool) ...@@ -316,8 +315,15 @@ BOOST_PYTHON_MODULE(libgraph_tool)
.def("WriteToFile", WriteToFile2) .def("WriteToFile", WriteToFile2)
.def("ReadFromFile", ReadFromFile1) .def("ReadFromFile", ReadFromFile1)
.def("ReadFromFile", ReadFromFile2) .def("ReadFromFile", ReadFromFile2)
.def("vertices", &GraphInterface::Vertices) .def("Vertices", &GraphInterface::Vertices)
.def("edges", &GraphInterface::Edges) .def("Edges", &GraphInterface::Edges)
.def("AddVertex", &GraphInterface::AddVertex)
.def("AddEdge", &GraphInterface::AddEdge)
.def("RemoveVertex", &GraphInterface::RemoveVertex)
.def("RemoveEdge", &GraphInterface::RemoveEdge)
.def("GetVertexProperties", &GraphInterface::GetVertexProperties)
.def("GetEdgeProperties", &GraphInterface::GetEdgeProperties)
.def("GetGraphProperties", &GraphInterface::GetGraphProperties)
.def("InitSignalHandling", &GraphInterface::InitSignalHandling); .def("InitSignalHandling", &GraphInterface::InitSignalHandling);
enum_<GraphInterface::degree_t>("Degree") enum_<GraphInterface::degree_t>("Degree")
......
...@@ -66,7 +66,6 @@ vertex(size_t i, const reverse_graph<Graph>& g) ...@@ -66,7 +66,6 @@ vertex(size_t i, const reverse_graph<Graph>& g)
return vertex(i, g.m_g); return vertex(i, g.m_g);
} }
//============================================================================== //==============================================================================
// add_edge(u, v, filtered_graph<G>) // add_edge(u, v, filtered_graph<G>)
//============================================================================== //==============================================================================
...@@ -86,6 +85,19 @@ add_edge(typename graph_traits ...@@ -86,6 +85,19 @@ add_edge(typename graph_traits
return add_edge(u,v, const_cast<Graph&>(g.m_g)); return add_edge(u,v, const_cast<Graph&>(g.m_g));
} }
//==============================================================================
// add_edge(u, v, reverse_graph<G>)
//==============================================================================
template <class Graph>
inline
std::pair<typename graph_traits<reverse_graph<Graph> >::edge_descriptor,bool>
add_edge(typename graph_traits<reverse_graph<Graph> >::vertex_descriptor u,
typename graph_traits<reverse_graph<Graph> >::vertex_descriptor v,
reverse_graph<Graph>& g)
{
return add_edge(v, u, const_cast<Graph&>(g.m_g)); // insert reversed
}
//============================================================================== //==============================================================================
//remove_edge(e, filtered_graph<G>) //remove_edge(e, filtered_graph<G>)
//============================================================================== //==============================================================================
...@@ -99,6 +111,29 @@ void remove_edge(typename graph_traits ...@@ -99,6 +111,29 @@ void remove_edge(typename graph_traits
return remove_edge(e,const_cast<Graph&>(g.m_g)); return remove_edge(e,const_cast<Graph&>(g.m_g));
} }
//==============================================================================
// add_vertex(filtered_graph<G>)
//==============================================================================
template <class Graph, class EdgePredicate, class VertexPredicate>
inline
typename graph_traits
<filtered_graph<Graph,EdgePredicate,VertexPredicate> >::vertex_descriptor
add_vertex(filtered_graph<Graph,EdgePredicate,VertexPredicate>& g)
{
return add_vertex(const_cast<Graph&>(g.m_g));
}
//==============================================================================
// add_vertex(reverse_graph<G>)
//==============================================================================
template <class Graph>
inline
typename graph_traits<reverse_graph<Graph> >::vertex_descriptor
add_vertex(reverse_graph<Graph>& g)
{
return add_vertex(const_cast<Graph&>(g.m_g));
}
} // namespace boost } // namespace boost
...@@ -244,7 +279,7 @@ typedef mpl::vector<mpl::bool_<false> > always_undirected; ...@@ -244,7 +279,7 @@ typedef mpl::vector<mpl::bool_<false> > always_undirected;
template <class Graph, class Action> template <class Graph, class Action>
struct check_reverse struct check_reverse
{ {
check_reverse(const Graph &g, Action a, bool reverse, bool& found, check_reverse(Graph &g, Action a, bool reverse, bool& found,
bool run_all) bool run_all)
: _g(g), _a(a), _reverse(reverse), _found(found), _run_all(run_all) {} : _g(g), _a(a), _reverse(reverse), _found(found), _run_all(run_all) {}
...@@ -253,7 +288,13 @@ struct check_reverse ...@@ -253,7 +288,13 @@ struct check_reverse
{ {
if (_reverse || _run_all) if (_reverse || _run_all)
{ {
static reverse_graph<Graph> rg(_g); typedef typename mpl::if_<is_const<Graph>,
const reverse_graph
<typename remove_const<Graph>::type>,
reverse_graph<Graph> >::type
reverse_graph_t;
static reverse_graph_t rg(_g);
_a(rg); _a(rg);
_found = true; _found = true;
} }
...@@ -268,7 +309,7 @@ struct check_reverse ...@@ -268,7 +309,7 @@ struct check_reverse
} }
} }
const Graph &_g; Graph& _g;
Action _a; Action _a;
bool _reverse; bool _reverse;
bool& _found; bool& _found;
...@@ -281,7 +322,7 @@ struct check_reverse ...@@ -281,7 +322,7 @@ struct check_reverse
template <class Graph, class Action, class ReverseCheck> template <class Graph, class Action, class ReverseCheck>
struct check_directed struct check_directed
{ {
check_directed(const Graph &g, Action a, bool reverse, bool directed, check_directed(Graph &g, Action a, bool reverse, bool directed,
bool& found, bool run_all) bool& found, bool run_all)
: _g(g), _a(a), _reverse(reverse), _directed(directed), _found(found), : _g(g), _a(a), _reverse(reverse), _directed(directed), _found(found),
_run_all(run_all) {} _run_all(run_all) {}
...@@ -291,7 +332,7 @@ struct check_directed ...@@ -291,7 +332,7 @@ struct check_directed
{ {
if (_directed || _run_all) if (_directed || _run_all)
mpl::for_each<ReverseCheck> mpl::for_each<ReverseCheck>
(check_reverse<Graph, Action>(_g, _a, _reverse, _found, (check_reverse<Graph,Action>(_g, _a, _reverse, _found,
_run_all)); _run_all));
} }
...@@ -305,7 +346,7 @@ struct check_directed ...@@ -305,7 +346,7 @@ struct check_directed
} }
} }
const Graph &_g; Graph& _g;
Action _a; Action _a;
bool _reverse; bool _reverse;
bool _directed; bool _directed;
...@@ -316,10 +357,14 @@ struct check_directed ...@@ -316,10 +357,14 @@ struct check_directed
// this will check whether a graph is range filtered and run the proper version // this will check whether a graph is range filtered and run the proper version
// of the algorithm // of the algorithm
template <class Action, class ReverseCheck, class DirectedCheck> template <class GraphInterfaceType, class Action, class ReverseCheck,
void check_filter(const GraphInterface &g, Action a, ReverseCheck, class DirectedCheck>
void check_filter(GraphInterfaceType &g, Action a, ReverseCheck,
DirectedCheck, bool run_all = false) DirectedCheck, bool run_all = false)
{ {
typedef typename mpl::if_<is_const<GraphInterfaceType>,
const GraphInterface::multigraph_t,
GraphInterface::multigraph_t>::type multigraph_t;
bool found = false; bool found = false;
typedef RangeFilter<GraphInterface::vertex_filter_map_t> vertex_filter_t; typedef RangeFilter<GraphInterface::vertex_filter_map_t> vertex_filter_t;
...@@ -329,8 +374,7 @@ void check_filter(const GraphInterface &g, Action a, ReverseCheck, ...@@ -329,8 +374,7 @@ void check_filter(const GraphInterface &g, Action a, ReverseCheck,
if (g._vertex_filter_property != "" || g._edge_filter_property != "" || if (g._vertex_filter_property != "" || g._edge_filter_property != "" ||
run_all) run_all)
{ {
typedef filtered_graph<GraphInterface::multigraph_t, edge_filter_t, typedef filtered_graph<multigraph_t, edge_filter_t,vertex_filter_t> fg_t;
vertex_filter_t> fg_t;
static fg_t fg(g._mg, edge_filter_t(g._edge_filter_map, g._edge_range, static fg_t fg(g._mg, edge_filter_t(g._edge_filter_map, g._edge_range,
g._edge_range_include, g._edge_range_include,
g._edge_range_invert), g._edge_range_invert),
...@@ -345,13 +389,12 @@ void check_filter(const GraphInterface &g, Action a, ReverseCheck, ...@@ -345,13 +389,12 @@ void check_filter(const GraphInterface &g, Action a, ReverseCheck,
if (!found || run_all) if (!found || run_all)
{ {
mpl::for_each<DirectedCheck> mpl::for_each<DirectedCheck>
(check_directed<GraphInterface::multigraph_t,Action, (check_directed<multigraph_t,Action,ReverseCheck>
ReverseCheck>
(g._mg, a, g._reversed, g._directed, found, run_all)); (g._mg, a, g._reversed, g._directed, found, run_all));
} }
#else #else
mpl::for_each<DirectedCheck> mpl::for_each<DirectedCheck>
(check_directed<GraphInterface::multigraph_t,Action,ReverseCheck> (check_directed<multigraph_t,Action,ReverseCheck>
(g._mg, a, g._reversed, g._directed, found)); (g._mg, a, g._reversed, g._directed, found));
#endif #endif
if (!found) if (!found)
......
...@@ -146,7 +146,8 @@ template <class Descriptor> ...@@ -146,7 +146,8 @@ template <class Descriptor>
struct edit_property struct edit_property
{ {
template <class Graph> template <class Graph>
void operator()(GraphInterface& gi, const Graph& g, const dynamic_properties& dp, void operator()(GraphInterface& gi, const Graph& g,
const dynamic_properties& dp,
dynamic_property_map* prop_map, python::object& op) const dynamic_property_map* prop_map, python::object& op) const
{ {
put_properties(gi, g, Descriptor(), *prop_map, op); put_properties(gi, g, Descriptor(), *prop_map, op);
...@@ -158,6 +159,9 @@ struct edit_property ...@@ -158,6 +159,9 @@ struct edit_property
dynamic_property_map& prop_map, dynamic_property_map& prop_map,
python::object& operation) const python::object& operation) const
{ {
if (operation == python::object()) // don't set properties if op == None
return;
typename graph_traits<Graph>::vertex_iterator v,v_end; typename graph_traits<Graph>::vertex_iterator v,v_end;
for (tie(v, v_end) = vertices(g); v != v_end; ++v) for (tie(v, v_end) = vertices(g); v != v_end; ++v)
{ {
...@@ -174,6 +178,9 @@ struct edit_property ...@@ -174,6 +178,9 @@ struct edit_property
dynamic_property_map& prop_map, dynamic_property_map& prop_map,
python::object& operation) const python::object& operation) const
{ {
if (operation == python::object()) // don't set properties if op == None
return;
typename graph_traits<Graph>::edge_iterator e, e_end; typename graph_traits<Graph>::edge_iterator e, e_end;
for (tie(e, e_end) = edges(g); e != e_end; ++e) for (tie(e, e_end) = edges(g); e != e_end; ++e)
{ {
...@@ -329,8 +336,11 @@ void GraphInterface::EditGraphProperty(string property, string type, ...@@ -329,8 +336,11 @@ void GraphInterface::EditGraphProperty(string property, string type,
ConstantPropertyMap<size_t,graph_property_tag> > ConstantPropertyMap<size_t,graph_property_tag> >
(*this, _properties, graph_index, property, type, type_names, pmap)); (*this, _properties, graph_index, property, type, type_names, pmap));
python::object val = op(python::object(ref(*this))); if (op != python::object()) // don't set property if op == None
pmap->put(graph_property_tag(), val); {
python::object val = op(python::object(ref(*this)));
pmap->put(graph_property_tag(), val);
}
delete pmap; delete pmap;
} }
...@@ -354,47 +364,3 @@ private: ...@@ -354,47 +364,3 @@ private:
string& _name; string& _name;
}; };
void GraphInterface::ListProperties() const
{
list<tuple<string,string,string> > graph_properties, vertex_properties,
edge_properties;
for (typeof(_properties.begin()) p = _properties.begin();
p != _properties.end(); ++p)
{
tuple<string,string,string> prop;
get<0>(prop) = p->first;
mpl::for_each<value_types>
(get_type_name<value_types>(p->second->value(), type_names,
get<2>(prop)));
if (p->second->key() == typeid(vertex_t))
{
get<1>(prop) = "(vertex)";
vertex_properties.push_back(prop);
}
else
if (p->second->key() == typeid(edge_t))
{
get<1>(prop) = "(edge)";
edge_properties.push_back(prop);
}
else
{
get<1>(prop) = "(graph)";
graph_properties.push_back(prop);
}
}
list<tuple<string,string,string> > props;
props.insert(props.end(), graph_properties.begin(), graph_properties.end());
props.insert(props.end(), vertex_properties.begin(),
vertex_properties.end());
props.insert(props.end(), edge_properties.begin(), edge_properties.end());
for (typeof(props.begin()) iter = props.begin();
iter != props.end(); ++iter)
{
cout << setw(15) << left << get<0>(*iter) << " " << setw(8) << left
<< get<1>(*iter) << " type: " << get<2>(*iter) << endl;
}
}
...@@ -76,6 +76,195 @@ GraphInterface::Edges() const ...@@ -76,6 +76,195 @@ GraphInterface::Edges() const
return iter; return iter;