Remove all boundary nodes and use simple u-v-stragtegy to pick id
This commit removes all occurences of unconnected boundary nodes and switches to the simple heuristic of picking U for the forward and V for the backward node. This performs better than several fancy heuristics.
This commit is contained in:
parent
bf6698f4cc
commit
57c6c6e51c
@ -10,10 +10,12 @@
|
||||
#include "extractor/guidance/turn_analysis.hpp"
|
||||
#include "extractor/guidance/turn_instruction.hpp"
|
||||
#include "extractor/guidance/turn_lane_types.hpp"
|
||||
#include "extractor/nbg_to_ebg.hpp"
|
||||
#include "extractor/original_edge_data.hpp"
|
||||
#include "extractor/profile_properties.hpp"
|
||||
#include "extractor/query_node.hpp"
|
||||
#include "extractor/restriction_map.hpp"
|
||||
|
||||
#include "util/deallocating_vector.hpp"
|
||||
#include "util/guidance/bearing_class.hpp"
|
||||
#include "util/guidance/entry_class.hpp"
|
||||
@ -35,7 +37,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
@ -144,7 +145,7 @@ class EdgeBasedGraphFactory
|
||||
|
||||
unsigned RenumberEdges();
|
||||
|
||||
void GenerateEdgeExpandedNodes(const std::string &nbg_ebg_mapping_path);
|
||||
std::vector<NBGToEBG> GenerateEdgeExpandedNodes();
|
||||
|
||||
void GenerateEdgeExpandedEdges(ScriptingEnvironment &scripting_environment,
|
||||
const std::string &original_edge_data_filename,
|
||||
@ -153,15 +154,7 @@ class EdgeBasedGraphFactory
|
||||
const std::string &turn_duration_penalties_filename,
|
||||
const std::string &turn_penalties_index_filename);
|
||||
|
||||
// Mapping betweenn the node based graph u,v nodes and the edge based graph head,tail edge ids.
|
||||
// Required in the osrm-partition tool to translate from a nbg partition to a ebg partition.
|
||||
struct Mapping
|
||||
{
|
||||
NodeID u, v;
|
||||
EdgeID head, tail;
|
||||
};
|
||||
|
||||
boost::optional<Mapping> InsertEdgeBasedNode(const NodeID u, const NodeID v);
|
||||
NBGToEBG InsertEdgeBasedNode(const NodeID u, const NodeID v);
|
||||
|
||||
void FlushVectorToStream(storage::io::FileWriter &edge_data_file,
|
||||
std::vector<OriginalEdgeData> &original_edge_data_vector) const;
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define OSRM_EXTRACTOR_IO_HPP
|
||||
|
||||
#include "extractor/datasources.hpp"
|
||||
#include "extractor/nbg_to_ebg.hpp"
|
||||
#include "extractor/segment_data_container.hpp"
|
||||
|
||||
#include "storage/io.hpp"
|
||||
@ -15,7 +16,23 @@ namespace extractor
|
||||
namespace io
|
||||
{
|
||||
|
||||
void read(const boost::filesystem::path &path, Datasources &sources)
|
||||
inline void read(const boost::filesystem::path &path, std::vector<NBGToEBG> &mapping)
|
||||
{
|
||||
const auto fingerprint = storage::io::FileReader::VerifyFingerprint;
|
||||
storage::io::FileReader reader{path, fingerprint};
|
||||
|
||||
reader.DeserializeVector(mapping);
|
||||
}
|
||||
|
||||
inline void write(const boost::filesystem::path &path, const std::vector<NBGToEBG> &mapping)
|
||||
{
|
||||
const auto fingerprint = storage::io::FileWriter::GenerateFingerprint;
|
||||
storage::io::FileWriter reader{path, fingerprint};
|
||||
|
||||
reader.SerializeVector(mapping);
|
||||
}
|
||||
|
||||
inline void read(const boost::filesystem::path &path, Datasources &sources)
|
||||
{
|
||||
const auto fingerprint = storage::io::FileReader::HasNoFingerprint;
|
||||
storage::io::FileReader reader{path, fingerprint};
|
||||
@ -23,7 +40,7 @@ void read(const boost::filesystem::path &path, Datasources &sources)
|
||||
reader.ReadInto(sources);
|
||||
}
|
||||
|
||||
void write(const boost::filesystem::path &path, Datasources &sources)
|
||||
inline void write(const boost::filesystem::path &path, Datasources &sources)
|
||||
{
|
||||
const auto fingerprint = storage::io::FileWriter::HasNoFingerprint;
|
||||
storage::io::FileWriter writer{path, fingerprint};
|
||||
@ -31,7 +48,8 @@ void write(const boost::filesystem::path &path, Datasources &sources)
|
||||
writer.WriteFrom(sources);
|
||||
}
|
||||
|
||||
template <> void read(const boost::filesystem::path &path, SegmentDataContainer &segment_data)
|
||||
template <>
|
||||
inline void read(const boost::filesystem::path &path, SegmentDataContainer &segment_data)
|
||||
{
|
||||
const auto fingerprint = storage::io::FileReader::HasNoFingerprint;
|
||||
storage::io::FileReader reader{path, fingerprint};
|
||||
@ -57,7 +75,7 @@ template <> void read(const boost::filesystem::path &path, SegmentDataContainer
|
||||
}
|
||||
|
||||
template <>
|
||||
void write(const boost::filesystem::path &path, const SegmentDataContainer &segment_data)
|
||||
inline void write(const boost::filesystem::path &path, const SegmentDataContainer &segment_data)
|
||||
{
|
||||
const auto fingerprint = storage::io::FileWriter::HasNoFingerprint;
|
||||
storage::io::FileWriter writer{path, fingerprint};
|
||||
|
21
include/extractor/nbg_to_ebg.hpp
Normal file
21
include/extractor/nbg_to_ebg.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef OSRM_EXTRACTOR_NBG_TO_EBG_HPP
|
||||
#define OSRM_EXTRACTOR_NBG_TO_EBG_HPP
|
||||
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
// Mapping betweenn the node based graph u,v nodes and the edge based graph head,tail edge ids.
|
||||
// Required in the osrm-partition tool to translate from a nbg partition to a ebg partition.
|
||||
struct NBGToEBG
|
||||
{
|
||||
NodeID u, v;
|
||||
NodeID forward_ebg_node, backward_ebg_node;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -1,63 +0,0 @@
|
||||
#ifndef NODE_BASED_GRAPH_TO_EDGE_BASED_GRAPH_MAPPING_WRITER_HPP
|
||||
#define NODE_BASED_GRAPH_TO_EDGE_BASED_GRAPH_MAPPING_WRITER_HPP
|
||||
|
||||
#include "storage/io.hpp"
|
||||
#include "util/log.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
// Writes: | Fingerprint | #mappings | u v fwd_node bkw_node | u v fwd_node bkw_node | ..
|
||||
// - uint64: number of mappings (u, v, fwd_node bkw_node) chunks
|
||||
// - NodeID u, NodeID v, EdgeID fwd_node, EdgeID bkw_node
|
||||
|
||||
struct NodeBasedGraphToEdgeBasedGraphMappingWriter
|
||||
{
|
||||
NodeBasedGraphToEdgeBasedGraphMappingWriter(const std::string &path)
|
||||
: writer{path, storage::io::FileWriter::GenerateFingerprint}, num_written{0}
|
||||
{
|
||||
const std::uint64_t dummy{0}; // filled in later
|
||||
writer.WriteElementCount64(dummy);
|
||||
}
|
||||
|
||||
void WriteMapping(NodeID u, NodeID v, EdgeID fwd_ebg_node, EdgeID bkw_ebg_node)
|
||||
{
|
||||
BOOST_ASSERT(u != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(v != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(fwd_ebg_node != SPECIAL_EDGEID || bkw_ebg_node != SPECIAL_EDGEID);
|
||||
|
||||
writer.WriteOne(u);
|
||||
writer.WriteOne(v);
|
||||
writer.WriteOne(fwd_ebg_node);
|
||||
writer.WriteOne(bkw_ebg_node);
|
||||
|
||||
num_written += 1;
|
||||
}
|
||||
|
||||
~NodeBasedGraphToEdgeBasedGraphMappingWriter()
|
||||
{
|
||||
if (num_written != 0)
|
||||
{
|
||||
writer.SkipToBeginning();
|
||||
writer.WriteOne(num_written);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
storage::io::FileWriter writer;
|
||||
std::uint64_t num_written;
|
||||
};
|
||||
|
||||
} // ns extractor
|
||||
} // ns osrm
|
||||
|
||||
#endif // NODE_BASED_GRAPH_TO_EDGE_BASED_GRAPH_MAPPING_WRITER_HPP
|
@ -240,6 +240,8 @@ template <bool UseShareMemory> class CellStorageImpl
|
||||
if (!is_source_node && !is_destination_node)
|
||||
{
|
||||
number_of_unconneced++;
|
||||
util::Log(logWARNING) << "Found unconnected boundary node " << node << "("
|
||||
<< cell_id << ") on level " << (int)level;
|
||||
level_destination_boundary.emplace_back(cell_id, node);
|
||||
}
|
||||
}
|
||||
|
@ -1,80 +0,0 @@
|
||||
#ifndef OSRM_NODE_BASED_GRAPH_TO_EDGE_BASED_GRAPH_MAPPING_READER_HPP
|
||||
#define OSRM_NODE_BASED_GRAPH_TO_EDGE_BASED_GRAPH_MAPPING_READER_HPP
|
||||
|
||||
#include "storage/io.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <iterator>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace partition
|
||||
{
|
||||
|
||||
struct NodeBasedGraphToEdgeBasedGraphMapping
|
||||
{
|
||||
NodeBasedGraphToEdgeBasedGraphMapping(storage::io::FileReader &reader)
|
||||
{
|
||||
// Reads: | Fingerprint | #mappings | u v fwd_node bkw_node | u v fwd_node bkw_node | ..
|
||||
// - uint64: number of mappings (u, v, fwd_node, bkw_node) chunks
|
||||
// - NodeID u, NodeID v, EdgeID fwd_node, EdgeID bkw_node
|
||||
//
|
||||
// Gets written in NodeBasedGraphToEdgeBasedGraphMappingWriter
|
||||
|
||||
const auto num_mappings = reader.ReadElementCount64();
|
||||
|
||||
edge_based_node_to_node_based_nodes.reserve(num_mappings * 2);
|
||||
|
||||
for (std::uint64_t i{0}; i < num_mappings; ++i)
|
||||
{
|
||||
|
||||
const auto u = reader.ReadOne<NodeID>(); // node based graph `from` node
|
||||
const auto v = reader.ReadOne<NodeID>(); // node based graph `to` node
|
||||
const auto fwd_ebg_node = reader.ReadOne<EdgeID>(); // edge based graph forward node
|
||||
const auto bkw_ebg_node = reader.ReadOne<EdgeID>(); // edge based graph backward node
|
||||
|
||||
edge_based_node_to_node_based_nodes.insert({fwd_ebg_node, {u, v}});
|
||||
edge_based_node_to_node_based_nodes.insert({bkw_ebg_node, {v, u}});
|
||||
}
|
||||
}
|
||||
|
||||
struct NodeBasedNodes
|
||||
{
|
||||
NodeID u, v;
|
||||
};
|
||||
|
||||
NodeBasedNodes Lookup(EdgeID edge_based_node) const
|
||||
{
|
||||
auto it = edge_based_node_to_node_based_nodes.find(edge_based_node);
|
||||
|
||||
if (it != end(edge_based_node_to_node_based_nodes))
|
||||
return it->second;
|
||||
|
||||
BOOST_ASSERT_MSG(false, "unable to fine edge based node, graph <-> mapping out of sync");
|
||||
return NodeBasedNodes{SPECIAL_NODEID, SPECIAL_NODEID};
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<EdgeID, NodeBasedNodes> edge_based_node_to_node_based_nodes;
|
||||
};
|
||||
|
||||
inline NodeBasedGraphToEdgeBasedGraphMapping
|
||||
LoadNodeBasedGraphToEdgeBasedGraphMapping(const std::string &path)
|
||||
{
|
||||
const auto fingerprint = storage::io::FileReader::VerifyFingerprint;
|
||||
storage::io::FileReader reader(path, fingerprint);
|
||||
|
||||
NodeBasedGraphToEdgeBasedGraphMapping mapping{reader};
|
||||
return mapping;
|
||||
}
|
||||
|
||||
} // ns partition
|
||||
} // ns osrm
|
||||
|
||||
#endif
|
115
include/partition/remove_unconnected.hpp
Normal file
115
include/partition/remove_unconnected.hpp
Normal file
@ -0,0 +1,115 @@
|
||||
#ifndef OSRM_PARTITION_REMOVE_UNCONNECTED_HPP
|
||||
#define OSRM_PARTITION_REMOVE_UNCONNECTED_HPP
|
||||
|
||||
#include "util/log.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace partition
|
||||
{
|
||||
using Partition = std::vector<CellID>;
|
||||
|
||||
template <typename GraphT>
|
||||
std::size_t removeUnconnectedBoundaryNodes(const GraphT &edge_based_graph,
|
||||
std::vector<Partition> &partitions)
|
||||
{
|
||||
auto num_unconnected = 0;
|
||||
auto could_not_fix = 0;
|
||||
for (int level_index = partitions.size() - 1; level_index >= 0; level_index--)
|
||||
{
|
||||
struct Witness
|
||||
{
|
||||
NodeID id;
|
||||
std::size_t induced_border_edges;
|
||||
};
|
||||
std::vector<Witness> witnesses;
|
||||
for (NodeID node = 0; node < edge_based_graph.GetNumberOfNodes(); ++node)
|
||||
{
|
||||
witnesses.clear();
|
||||
|
||||
bool is_source = false;
|
||||
bool is_target = false;
|
||||
|
||||
const auto cell_id = partitions[level_index][node];
|
||||
for (auto edge : edge_based_graph.GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const auto data = edge_based_graph.GetEdgeData(edge);
|
||||
const auto target = edge_based_graph.GetTarget(edge);
|
||||
const auto target_cell_id = partitions[level_index][target];
|
||||
if (target_cell_id == cell_id)
|
||||
{
|
||||
is_source |= data.forward;
|
||||
is_target |= data.backward;
|
||||
}
|
||||
else
|
||||
{
|
||||
witnesses.push_back({target, 0});
|
||||
}
|
||||
}
|
||||
|
||||
const auto unconnected = witnesses.size() > 0 && !is_source && !is_target;
|
||||
|
||||
if (unconnected)
|
||||
{
|
||||
num_unconnected++;
|
||||
|
||||
if (level_index < static_cast<int>(partitions.size() - 1))
|
||||
{
|
||||
auto new_end = std::remove_if(
|
||||
witnesses.begin(), witnesses.end(), [&](const auto &witness) {
|
||||
return partitions[level_index + 1][node] !=
|
||||
partitions[level_index + 1][witness.id];
|
||||
});
|
||||
witnesses.resize(new_end - witnesses.begin());
|
||||
}
|
||||
if (witnesses.size() == 0)
|
||||
{
|
||||
could_not_fix++;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto &witness : witnesses)
|
||||
{
|
||||
for (auto edge : edge_based_graph.GetAdjacentEdgeRange(node))
|
||||
{
|
||||
auto target = edge_based_graph.GetTarget(edge);
|
||||
for (auto sublevel_index = level_index; sublevel_index >= 0;
|
||||
--sublevel_index)
|
||||
{
|
||||
if (partitions[sublevel_index][target] !=
|
||||
partitions[sublevel_index][witness.id])
|
||||
witness.induced_border_edges++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto best_witness = std::min_element(
|
||||
witnesses.begin(), witnesses.end(), [](const auto &lhs, const auto &rhs) {
|
||||
return lhs.induced_border_edges < rhs.induced_border_edges;
|
||||
});
|
||||
BOOST_ASSERT(best_witness != witnesses.end());
|
||||
|
||||
// assign `node` to same subcells as `best_witness`
|
||||
for (auto sublevel_index = level_index; sublevel_index >= 0; --sublevel_index)
|
||||
{
|
||||
partitions[sublevel_index][node] = partitions[sublevel_index][best_witness->id];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (could_not_fix > 0)
|
||||
util::Log(logWARNING) << "Could not fix " << could_not_fix << " unconnected boundary nodes";
|
||||
|
||||
return num_unconnected;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -2,7 +2,7 @@
|
||||
#include "extractor/edge_based_edge.hpp"
|
||||
#include "extractor/guidance/turn_analysis.hpp"
|
||||
#include "extractor/guidance/turn_lane_handler.hpp"
|
||||
#include "extractor/node_based_graph_to_edge_based_graph_mapping_writer.hpp"
|
||||
#include "extractor/io.hpp"
|
||||
#include "extractor/scripting_environment.hpp"
|
||||
#include "extractor/suffix_table.hpp"
|
||||
|
||||
@ -94,8 +94,7 @@ void EdgeBasedGraphFactory::GetEdgeBasedNodeWeights(std::vector<EdgeWeight> &out
|
||||
|
||||
EdgeID EdgeBasedGraphFactory::GetHighestEdgeID() { return m_max_edge_id; }
|
||||
|
||||
boost::optional<EdgeBasedGraphFactory::Mapping>
|
||||
EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const NodeID node_v)
|
||||
NBGToEBG EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const NodeID node_v)
|
||||
{
|
||||
// merge edges together into one EdgeBasedNode
|
||||
BOOST_ASSERT(node_u != SPECIAL_NODEID);
|
||||
@ -113,10 +112,7 @@ EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const NodeID nod
|
||||
|
||||
const EdgeData &reverse_data = m_node_based_graph->GetEdgeData(edge_id_2);
|
||||
|
||||
if (forward_data.edge_id == SPECIAL_NODEID && reverse_data.edge_id == SPECIAL_NODEID)
|
||||
{
|
||||
return boost::none;
|
||||
}
|
||||
BOOST_ASSERT(forward_data.edge_id != SPECIAL_NODEID || reverse_data.edge_id != SPECIAL_NODEID);
|
||||
|
||||
if (forward_data.edge_id != SPECIAL_NODEID && reverse_data.edge_id == SPECIAL_NODEID)
|
||||
m_edge_based_node_weights[forward_data.edge_id] = INVALID_EDGE_WEIGHT;
|
||||
@ -176,7 +172,7 @@ EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const NodeID nod
|
||||
|
||||
BOOST_ASSERT(current_edge_source_coordinate_id == node_v);
|
||||
|
||||
return Mapping{node_u, node_v, forward_data.edge_id, reverse_data.edge_id};
|
||||
return NBGToEBG{node_u, node_v, forward_data.edge_id, reverse_data.edge_id};
|
||||
}
|
||||
|
||||
void EdgeBasedGraphFactory::FlushVectorToStream(
|
||||
@ -207,7 +203,10 @@ void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment,
|
||||
|
||||
TIMER_START(generate_nodes);
|
||||
m_edge_based_node_weights.reserve(m_max_edge_id + 1);
|
||||
GenerateEdgeExpandedNodes(cnbg_ebg_mapping_path);
|
||||
{
|
||||
auto mapping = GenerateEdgeExpandedNodes();
|
||||
io::write(cnbg_ebg_mapping_path, mapping);
|
||||
}
|
||||
TIMER_STOP(generate_nodes);
|
||||
|
||||
TIMER_START(generate_edges);
|
||||
@ -259,12 +258,9 @@ unsigned EdgeBasedGraphFactory::RenumberEdges()
|
||||
}
|
||||
|
||||
/// Creates the nodes in the edge expanded graph from edges in the node-based graph.
|
||||
void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const std::string &cnbg_ebg_mapping_path)
|
||||
std::vector<NBGToEBG> EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
|
||||
{
|
||||
// Optional writer, for writing out a mapping. Neither default ctor not boost::optional work
|
||||
// with the underlying FileWriter, so hack around that limitation with a unique_ptr.
|
||||
std::unique_ptr<NodeBasedGraphToEdgeBasedGraphMappingWriter> writer;
|
||||
writer = std::make_unique<NodeBasedGraphToEdgeBasedGraphMappingWriter>(cnbg_ebg_mapping_path);
|
||||
std::vector<NBGToEBG> mapping;
|
||||
|
||||
util::Log() << "Generating edge expanded nodes ... ";
|
||||
{
|
||||
@ -295,21 +291,14 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const std::string &cnbg_eb
|
||||
|
||||
BOOST_ASSERT(node_u < node_v);
|
||||
|
||||
boost::optional<Mapping> mapping;
|
||||
|
||||
// if we found a non-forward edge reverse and try again
|
||||
if (edge_data.edge_id == SPECIAL_NODEID)
|
||||
{
|
||||
mapping = InsertEdgeBasedNode(node_v, node_u);
|
||||
mapping.push_back(InsertEdgeBasedNode(node_v, node_u));
|
||||
}
|
||||
else
|
||||
{
|
||||
mapping = InsertEdgeBasedNode(node_u, node_v);
|
||||
}
|
||||
|
||||
if (mapping)
|
||||
{
|
||||
writer->WriteMapping(mapping->u, mapping->v, mapping->head, mapping->tail);
|
||||
mapping.push_back(InsertEdgeBasedNode(node_u, node_v));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -319,6 +308,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const std::string &cnbg_eb
|
||||
BOOST_ASSERT(m_max_edge_id + 1 == m_edge_based_node_weights.size());
|
||||
|
||||
util::Log() << "Generated " << m_edge_based_node_list.size() << " nodes in edge-expanded graph";
|
||||
|
||||
return mapping;
|
||||
}
|
||||
|
||||
/// Actually it also generates OriginalEdgeData and serializes them...
|
||||
|
@ -42,6 +42,7 @@ Partition cellsToPartition(const std::vector<CellBisection> &cells,
|
||||
[&partition, cell_id](const auto node_id) { partition[node_id] = cell_id; });
|
||||
cell_id++;
|
||||
}
|
||||
BOOST_ASSERT(std::find(partition.begin(), partition.end(), INVALID_CELL_ID) == partition.end());
|
||||
|
||||
return partition;
|
||||
}
|
||||
@ -126,9 +127,10 @@ bisectionToPartition(const std::vector<BisectionID> &node_to_bisection_id,
|
||||
std::vector<Partition> partitions(max_cell_sizes.size());
|
||||
std::vector<std::uint32_t> num_cells(max_cell_sizes.size());
|
||||
|
||||
auto level_idx = max_cell_sizes.size() - 1;
|
||||
int level_idx = max_cell_sizes.size() - 1;
|
||||
for (auto max_cell_size : boost::adaptors::reverse(max_cell_sizes))
|
||||
{
|
||||
BOOST_ASSERT(level_idx >= 0);
|
||||
partitionLevel(node_to_bisection_id, max_cell_size, permutation, cells);
|
||||
|
||||
partitions[level_idx] = cellsToPartition(cells, permutation);
|
||||
|
@ -6,8 +6,10 @@
|
||||
#include "partition/edge_based_graph_reader.hpp"
|
||||
#include "partition/io.hpp"
|
||||
#include "partition/multi_level_partition.hpp"
|
||||
#include "partition/node_based_graph_to_edge_based_graph_mapping_reader.hpp"
|
||||
#include "partition/recursive_bisection.hpp"
|
||||
#include "partition/remove_unconnected.hpp"
|
||||
|
||||
#include "extractor/io.hpp"
|
||||
|
||||
#include "util/coordinate.hpp"
|
||||
#include "util/geojson_debug_logger.hpp"
|
||||
@ -123,7 +125,8 @@ int Partitioner::Run(const PartitionConfig &config)
|
||||
// Then loads the edge based graph tanslates the partition and modifies it.
|
||||
// For details see #3205
|
||||
|
||||
auto mapping = LoadNodeBasedGraphToEdgeBasedGraphMapping(config.cnbg_ebg_mapping_path.string());
|
||||
std::vector<extractor::NBGToEBG> mapping;
|
||||
extractor::io::read(config.cnbg_ebg_mapping_path.string(), mapping);
|
||||
util::Log() << "Loaded node based graph to edge based graph mapping";
|
||||
|
||||
auto edge_based_graph = LoadEdgeBasedGraph(config.edge_based_graph_path.string());
|
||||
@ -137,61 +140,22 @@ int Partitioner::Run(const PartitionConfig &config)
|
||||
const auto &node_based_partition_ids = recursive_bisection.BisectionIDs();
|
||||
|
||||
// Partition ids, keyed by edge based graph nodes
|
||||
std::vector<NodeID> edge_based_partition_ids(edge_based_graph->GetNumberOfNodes());
|
||||
std::vector<NodeID> edge_based_partition_ids(edge_based_graph->GetNumberOfNodes(),
|
||||
SPECIAL_NODEID);
|
||||
|
||||
// Extract edge based border nodes, based on node based partition and mapping.
|
||||
for (const auto node : util::irange(0u, edge_based_graph->GetNumberOfNodes()))
|
||||
// Only resolve all easy cases in the first pass
|
||||
for (const auto &entry : mapping)
|
||||
{
|
||||
const auto node_based_nodes = mapping.Lookup(node);
|
||||
const auto u = entry.u;
|
||||
const auto v = entry.v;
|
||||
const auto forward_node = entry.forward_ebg_node;
|
||||
const auto backward_node = entry.backward_ebg_node;
|
||||
|
||||
const auto u = node_based_nodes.u;
|
||||
const auto v = node_based_nodes.v;
|
||||
|
||||
if (node_based_partition_ids[u] == node_based_partition_ids[v])
|
||||
{
|
||||
// Can use partition_ids[u/v] as partition for edge based graph `node_id`
|
||||
edge_based_partition_ids[node] = node_based_partition_ids[u];
|
||||
|
||||
auto edges = edge_based_graph->GetAdjacentEdgeRange(node);
|
||||
if (edges.size() == 1)
|
||||
{ // Check the edge case with one adjacent edge-based backward edge
|
||||
auto edge = edges.front();
|
||||
auto other = edge_based_graph->GetTarget(edge);
|
||||
auto &data = edge_based_graph->GetEdgeData(edge);
|
||||
auto other_node_based_nodes = mapping.Lookup(other);
|
||||
if (data.backward &&
|
||||
node_based_partition_ids[other_node_based_nodes.u] !=
|
||||
node_based_partition_ids[u])
|
||||
{ // use id of other node if the edge [other_u, other_v] -> [u,v] is a single edge
|
||||
// and nodes other_[u,v] are in different node-based partitions
|
||||
edge_based_partition_ids[node] =
|
||||
node_based_partition_ids[other_node_based_nodes.u];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Border nodes u,v - need to be resolved.
|
||||
// FIXME: just pick one side for now. See #3205.
|
||||
|
||||
bool use_u = false;
|
||||
for (auto edge : edge_based_graph->GetAdjacentEdgeRange(node))
|
||||
{
|
||||
auto other = edge_based_graph->GetTarget(edge);
|
||||
auto &data = edge_based_graph->GetEdgeData(edge);
|
||||
auto other_node_based_nodes = mapping.Lookup(other);
|
||||
|
||||
if (data.backward)
|
||||
{ // can use id of u if [other_u, other_v] -> [u,v] is in the same partition as u
|
||||
BOOST_ASSERT(u == other_node_based_nodes.v);
|
||||
use_u |= node_based_partition_ids[u] ==
|
||||
node_based_partition_ids[other_node_based_nodes.u];
|
||||
}
|
||||
}
|
||||
|
||||
// Use partition that introduce less cross cell connections
|
||||
edge_based_partition_ids[node] = node_based_partition_ids[use_u ? u : v];
|
||||
}
|
||||
// This heuristic strategy seems to work best, even beating chosing the minimum
|
||||
// border edge bisection ID
|
||||
edge_based_partition_ids[forward_node] = node_based_partition_ids[u];
|
||||
if (backward_node != SPECIAL_NODEID)
|
||||
edge_based_partition_ids[backward_node] = node_based_partition_ids[v];
|
||||
}
|
||||
|
||||
std::vector<Partition> partitions;
|
||||
@ -203,6 +167,9 @@ int Partitioner::Run(const PartitionConfig &config)
|
||||
config.minimum_cell_size * 32 * 16,
|
||||
config.minimum_cell_size * 32 * 16 * 32});
|
||||
|
||||
auto num_unconnected = removeUnconnectedBoundaryNodes(*edge_based_graph, partitions);
|
||||
util::Log() << "Fixed " << num_unconnected << " unconnected nodes";
|
||||
|
||||
util::Log() << "Edge-based-graph annotation:";
|
||||
for (std::size_t level = 0; level < level_to_num_cells.size(); ++level)
|
||||
{
|
||||
|
117
unit_tests/partition/remove_unconnected.cpp
Normal file
117
unit_tests/partition/remove_unconnected.cpp
Normal file
@ -0,0 +1,117 @@
|
||||
#include <boost/numeric/conversion/cast.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include "partition/remove_unconnected.hpp"
|
||||
|
||||
#include "util/static_graph.hpp"
|
||||
|
||||
#define CHECK_SIZE_RANGE(range, ref) BOOST_CHECK_EQUAL(range.end() - range.begin(), ref)
|
||||
#define CHECK_EQUAL_RANGE(range, ref) \
|
||||
do \
|
||||
{ \
|
||||
const auto &lhs = range; \
|
||||
const auto &rhs = ref; \
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); \
|
||||
} while (0)
|
||||
|
||||
using namespace osrm;
|
||||
using namespace osrm::partition;
|
||||
|
||||
namespace
|
||||
{
|
||||
struct MockEdge
|
||||
{
|
||||
NodeID start;
|
||||
NodeID target;
|
||||
};
|
||||
|
||||
auto makeGraph(const std::vector<MockEdge> &mock_edges)
|
||||
{
|
||||
struct EdgeData
|
||||
{
|
||||
bool forward;
|
||||
bool backward;
|
||||
};
|
||||
using Edge = util::static_graph_details::SortableEdgeWithData<EdgeData>;
|
||||
std::vector<Edge> edges;
|
||||
std::size_t max_id = 0;
|
||||
for (const auto &m : mock_edges)
|
||||
{
|
||||
max_id = std::max<std::size_t>(max_id, std::max(m.start, m.target));
|
||||
edges.push_back(Edge{m.start, m.target, true, false});
|
||||
edges.push_back(Edge{m.target, m.start, false, true});
|
||||
}
|
||||
std::sort(edges.begin(), edges.end());
|
||||
return util::StaticGraph<EdgeData>(max_id + 1, edges);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(remove_unconnected_tests)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(remove_minimum_border_eges)
|
||||
{
|
||||
|
||||
// node: 0 1 2 3 4 5 6 7 8 9 10 11 12
|
||||
std::vector<CellID> l1{{0, 0, 0, 0, 1, 1, 2, 2, 2, 2, 2, 3, 3}};
|
||||
std::vector<CellID> l2{{0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2}};
|
||||
std::vector<CellID> l3{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}};
|
||||
|
||||
/*
|
||||
0---1 4---5 8---7 9
|
||||
\ / \ / \ /
|
||||
2 3------6
|
||||
|
|
||||
10
|
||||
| \
|
||||
11-12
|
||||
*/
|
||||
std::vector<MockEdge> edges = {
|
||||
// first clique
|
||||
{0, 1},
|
||||
{1, 2},
|
||||
{2, 0},
|
||||
|
||||
// second clique
|
||||
{3, 4},
|
||||
{4, 5},
|
||||
{5, 3},
|
||||
|
||||
// third clique
|
||||
{6, 7},
|
||||
{7, 8},
|
||||
{8, 6},
|
||||
|
||||
// fourth clique
|
||||
{10, 11},
|
||||
{11, 12},
|
||||
{12, 11},
|
||||
|
||||
// connection 3 to thrid clique
|
||||
{3, 6},
|
||||
// connect 10 to first clique
|
||||
{2, 10},
|
||||
};
|
||||
|
||||
// 10 is going to be unconnected on level 2 and 1
|
||||
// 3 is going to be unconnected only on level 1
|
||||
|
||||
auto graph = makeGraph(edges);
|
||||
std::vector<Partition> partitions = {l1, l2, l3};
|
||||
std::vector<Partition> reference_partitions = partitions;
|
||||
// 3 get's merged into cell 1 on first level
|
||||
reference_partitions[0][3] = 1;
|
||||
reference_partitions[1][3] = 0;
|
||||
// 10 get's merged into cell 0 on both levels and not with 11 (different parent cell)
|
||||
// even though there are would be less boundary edges
|
||||
reference_partitions[0][10] = 0;
|
||||
reference_partitions[1][10] = 0;
|
||||
|
||||
auto num_unconnected = removeUnconnectedBoundaryNodes(graph, partitions);
|
||||
BOOST_CHECK_EQUAL(num_unconnected, 2);
|
||||
|
||||
CHECK_EQUAL_RANGE(partitions[0], reference_partitions[0]);
|
||||
CHECK_EQUAL_RANGE(partitions[1], reference_partitions[1]);
|
||||
CHECK_EQUAL_RANGE(partitions[2], reference_partitions[2]);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
Loading…
Reference in New Issue
Block a user