Boost :: dynamic_properties and immutable graph object

after implementing some algorithm using BGL, im trying to provide io functions using GraphML. However, I am unable to compile a suitable <<operator that takes a constant reference.

Here's an example:

// use bundled properties for vertices and edges
struct VertexProperty
{
   double error;
};

typedef boost::adjacency_list< boost::setS, boost::setS, boost::undirectedS, VertexProperty> Graph;

typedef typename boost::graph_traits<Graph>::edge_descriptor edge_descriptor;
typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;

std::ostream& operator<<(std::ostream& os, const Graph& graph)
{
    typedef std::map<vertex_descriptor, std::size_t> IndexMap;
    IndexMap index_map;
    boost::associative_property_map<IndexMap> index_properties(index_map);

    std::size_t i = 0;
    for (const vertex_descriptor& v : boost::make_iterator_range(boost::vertices(graph)))
        index_properties[v] = i++;

    boost::dynamic_properties dp;
    typename boost::property_map<Graph, double VertexProperty::*>::const_type error_map = get(&VertexProperty::error, graph);

    dp.property("error", error_map);

    boost::write_graphml(os, graph,index_properties,dp);

    return os;
}

int main()
{
  Graph g;
  std::cout << g <<std::endl;
}

      

Fail compilation:

boost / property_map / property_map.hpp: 309: 44: error: read-only assignment "(& ((const boost :: adj_list_vertex_property_map, double, const double &, double VertexProperty :: *> &) pa)) → boost :: adj_list_vertex_property_map :: operator [], double, const double &, double VertexProperty :: *> () "static_cast (pa) [k] = v;

As far as I understood the dynamic_properties documentation, these read-only checks have to be done at runtime (isn't this one of the goals of erasing the entire type). And of course they must fail if they try to change the immutable property. But the call to wirte write_graphml () takes a ref constant for dynamic properties and shouldn't change anything.

To ask question (s):

  • Why doesn't compilation work?
  • And how do I do it right?
  • Using a different property_map (Yes / No / Which)?

For an example (not) working @ coliru.stacked-crooked.com: See it here!

Regards, Marti

+3


source to share


1 answer


The real problem is that the vertex property display category is inferred as LvaluePropertyMap

(what it is).

However, the concept of LvaluePropertyMap

promises must be a superset of ReadablePropertyMap

and WritablePropertyMap

. This creates problems when using const_type

chart properties: they are lvalues, but they are not writable.

The only working solution I came across was to wrap the property map type to override the category:

namespace detail {
    template <typename Map>
        struct readable_only_pmap : Map {
            readable_only_pmap(Map map) : Map(map) { }

            // overrule the category tag
            typedef boost::readable_property_map_tag category;
        };
}

      

Now you can use it like this:

using pmap_t = typename boost::property_map<Graph, double VertexProperty::*>::const_type;
detail::readable_only_pmap<pmap_t> error_map = get(&VertexProperty::error, graph);

      



While it is pretty much the same, now dynamic_properties::property

detects that the map is read-only and does not try to generate flagged helpers (instead, if attempted put

) an exception will be thrown.

Full code with demo graph:

Live On Coliru

#include <iostream>
#include <string>
#include <vector>
#include <functional>

#include <iostream>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphml.hpp>
// #include <Eigen/Core>

// use bundled properties for vertices and edges
struct VertexProperty
{
    double error;
    // Eigen::Matrix<real,dim,1> location;
};

typedef boost::adjacency_list< boost::setS, boost::setS, boost::undirectedS, VertexProperty> Graph;

typedef typename boost::graph_traits<Graph>::edge_descriptor edge_descriptor;
typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;

namespace detail {
    template <typename Map>
        struct readable_only_pmap : Map {
            readable_only_pmap(Map map) : Map(map) { }

            // overrule the category tag
            typedef boost::readable_property_map_tag category;
        };
}

std::ostream& operator<<(std::ostream& os, const Graph& graph)
{
    typedef std::map<vertex_descriptor, std::size_t> IndexMap;
    IndexMap index_map;
    boost::associative_property_map<IndexMap> index_properties(index_map);

    std::size_t i = 0;
    for (const vertex_descriptor& v : boost::make_iterator_range(boost::vertices(graph)))
        index_properties[v] = i++;

    using pmap_t = typename boost::property_map<Graph, double VertexProperty::*>::const_type;
    detail::readable_only_pmap<pmap_t> error_map = get(&VertexProperty::error, graph);

    boost::dynamic_properties dp;
    dp.property("error", error_map);
    boost::write_graphml(os, graph, index_properties, dp);

    return os;
}

int main()
{
  Graph g;
  auto v1 = boost::add_vertex(VertexProperty{0.1}, g);
  auto v2 = boost::add_vertex(VertexProperty{0.2}, g);
  auto v3 = boost::add_vertex(VertexProperty{0.3}, g);
  auto v4 = boost::add_vertex(VertexProperty{0.4}, g);
  auto v5 = boost::add_vertex(VertexProperty{0.5}, g);

  add_edge(v1,v2,g);
  add_edge(v5,v2,g);
  add_edge(v4,v2,g);
  add_edge(v2,v3,g);
  add_edge(v3,v4,g);
  add_edge(v4,v1,g);

  std::cout << g <<std::endl;
}

      

Output: (slightly reformatted)

<?xml version="1.0" encoding="UTF-8"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
<key id="key0" for="node" attr.name="error" attr.type="double" />
<graph id="G" edgedefault="undirected" parse.nodeids="free" parse.edgeids="canonical" parse.order="nodesfirst">
    <node id="n0"> <data key="key0">0.1</data> </node>
    <node id="n1"> <data key="key0">0.2</data> </node>
    <node id="n2"> <data key="key0">0.3</data> </node>
    <node id="n3"> <data key="key0">0.4</data> </node>
    <node id="n4"> <data key="key0">0.5</data> </node>
    <edge id="e0" source="n0" target="n1"> </edge>
    <edge id="e1" source="n4" target="n1"> </edge>
    <edge id="e2" source="n3" target="n1"> </edge>
    <edge id="e3" source="n1" target="n2"> </edge>
    <edge id="e4" source="n2" target="n3"> </edge>
    <edge id="e5" source="n3" target="n0"> </edge>
</graph>
</graphml>

      

+6


source







All Articles