graph-v2 icon indicating copy to clipboard operation
graph-v2 copied to clipboard

A breaking and uncomfortable change in the descriptor rewrite

Open akrzemi1 opened this issue 5 months ago • 0 comments

I have a situation when testing the descriptor implementation in branch desc4. The definition of the CPO find_vertex changed significantly, to the extent that my graph representation has the CPO find_vertex valid in branch master, but no longer so on branch desc4.

This is my graph:

namespace MyLibrary 
{

struct MyEdge
{
  std::string content;
  int indexOfTarget;
  
  int target_id(auto&&) const { return indexOfTarget; }
};

struct MyVertex
{
  std::string content;
  std::vector<MyEdge> outEdges;
  
  std::vector<MyEdge> const& edges(auto&&) const { return outEdges; }
};

class MyGraph 
{
  std::vector<MyVertex> _vertices;
  
public:
  std::vector<MyVertex> const& vertices() const { return _vertices; }
};

std::vector<MyEdge> const& edges(MyGraph const& g, int uid) { return g.vertices()[uid].edges(g); }
}

I never had to define find_vertex, because in master there was an if constexpr in the CPO that checked random_access_iterator<vertex_iterator_t<_G>>. In desc4 this has been replaced with a different condition that no longer holds for my graph: random_access_range<_G>. See https://github.com/stdgraph/graph-v2/blob/desc4/include/graph/detail/graph_cpo.hpp#L553.

Is there some fundamental reason why my graph cannot get a default customization for vertex_value or is it ust an oversight?

Interestingly, my graph above models graph::index_adjacency_list, and I can use it with graph::dijkstra_shortest_paths in the simplest cases. Apparently find_vertex is not part of the concept. But the moment I start using a visitor, an if constexpr branch triggers that calls find_vertex and my program no longer compiles. A full example follows.

#include <graph/graph.hpp>
#include <vector>
#include <iostream>
#include <cassert>
#include <graph/algorithm/dijkstra_shortest_paths.hpp>

namespace MyLibrary 
{

struct MyEdge
{
  std::string content;
  int indexOfTarget;
  
  int target_id(auto&&) const { return indexOfTarget; }
};

struct MyVertex
{
  std::string content;
  std::vector<MyEdge> outEdges;
  
  std::vector<MyEdge> const& edges(auto&&) const { return outEdges; }
};

class MyGraph 
{
  std::vector<MyVertex> _vertices;
  
public:
  std::vector<MyVertex> const& vertices() const { return _vertices; }
};

std::vector<MyEdge> const& edges(MyGraph const& g, int uid) { return g.vertices()[uid].edges(g); }
}

class ShowProgress
{
  using G = MyLibrary::MyGraph;
  using VD = graph::vertex_info<graph::vertex_id_t<G>, graph::vertex_reference_t<G>, void>;    
  int vertex_count = 0;

public:   
  void on_discover_vertex(VD const& v)
  {
    if (vertex_count % 3 == 0)
      std::cout << "processing vertex " << v.id << "\n";
    ++vertex_count;
  }
};

auto weight = [](std::tuple<int, double> const& uv) {
  return std::get<1>(uv);
}; 

int main()
{
  std::vector<int> predecessors;
  std::vector<double> distances;
  
  MyLibrary::MyGraph g;

  static_assert(graph::index_adjacency_list<MyLibrary::MyGraph>);
  graph::dijkstra_shortest_paths(g, 0, distances, predecessors, weight, ShowProgress{});
  auto && vtcs = graph::vertices(g);
  

  auto vit = std::ranges::begin(vtcs);
  int id0 = graph::vertex_id(g, *vit);

  assert(id0 == 0);
  auto && edgs = graph::edges(g, *vit);

  auto eit = std::ranges::begin(edgs);
  int id1 = graph::target_id(g, *eit);

  assert(id1 == 1);

  auto wit = graph::find_vertex(g, id1);
  int id1_ = graph::vertex_id(g, *wit);
  assert(id1_ == 1);
}

akrzemi1 avatar Jul 14 '25 23:07 akrzemi1