提问者:小点点

Boost A*投掷分割故障


这是我提出的关于提升图的另一个问题的延续。(GraphML in Boost)。成功阅读图表后,我正在尝试在一些随机开始和目标节点上应用 boost A*,但它的抛出分割错误。

以下是我的图表的细节。

using Graph = boost::adjacency_list<boost::setS, boost::vecS, boost::undirectedS, VertexProperties, EdgeProperties>;

struct VertexProperties {
    std::vector<double> joint_angles;
    VertexProperties() : joint_angles(3){}
    
};
struct EdgeProperties {
    double weight;
};

我使用 Boost 中的 A* 城市文件作为参考(A* 城市)来编码我的距离启发式和astar_goal_visitor。

struct found_goal {}; // exception for termination

// visitor that terminates when we find the goal
template <typename Vertex>
class astar_goal_visitor : public boost::default_astar_visitor
{
public:
  astar_goal_visitor(Vertex goal) : m_goal(goal) {}
  template <class Graph>
  void examine_vertex(Vertex u, Graph& g) {
    if(u == m_goal)
      throw found_goal();
  }
private:
  Vertex m_goal;
};

// euclidean distance heuristic
template <class Graph>
class distance_heuristic : public boost::astar_heuristic<typename Graph::Graph, double>
{
public:
  typedef typename boost::graph_traits<typename Graph::Graph>::vertex_descriptor Vertex;
  distance_heuristic(Vertex goal, Graph &graph)
    :  m_goal(goal), m_graph(graph) {}
  double operator()(Vertex u)
  {
    double dx = m_graph.getGraph()[m_goal].joint_angles[0] - m_graph.getGraph()[u].joint_angles[0];
    double dy = m_graph.getGraph()[m_goal].joint_angles[1] - m_graph.getGraph()[u].joint_angles[1];
    double dz = m_graph.getGraph()[m_goal].joint_angles[2] - m_graph.getGraph()[u].joint_angles[2];
    
    return ::sqrt(dx * dx + dy * dy + dz * dz);
  }
private:
  Graph m_graph;
  Vertex m_goal;
};

至于astar_search参数,前身映射定义如下。

typedef boost::property_map < Graph, boost::vertex_index_t >::type IndexMap;
typedef boost::iterator_property_map < Vertex*, IndexMap, Vertex, Vertex& > PredecessorMap;
BoostGraph::PredecessorMap BoostGraph::getPredecessorMap(){

    IndexMap indexMap = boost::get(boost::vertex_index, graph);
    std::vector<Vertex> p(boost::num_vertices(graph));
    PredecessorMap predecessorMap(&p[0], indexMap);

    return predecessorMap;
}

搜索的最终代码是

std::vector<double> d(boost::num_vertices(graph.getGraph()));

    std::mt19937 gen(time(0));
    BoostGraph::Vertex start = boost::random_vertex(graph.getGraph(), gen);
    BoostGraph::Vertex goal = boost::random_vertex(graph.getGraph(), gen);

    auto weightmap = boost::get(&EdgeProperties::weight, graph.getGraph());

    try {
    // call astar named parameter interface
    boost::astar_search
      (graph.getGraph(), start,
       distance_heuristic<BoostGraph>
        (goal, graph),
       boost::predecessor_map(graph.getPredecessorMap()).distance_map(boost::make_iterator_property_map(d.begin(), boost::get(boost::vertex_index, graph.getGraph()))).
       weight_map(weightmap).
       visitor(astar_goal_visitor<BoostGraph::Vertex>(goal)));
  
  
  } catch(found_goal fg) { // found a path to the goal
    std::list<BoostGraph::Vertex> shortest_path;
    for(BoostGraph::Vertex v = goal;; v = p[v]) {
      shortest_path.push_front(v);
      if(p[v] == v)
        break;
    }
  }

在下面定义了类BoostG想像的getG想像函数,其中FIG是类BoostG想像的受保护成员。

protected:
    Graph graph;

const BoostGraph::Graph& BoostGraph::getGraph() const{
    return graph;
}

分段错误出现在stl_tree.h中,我不知道哪里出错了。任何帮助都将不胜感激。谢谢


共1个答案

匿名用户

>

  • 您的启发式方法包含图形的副本。您正在使用属于不同图形的顶点描述符进行索引。

    您的前任映射是一个局部变量(vector),在< code>getPredecessorMap返回后,该映射是对它的悬空引用。只要让vector成为成员,然后< code>getPredecessorMap就可以消除了,因为它并没有真正增加多少。

    此外,您正在索引到< code>joint_angles中,而没有边界检查。首选<代码>。如果您想更安全,请在< code>[n]上方的(n)处。事实上,可以考虑使用< code>std::array

    总而言之,我的印象是你一直在试图隐藏类和成员函数中的复杂性,但它会导致代码变得碎片化并引发许多不必要的生命周期问题。

    还有一些代码没有显示。它们可能存在更多问题(例如,getGraph()至关重要)。

    以下是我的简化观点:

    科里鲁

    #include <boost/graph/adjacency_list.hpp>
    #include <boost/graph/astar_search.hpp>
    #include <boost/graph/random.hpp>
    
    using JointAngles = std::vector<double>;
    
    struct VertexProperties {
        JointAngles joint_angles{0, 0, 0};
    };
    
    struct EdgeProperties {
        double weight = 0;
    };
    
    using Graph  = boost::adjacency_list<boost::setS, boost::vecS, boost::undirectedS,
                                        VertexProperties, EdgeProperties>;
    using Vertex = Graph::vertex_descriptor;
    
    
    // visitor that terminates when we find the goal
    struct goal_visitor : boost::default_astar_visitor {
        struct found {}; // exception for termination
        Vertex m_goal;
    
        goal_visitor(Vertex g) : m_goal(g) {}
    
        template <class Graph> void examine_vertex(Vertex u, Graph&) {
            if (u == m_goal)
                throw found{};
        }
    };
    
    // euclidean distance heuristic
    struct distance_heuristic : boost::astar_heuristic<Graph, double> {
        distance_heuristic(Vertex goal, Graph& graph)
            : m_graph(graph)
            , m_goal(graph[goal].joint_angles) {}
    
        double operator()(Vertex u) const {
            auto& c = m_graph[u].joint_angles;
    
            auto                             //
                dx = m_goal.at(0) - c.at(0), //
                dy = m_goal.at(1) - c.at(1), //
                dz = m_goal.at(2) - c.at(2);
    
            using std::sqrt; // allow ADL, good practice
            return sqrt(dx * dx + dy * dy + dz * dz);
        }
    
      private:
        Graph&      m_graph; // reference!
        JointAngles m_goal;
    };
    
    #include <random>
    #include <fmt/ranges.h>
    int main() {
        Graph graph(4);
        graph[0] = VertexProperties{{0, 0, 0}};
        graph[1] = VertexProperties{{1, 1, 1}};
        graph[2] = VertexProperties{{2, 2, 2}};
        add_edge(0, 1, graph);
        add_edge(1, 2, graph);
    
        std::vector<Vertex> predecessors(num_vertices(graph));
        std::vector<double> distances(num_vertices(graph));
    
        auto index = get(boost::vertex_index, graph);
        auto pmap  = make_safe_iterator_property_map(predecessors.begin(), predecessors.size(), index);
        auto dmap  = make_safe_iterator_property_map(distances.begin(), distances.size(), index);
        auto weightmap = get(&EdgeProperties::weight, graph);
    
        std::mt19937 gen(std::random_device{}());
        Vertex       start = random_vertex(graph, gen);
        Vertex       goal  = random_vertex(graph, gen);
    
        try {
            // call astar named parameter interface
            astar_search( //
                graph, start, distance_heuristic{goal, graph},
                boost::predecessor_map(pmap) //
                    .distance_map(dmap)
                    .weight_map(weightmap)
                    .visitor(goal_visitor{goal}));
    
            fmt::print("{} -> {}: No path\n", start, goal);
        } catch (goal_visitor::found) {
            std::list<Vertex> path;
            for (auto cursor = goal;;) {
                path.push_front(cursor);
                auto previous = std::exchange(cursor, predecessors.at(cursor));
                if (cursor == previous)
                    break;
            }
    
            fmt::print("{} -> {}: {}\n", start, goal, path);
        }
    }
    

    哪些印刷品例如。

    2 -> 1: [2, 1]
    

    如果您想封装,请沿着功能边界进行,而不是人为的边界,因为它会让您一生都头疼,而不是您不需要的。如果性能无关紧要,您可以使用vector_property_map之类的工具来减少代码。例如:

    住在科里鲁

    #include <boost/graph/adjacency_list.hpp>
    #include <boost/graph/astar_search.hpp>
    #include <boost/graph/graph_utility.hpp>
    #include <boost/graph/random.hpp>
    #include <boost/property_map/transform_value_property_map.hpp>
    #include <boost/property_map/vector_property_map.hpp>
    #include <fmt/ranges.h>
    #include <random>
    
    class BoostGraph {
      private:
        using JointAngles = std::vector<double>;
    
        struct VertexProperties {
            JointAngles joint_angles{0, 0, 0};
        };
    
        struct EdgeProperties {
            double weight = 0;
        };
    
        using Graph  = boost::adjacency_list<boost::setS, boost::vecS, boost::undirectedS,
                                            VertexProperties, EdgeProperties>;
        using Vertex = Graph::vertex_descriptor;
    
      public:
        BoostGraph() : m_graph(4) {
            // TODO read graph
            m_graph[0] = VertexProperties{{0, 0, 0}};
            m_graph[1] = VertexProperties{{1, 1, 1}};
            m_graph[2] = VertexProperties{{2, 2, 2}};
            add_edge(0, 1, m_graph);
            add_edge(1, 2, m_graph);
        }
    
        friend std::ostream& operator<<(std::ostream& os, BoostGraph const& bg) {
            auto name = boost::make_transform_value_property_map(
                [ja = get(&VertexProperties::joint_angles, bg.m_graph)](Vertex v) {
                    return fmt::format("Vertex #{} ({})", v, ja[v]);
                },
                get(boost::vertex_index, bg.m_graph));
    
            print_graph(bg.m_graph, name, os);
            return os;
        }
    
        Vertex random_vertex() { return boost::random_vertex(m_graph, m_prng); }
    
        std::list<Vertex> find_path(Vertex start, Vertex goal) const {
            std::list<Vertex> path;
            auto pmap = make_vector_property_map<Vertex>(get(boost::vertex_index, m_graph));
    
            try {
                astar_search( //
                    m_graph, start, distance_heuristic{goal, m_graph},
                    boost::predecessor_map(pmap) //
                        .weight_map(get(&EdgeProperties::weight, m_graph))
                        .visitor(finder{goal}));
            } catch (finder::found) {
                for (auto cursor = goal;;) {
                    path.push_front(cursor);
                    auto previous = std::exchange(cursor, pmap[cursor]);
                    if (cursor == previous)
                        break;
                }
            }
            return path;
        }
    
      private:
        // visitor that terminates when we find the goal
        struct finder : boost::default_astar_visitor {
            struct found {}; // exception for termination
            Vertex m_goal;
    
            finder(Vertex g) : m_goal(g) {}
    
            void examine_vertex(Vertex u, Graph const&) const {
                if (u == m_goal)
                    throw found{};
            }
        };
    
        // euclidean distance heuristic
        struct distance_heuristic : boost::astar_heuristic<Graph, double> {
            distance_heuristic(Vertex goal, Graph const& graph)
                : m_graph(graph)
                , m_goal(graph[goal].joint_angles) {}
    
            double operator()(Vertex u) const {
                auto& c = m_graph[u].joint_angles;
    
                auto                             //
                    dx = m_goal.at(0) - c.at(0), //
                    dy = m_goal.at(1) - c.at(1), //
                    dz = m_goal.at(2) - c.at(2);
    
                using std::sqrt; // allow ADL, good practice
                return sqrt(dx * dx + dy * dy + dz * dz);
            }
    
          private:
            Graph const& m_graph; // reference!
            JointAngles  m_goal;
        };
    
        Graph        m_graph;
        std::mt19937 m_prng{std::random_device{}()};
    };
    
    int main() {
        BoostGraph bg;
    
        std::cout << "Graph: " << bg << "\n";
    
        for (auto i = 0; i < 10; ++i) {
            auto start = bg.random_vertex(), goal = bg.random_vertex();
            auto path = bg.find_path(start, goal);
    
            fmt::print("{} -> {}: {}\n", start, goal, path);
        }
    }
    

    打印,例如

    Graph: Vertex #0 ([0, 0, 0]) <--> Vertex #1 ([1, 1, 1]) 
    Vertex #1 ([1, 1, 1]) <--> Vertex #0 ([0, 0, 0]) Vertex #2 ([2, 2, 2]) 
    Vertex #2 ([2, 2, 2]) <--> Vertex #1 ([1, 1, 1]) 
    Vertex #3 ([0, 0, 0]) <--> 
    
    2 -> 2: [2]
    1 -> 0: [1, 0]
    0 -> 1: [0, 1]
    2 -> 0: [2, 1, 0]
    3 -> 0: []
    0 -> 3: []
    0 -> 3: []
    1 -> 0: [1, 0]
    1 -> 0: [1, 0]
    3 -> 1: []