routing-lisbon/generator.py

171 lines
4.9 KiB
Python

def generate_graph(output_name, module_name, node_ids, edges):
with open(output_name, "w") as out:
out.write("""
#include <boost/config.hpp>
#include <boost/python.hpp>
#include <iostream>
#include <fstream>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/property_map/property_map.hpp>
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>, 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<std::string> 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<vertex_descriptor> 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<std::string> 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);
}
""")