def generate_graph(output_name, module_name, node_ids, edges): with open(output_name, "w") as out: out.write(""" #include #include #include #include #include #include #include #include using namespace boost; // create a typedef for the Graph type typedef adjacency_list< vecS, vecS, undirectedS, no_property, property< edge_weight_t, int > > graph_t; typedef graph_traits< graph_t >::vertex_descriptor vertex_descriptor; typedef std::pair< int, int > Edge; int getIndex(std::vector, std::string); graph_t buildGraph(); """) out.write(f"const int num_nodes = {len(node_ids)};\n\n") out.write("enum nodes {\n") for node_id in node_ids: out.write(f" {node_id},\n") out.write("};\n\n") out.write('std::string _name[] = {') for node_id in node_ids: if node_id != node_ids[-1]: out.write(f'"{str(node_id)}",') else: out.write(f'"{str(node_id)}"') out.write('};\n') out.write("std::vector name(_name, _name + sizeof(_name)/sizeof(std::string));\n\n") out.write("Edge edge_array[] = {\n") for edge in edges: if edge != edges[-1]: out.write(f" Edge({edge.start_id}, {edge.end_id}),\n") else: out.write(f" Edge({edge.start_id}, {edge.end_id})\n") out.write("};\n\n") out.write("float weights[] = {") for edge in edges: if edge != edges[-1]: out.write(f"{edge.distance}, ") else: out.write(f"{edge.distance}") out.write("};\n") out.write(""" std::string get_route(std::string start, std::string end) { graph_t graph = buildGraph(); property_map< graph_t, edge_weight_t >::type weightmap = get(edge_weight, graph); std::vector< vertex_descriptor > p(num_vertices(graph)); std::vector< int > d(num_vertices(graph)); int pos_start = getIndex(name, start); int pos_end = getIndex(name, end); if (pos_start == -1) { std::string msg("Invalid id (not found) for start position"); throw std::invalid_argument(msg); } else if (pos_end == -1) { std::string msg("Invalid id (not found) for end position"); throw std::invalid_argument(msg); } vertex_descriptor s = vertex(nodes(pos_start), graph); vertex_descriptor e = vertex(nodes(pos_end), graph); dijkstra_shortest_paths(graph, s, predecessor_map(boost::make_iterator_property_map( p.begin(), get(boost::vertex_index, graph))) .distance_map(boost::make_iterator_property_map( d.begin(), get(boost::vertex_index, graph)))); //find path from start to end vertex std::list pathVertices; int distance = d[e]; while (e != s) { pathVertices.push_front(e); if(name[e] == name[p[e]]) // see https://stackoverflow.com/questions/48367649/boost-dijkstra-shortest-paths-cant-extract-or-find-the-path-path-contains break; e = p[e]; } pathVertices.push_front(s); // add starting point to path std::string path; for (vertex_descriptor n : pathVertices) { path += name[n]; path += " "; } path += ":"; path += std::to_string(distance); return path; } graph_t buildGraph() { int num_arcs = sizeof(edge_array) / sizeof(Edge); graph_t g(edge_array, edge_array + num_arcs, weights, num_nodes); return g; } int getIndex(std::vector v, std::string element) { auto it = find(v.begin(), v.end(), element); // If element was found if (it != v.end()) { // calculating the index // of element int index = it - v.begin(); //std::cout << index << std::endl; return index; } else { // If the element is not // present in the vector return -1; } } """) out.write(f"BOOST_PYTHON_MODULE({module_name}) // module name must match the name of the .so compiled") out.write(""" { using namespace boost::python; def("get_route", get_route); } """)