Merge pull request #5508 from bykoianko/master-ingoing-wave

Backward wave in CrossMwmGraph
This commit is contained in:
Добрый Ээх 2017-03-06 11:24:04 +03:00 committed by GitHub
commit 87d8637509
11 changed files with 435 additions and 122 deletions

View file

@ -35,6 +35,8 @@ set(
newtype.hpp
normalize_unicode.cpp
observer_list.hpp
random.cpp
random.hpp
range_iterator.hpp
ref_counted.hpp
rolling_hash.hpp

View file

@ -18,6 +18,7 @@ SOURCES += \
logging.cpp \
lower_case.cpp \
normalize_unicode.cpp \
random.cpp \
shared_buffer_manager.cpp \
src_point.cpp \
string_format.cpp \
@ -59,6 +60,7 @@ HEADERS += \
mutex.hpp \
newtype.hpp \
observer_list.hpp \
random.hpp \
range_iterator.hpp \
ref_counted.hpp \
regexp.hpp \

22
base/random.cpp Normal file
View file

@ -0,0 +1,22 @@
#include "base/random.hpp"
#include <algorithm>
#include <numeric>
namespace base
{
std::vector<size_t> RandomSample(size_t n, size_t k, std::minstd_rand & rng)
{
std::vector<size_t> result(std::min(k, n));
std::iota(result.begin(), result.end(), 0);
for (size_t i = k; i < n; ++i)
{
size_t const j = rng() % (i + 1);
if (j < k)
result[j] = i;
}
return result;
}
} // base

10
base/random.hpp Normal file
View file

@ -0,0 +1,10 @@
#pragma once
#include <random>
#include <vector>
namespace base
{
// Selects a fair random subset of size min(|n|, |k|) from [0, 1, 2, ..., n - 1].
std::vector<size_t> RandomSample(size_t n, size_t k, std::minstd_rand & rng);
} // base

View file

@ -3,11 +3,134 @@
#include "geometry/distance_on_sphere.hpp"
#include <limits>
namespace
{
using namespace routing;
inline bool IsValidEdgeWeight(EdgeWeight const & w) { return w != INVALID_EDGE_WEIGHT; }
template <class Node>
class ClosestNodeFinder
{
public:
ClosestNodeFinder(CrossNode const & node, double & minDistance, Node & resultingCrossNode)
: m_node(node), m_minDistance(minDistance), m_resultingCrossNode(resultingCrossNode)
{
}
void operator()(Node const & crossNode) const
{
if (crossNode.m_nodeId != m_node.node)
return;
double const dist = ms::DistanceOnEarth(m_node.point, crossNode.m_point);
if (dist < m_minDistance)
{
m_minDistance = dist;
m_resultingCrossNode = crossNode;
}
}
private:
CrossNode const & m_node;
double & m_minDistance;
Node & m_resultingCrossNode;
};
double GetAdjacencyCost(CrossRoutingContextReader const & currentContext,
IngoingCrossNode const & ingoingCrossNode,
OutgoingCrossNode const & outgoingCrossNode)
{
return currentContext.GetAdjacencyCost(ingoingCrossNode, outgoingCrossNode);
}
double GetAdjacencyCost(CrossRoutingContextReader const & currentContext,
OutgoingCrossNode const & outgoingCrossNode,
IngoingCrossNode const & ingoingCrossNode)
{
return GetAdjacencyCost(currentContext, ingoingCrossNode, outgoingCrossNode);
}
template <class SourceNode, class TargetNode>
class EdgesFiller
{
public:
EdgesFiller(TRoutingMappingPtr const & currentMapping,
CrossRoutingContextReader const & currentContext, SourceNode const & startingNode,
CrossMwmGraph const & crossMwmGraph, vector<CrossWeightedEdge> & adj)
: m_currentMapping(currentMapping)
, m_currentContext(currentContext)
, m_startingNode(startingNode)
, m_crossMwmGraph(crossMwmGraph)
, m_adj(adj)
{
}
void operator()(TargetNode const & node) const
{
TWrittenEdgeWeight const outWeight = GetAdjacencyCost(m_currentContext, m_startingNode, node);
if (outWeight != kInvalidContextEdgeWeight && outWeight != 0)
{
vector<BorderCross> const & targets =
m_crossMwmGraph.ConstructBorderCross(m_currentMapping, node);
for (auto const & target : targets)
{
if (target.toNode.IsValid())
m_adj.emplace_back(target, outWeight);
}
}
}
private:
TRoutingMappingPtr const & m_currentMapping;
CrossRoutingContextReader const & m_currentContext;
SourceNode const & m_startingNode;
CrossMwmGraph const & m_crossMwmGraph;
vector<CrossWeightedEdge> & m_adj;
};
bool ForEachNodeNearPoint(CrossRoutingContextReader const & currentContext,
CrossNode const & crossNode,
ClosestNodeFinder<IngoingCrossNode> const & findingNode)
{
return currentContext.ForEachIngoingNodeNearPoint(crossNode.point, findingNode);
}
bool ForEachNodeNearPoint(CrossRoutingContextReader const & currentContext,
CrossNode const & crossNode,
ClosestNodeFinder<OutgoingCrossNode> const & findingNode)
{
return currentContext.ForEachOutgoingNodeNearPoint(crossNode.point, findingNode);
}
template <class Node>
void FindCrossNode(CrossRoutingContextReader const & currentContext, CrossNode const & crossNode,
Node & node)
{
double minDistance = std::numeric_limits<double>::max();
ClosestNodeFinder<Node> findingNode(crossNode, minDistance, node);
CHECK(ForEachNodeNearPoint(currentContext, crossNode, findingNode), ());
CHECK_NOT_EQUAL(minDistance, std::numeric_limits<double>::max(),
("crossNode.point:", crossNode.point));
}
template <class Fn>
vector<BorderCross> const & ConstructBorderCrossImpl(
TWrittenNodeId nodeId, TRoutingMappingPtr const & currentMapping,
unordered_map<CrossMwmGraph::TCachingKey, vector<BorderCross>, CrossMwmGraph::Hash> const &
cachedNextNodes,
Fn && borderCrossConstructor /*bool & result*/)
{
auto const key = make_pair(nodeId, currentMapping->GetMwmId());
auto const it = cachedNextNodes.find(key);
if (it != cachedNextNodes.end())
return it->second;
borderCrossConstructor(key);
return cachedNextNodes.find(key)->second;
}
} // namespace
namespace routing
{
IRouter::ResultCode CrossMwmGraph::SetStartNode(CrossNode const & startNode)
@ -54,14 +177,15 @@ IRouter::ResultCode CrossMwmGraph::SetStartNode(CrossNode const & startNode)
{
if (IsValidEdgeWeight(weights[i]))
{
vector<BorderCross> const & nextCrosses = ConstructBorderCross(outgoingNodes[i], startMapping);
vector<BorderCross> const & nextCrosses =
ConstructBorderCross(startMapping, outgoingNodes[i]);
for (auto const & nextCross : nextCrosses)
{
if (nextCross.toNode.IsValid())
dummyEdges.emplace_back(nextCross, weights[i]);
}
}
}
}
m_virtualEdges.insert(make_pair(startNode, dummyEdges));
return IRouter::NoError;
@ -129,24 +253,9 @@ IRouter::ResultCode CrossMwmGraph::SetFinalNode(CrossNode const & finalNode)
return IRouter::NoError;
}
vector<BorderCross> const & CrossMwmGraph::ConstructBorderCross(OutgoingCrossNode const & startNode,
TRoutingMappingPtr const & currentMapping) const
{
// Check cached crosses.
auto const key = make_pair(startNode.m_nodeId, currentMapping->GetMwmId());
auto const it = m_cachedNextNodes.find(key);
if (it != m_cachedNextNodes.end())
return it->second;
// Cache miss case.
auto & crosses = m_cachedNextNodes[key];
ConstructBorderCrossImpl(startNode, currentMapping, crosses);
return crosses;
}
bool CrossMwmGraph::ConstructBorderCrossImpl(OutgoingCrossNode const & startNode,
TRoutingMappingPtr const & currentMapping,
vector<BorderCross> & crosses) const
bool CrossMwmGraph::ConstructBorderCrossByOutgoingImpl(OutgoingCrossNode const & startNode,
TRoutingMappingPtr const & currentMapping,
vector<BorderCross> & crosses) const
{
auto const fromCross = CrossNode(startNode.m_nodeId, currentMapping->GetMwmId(), startNode.m_point);
string const & nextMwm = currentMapping->m_crossContext.GetOutgoingMwmName(startNode);
@ -156,71 +265,131 @@ bool CrossMwmGraph::ConstructBorderCrossImpl(OutgoingCrossNode const & startNode
return false;
ASSERT(crosses.empty(), ());
nextMapping->LoadCrossContext();
nextMapping->m_crossContext.ForEachIngoingNodeNearPoint(startNode.m_point, [&](IngoingCrossNode const & node)
{
if (node.m_point.EqualDxDy(startNode.m_point, kMwmCrossingNodeEqualityMeters * MercatorBounds::degreeInMetres))
{
auto const toCross = CrossNode(node.m_nodeId, nextMapping->GetMwmId(), node.m_point);
if (toCross.IsValid())
crosses.emplace_back(fromCross, toCross);
}
});
nextMapping->m_crossContext.ForEachIngoingNodeNearPoint(
startNode.m_point, [&](IngoingCrossNode const & node) {
if (node.m_nodeId == INVALID_NODE_ID)
return;
if (!node.m_point.EqualDxDy(
startNode.m_point, kMwmCrossingNodeEqualityMeters * MercatorBounds::degreeInMetres))
return;
crosses.emplace_back(fromCross,
CrossNode(node.m_nodeId, nextMapping->GetMwmId(), node.m_point));
});
return !crosses.empty();
}
void CrossMwmGraph::GetOutgoingEdgesList(BorderCross const & v,
vector<CrossWeightedEdge> & adj) const
bool CrossMwmGraph::ConstructBorderCrossByIngoingImpl(IngoingCrossNode const & startNode,
TRoutingMappingPtr const & currentMapping,
vector<BorderCross> & crosses) const
{
ASSERT(crosses.empty(), ());
auto const toCross = CrossNode(startNode.m_nodeId, currentMapping->GetMwmId(), startNode.m_point);
vector<string> const & neighboringMwms = currentMapping->m_crossContext.GetNeighboringMwmList();
string const & currentMwm = currentMapping->GetMwmId().GetInfo()->GetCountryName();
// Note. There's no field |m_ingoingIndex| in class IngoingCrossNode. Because this
// index is not saved in osrm routing section. So we need to write a workaround and
// to check all neighboring mwms.
for (string const & prevMwm : neighboringMwms)
{
TRoutingMappingPtr prevMapping = m_indexManager.GetMappingByName(prevMwm);
if (!prevMapping->IsValid())
continue;
prevMapping->LoadCrossContext();
prevMapping->m_crossContext.ForEachOutgoingNodeNearPoint(
startNode.m_point, [&](OutgoingCrossNode const & node) {
if (node.m_nodeId == INVALID_NODE_ID)
return;
if (prevMapping->m_crossContext.GetOutgoingMwmName(node) != currentMwm)
return;
if (!node.m_point.EqualDxDy(startNode.m_point, kMwmCrossingNodeEqualityMeters *
MercatorBounds::degreeInMetres))
return;
crosses.emplace_back(CrossNode(node.m_nodeId, prevMapping->GetMwmId(), node.m_point),
toCross);
});
}
return !crosses.empty();
}
vector<BorderCross> const & CrossMwmGraph::ConstructBorderCross(
TRoutingMappingPtr const & currentMapping, OutgoingCrossNode const & node) const
{
return ConstructBorderCrossImpl(node.m_nodeId, currentMapping, m_cachedNextNodesByOutgoing,
[&](std::pair<TWrittenNodeId, Index::MwmId const &> const & key) {
vector<BorderCross> crosses;
ConstructBorderCrossByOutgoingImpl(node, currentMapping,
crosses);
m_cachedNextNodesByOutgoing[key] = move(crosses);
});
}
vector<BorderCross> const & CrossMwmGraph::ConstructBorderCross(
TRoutingMappingPtr const & currentMapping, IngoingCrossNode const & node) const
{
return ConstructBorderCrossImpl(node.m_nodeId, currentMapping, m_cachedNextNodesByIngoing,
[&](std::pair<TWrittenNodeId, Index::MwmId const &> const & key) {
vector<BorderCross> crosses;
ConstructBorderCrossByIngoingImpl(node, currentMapping,
crosses);
m_cachedNextNodesByIngoing[key] = move(crosses);
});
}
void CrossMwmGraph::GetEdgesList(BorderCross const & v, bool isOutgoing,
vector<CrossWeightedEdge> & adj) const
{
// Check for virtual edges.
adj.clear();
// Note. Code below processes virtual edges. This code does not work properly if isOutgoing ==
// false.
// At the same time when this method is called with isOutgoing == false |m_virtualEdges| is empty.
if (!isOutgoing && !m_virtualEdges.empty())
{
NOTIMPLEMENTED();
return;
}
auto const it = m_virtualEdges.find(v.toNode);
if (it != m_virtualEdges.end())
{
adj.insert(adj.end(), it->second.begin(), it->second.end());
// For last map we need to load virtual shortcuts and real cross roads. It takes to account case
// when we have a path from the mwmw border to the point inside the map throuh another map.
// when we have a path from the mwm border to the point inside the map throuh another map.
// See Ust-Katav test for more.
if (it->second.empty() || !it->second.front().GetTarget().toNode.isVirtual)
return;
}
// Loading cross routing section.
TRoutingMappingPtr currentMapping = m_indexManager.GetMappingById(v.toNode.mwmId);
TRoutingMappingPtr currentMapping =
m_indexManager.GetMappingById(isOutgoing ? v.toNode.mwmId : v.fromNode.mwmId);
ASSERT(currentMapping->IsValid(), ());
currentMapping->LoadCrossContext();
currentMapping->FreeFileIfPossible();
CrossRoutingContextReader const & currentContext = currentMapping->m_crossContext;
// Find income node.
IngoingCrossNode ingoingNode;
bool found = false;
auto findingFn = [&ingoingNode, &v, &found](IngoingCrossNode const & node)
if (isOutgoing)
{
if (node.m_nodeId == v.toNode.node)
{
found = true;
ingoingNode = node;
IngoingCrossNode ingoingNode;
FindCrossNode<IngoingCrossNode>(currentContext, v.toNode, ingoingNode);
currentContext.ForEachOutgoingNode(EdgesFiller<IngoingCrossNode, OutgoingCrossNode>(
currentMapping, currentContext, ingoingNode, *this, adj));
}
else
{
OutgoingCrossNode outgoingNode;
FindCrossNode<OutgoingCrossNode>(currentContext, v.fromNode, outgoingNode);
currentContext.ForEachIngoingNode(EdgesFiller<OutgoingCrossNode, IngoingCrossNode>(
currentMapping, currentContext, outgoingNode, *this, adj));
}
};
CHECK(currentContext.ForEachIngoingNodeNearPoint(v.toNode.point, findingFn), ());
CHECK(found, ());
// Find outs. Generate adjacency list.
currentContext.ForEachOutgoingNode([&, this](OutgoingCrossNode const & node)
{
EdgeWeight const outWeight = currentContext.GetAdjacencyCost(ingoingNode, node);
if (outWeight != kInvalidContextEdgeWeight && outWeight != 0)
{
vector<BorderCross> const & targets = ConstructBorderCross(node, currentMapping);
for (auto const & target : targets)
{
if (target.toNode.IsValid())
adj.emplace_back(target, outWeight);
}
}
});
}
double CrossMwmGraph::HeuristicCostEstimate(BorderCross const & v, BorderCross const & w) const

View file

@ -72,6 +72,7 @@ struct BorderCross
BorderCross(CrossNode const & from, CrossNode const & to) : fromNode(from), toNode(to) {}
BorderCross() = default;
// TODO(bykoianko) Consider using fields |fromNode| and |toNode| in operator== and operator<.
inline bool operator==(BorderCross const & a) const { return toNode == a.toNode; }
inline bool operator<(BorderCross const & a) const { return toNode < a.toNode; }
};
@ -101,48 +102,10 @@ private:
class CrossMwmGraph
{
public:
using TCachingKey = pair<TWrittenNodeId, Index::MwmId>;
using TVertexType = BorderCross;
using TEdgeType = CrossWeightedEdge;
explicit CrossMwmGraph(RoutingIndexManager & indexManager) : m_indexManager(indexManager) {}
void GetOutgoingEdgesList(BorderCross const & v, vector<CrossWeightedEdge> & adj) const;
void GetIngoingEdgesList(BorderCross const & /* v */,
vector<CrossWeightedEdge> & /* adj */) const
{
NOTIMPLEMENTED();
}
double HeuristicCostEstimate(BorderCross const & v, BorderCross const & w) const;
IRouter::ResultCode SetStartNode(CrossNode const & startNode);
IRouter::ResultCode SetFinalNode(CrossNode const & finalNode);
private:
// Cashing wrapper for the ConstructBorderCrossImpl function.
vector<BorderCross> const & ConstructBorderCross(OutgoingCrossNode const & startNode,
TRoutingMappingPtr const & currentMapping) const;
// Pure function to construct boder cross by outgoing cross node.
bool ConstructBorderCrossImpl(OutgoingCrossNode const & startNode,
TRoutingMappingPtr const & currentMapping,
vector<BorderCross> & cross) const;
/*!
* Adds a virtual edge to the graph so that it is possible to represent
* the final segment of the path that leads from the map's border
* to finalNode. Addition of such virtual edges for the starting node is
* inlined elsewhere.
*/
void AddVirtualEdge(IngoingCrossNode const & node, CrossNode const & finalNode,
EdgeWeight weight);
map<CrossNode, vector<CrossWeightedEdge> > m_virtualEdges;
mutable RoutingIndexManager m_indexManager;
// Caching stuff.
using TCachingKey = pair<TWrittenNodeId, Index::MwmId>;
struct Hash
{
size_t operator()(TCachingKey const & p) const
@ -151,7 +114,53 @@ private:
}
};
mutable unordered_map<TCachingKey, vector<BorderCross>, Hash> m_cachedNextNodes;
explicit CrossMwmGraph(RoutingIndexManager & indexManager) : m_indexManager(indexManager) {}
void GetOutgoingEdgesList(BorderCross const & v, vector<CrossWeightedEdge> & adj) const
{
GetEdgesList(v, true /* isOutgoing */, adj);
}
void GetIngoingEdgesList(BorderCross const & v, vector<CrossWeightedEdge> & adj) const
{
GetEdgesList(v, false /* isOutgoing */, adj);
}
double HeuristicCostEstimate(BorderCross const & v, BorderCross const & w) const;
IRouter::ResultCode SetStartNode(CrossNode const & startNode);
IRouter::ResultCode SetFinalNode(CrossNode const & finalNode);
vector<BorderCross> const & ConstructBorderCross(TRoutingMappingPtr const & currentMapping,
OutgoingCrossNode const & node) const;
vector<BorderCross> const & ConstructBorderCross(TRoutingMappingPtr const & currentMapping,
IngoingCrossNode const & node) const;
private:
// Pure function to construct boder cross by outgoing cross node.
bool ConstructBorderCrossByOutgoingImpl(OutgoingCrossNode const & startNode,
TRoutingMappingPtr const & currentMapping,
vector<BorderCross> & cross) const;
bool ConstructBorderCrossByIngoingImpl(IngoingCrossNode const & startNode,
TRoutingMappingPtr const & currentMapping,
vector<BorderCross> & crosses) const;
/*!
* Adds a virtual edge to the graph so that it is possible to represent
* the final segment of the path that leads from the map's border
* to finalNode. Addition of such virtual edges for the starting node is
* inlined elsewhere.
*/
void AddVirtualEdge(IngoingCrossNode const & node, CrossNode const & finalNode,
EdgeWeight weight);
void GetEdgesList(BorderCross const & v, bool isOutgoing, vector<CrossWeightedEdge> & adj) const;
map<CrossNode, vector<CrossWeightedEdge> > m_virtualEdges;
mutable RoutingIndexManager m_indexManager;
// @TODO(bykoianko) Consider removing key work mutable.
mutable unordered_map<TCachingKey, vector<BorderCross>, Hash> m_cachedNextNodesByIngoing;
mutable unordered_map<TCachingKey, vector<BorderCross>, Hash> m_cachedNextNodesByOutgoing;
};
//--------------------------------------------------------------------------------------------------

View file

@ -105,8 +105,8 @@ const string & CrossRoutingContextReader::GetOutgoingMwmName(
return m_neighborMwmList[outgoingNode.m_outgoingIndex];
}
TWrittenEdgeWeight CrossRoutingContextReader::GetAdjacencyCost(IngoingCrossNode const & ingoing,
OutgoingCrossNode const & outgoing) const
TWrittenEdgeWeight CrossRoutingContextReader::GetAdjacencyCost(
IngoingCrossNode const & ingoing, OutgoingCrossNode const & outgoing) const
{
if (ingoing.m_adjacencyIndex == kInvalidAdjacencyIndex ||
outgoing.m_adjacencyIndex == kInvalidAdjacencyIndex)

View file

@ -91,7 +91,7 @@ class CrossRoutingContextReader
public:
void Load(Reader const & r);
const string & GetOutgoingMwmName(OutgoingCrossNode const & mwmIndex) const;
const string & GetOutgoingMwmName(OutgoingCrossNode const & outgoingNode) const;
TWrittenEdgeWeight GetAdjacencyCost(IngoingCrossNode const & ingoing,
OutgoingCrossNode const & outgoing) const;

View file

@ -1,9 +1,14 @@
#include "testing/testing.hpp"
#include "routing/cross_mwm_road_graph.hpp"
#include "routing/cross_routing_context.hpp"
#include "routing/osrm2feature_map.hpp"
#include "routing/routing_mapping.hpp"
#include "storage/country_info_getter.hpp"
#include "indexer/index.hpp"
#include "platform/local_country_file.hpp"
#include "platform/local_country_file_utils.hpp"
#include "platform/platform.hpp"
@ -12,9 +17,12 @@
#include "base/buffer_vector.hpp"
#include "base/logging.hpp"
#include "base/random.hpp"
#include "std/limits.hpp"
#include <chrono>
using namespace routing;
namespace
@ -123,4 +131,98 @@ UNIT_TEST(CheckOsrmToFeatureMapping)
LOG(LINFO, ("Found", localFiles.size(), "countries. In", checked, "maps with routing have", errors, "with errors."));
TEST_EQUAL(errors, 0, ("Some countries have osrm and features mismatch."));
}
// The idea behind the test is
// 1. to go through all ingoing nodes of all mwms
// 2. to find all cross mwm outgoing edges for each ingoing node
// 3. to find all edges which are ingoing for the outgoing edges
// 4. to check that an edge mentioned in (1) there's between the ingoing edges
// Note. This test may take more than 3 hours.
UNIT_TEST(CrossMwmGraphTest)
{
vector<platform::LocalCountryFile> localFiles;
Index index;
platform::FindAllLocalMapsAndCleanup(numeric_limits<int64_t>::max() /* latestVersion */,
localFiles);
for (platform::LocalCountryFile & file : localFiles)
{
file.SyncWithDisk();
index.RegisterMap(file);
}
for (auto it = localFiles.begin(); it != localFiles.end();)
{
string const & countryName = it->GetCountryName();
MwmSet::MwmId const mwmId = index.GetMwmIdByCountryFile(it->GetCountryFile());
if (countryName == "minsk-pass" || mwmId.GetInfo()->GetType() != MwmInfo::COUNTRY)
it = localFiles.erase(it);
else
++it;
}
Platform p;
unique_ptr<storage::CountryInfoGetter> infoGetter =
storage::CountryInfoReader::CreateCountryInfoReader(p);
auto countryFileGetter = [&infoGetter](m2::PointD const & pt) {
return infoGetter->GetRegionCountryId(pt);
};
RoutingIndexManager manager(countryFileGetter, index);
CrossMwmGraph crossMwmGraph(manager);
auto const seed = std::chrono::system_clock::now().time_since_epoch().count();
LOG(LINFO, ("Seed for RandomSample:", seed));
std::minstd_rand rng(static_cast<unsigned int>(seed));
std::vector<size_t> subset = base::RandomSample(localFiles.size(), 10 /* mwm number */, rng);
std::vector<platform::LocalCountryFile> subsetCountryFiles;
for (size_t i : subset)
subsetCountryFiles.push_back(localFiles[i]);
for (platform::LocalCountryFile const & file : subsetCountryFiles)
{
string const & countryName = file.GetCountryName();
LOG(LINFO, ("Processing", countryName));
MwmSet::MwmId const mwmId = index.GetMwmIdByCountryFile(file.GetCountryFile());
TEST(mwmId.IsAlive(), ("Mwm name:", countryName, "Subset:", subsetCountryFiles));
TRoutingMappingPtr currentMapping = manager.GetMappingById(mwmId);
if (!currentMapping->IsValid())
continue; // No routing sections in the mwm.
currentMapping->LoadCrossContext();
currentMapping->FreeFileIfPossible();
CrossRoutingContextReader const & currentContext = currentMapping->m_crossContext;
size_t ingoingCounter = 0;
currentContext.ForEachIngoingNode([&](IngoingCrossNode const & node) {
++ingoingCounter;
vector<BorderCross> const & targets =
crossMwmGraph.ConstructBorderCross(currentMapping, node);
for (BorderCross const & t : targets)
{
vector<CrossWeightedEdge> outAdjs;
crossMwmGraph.GetOutgoingEdgesList(t, outAdjs);
for (CrossWeightedEdge const & out : outAdjs)
{
vector<CrossWeightedEdge> inAdjs;
crossMwmGraph.GetIngoingEdgesList(out.GetTarget(), inAdjs);
TEST(find_if(inAdjs.cbegin(), inAdjs.cend(),
[&](CrossWeightedEdge const & e) {
return e.GetTarget() == t && out.GetWeight() == e.GetWeight();
}) != inAdjs.cend(),
("ForEachOutgoingNodeNearPoint() and ForEachIngoingNodeNearPoint() arn't "
"correlated. Mwm:",
countryName, "Subset:", subsetCountryFiles));
}
}
});
size_t outgoingCounter = 0;
currentContext.ForEachOutgoingNode(
[&](OutgoingCrossNode const & /* node */) { ++outgoingCounter; });
LOG(LINFO, ("Processed:", countryName, "Exits:", outgoingCounter, "Enters:", ingoingCounter));
}
}
} // namespace

View file

@ -9,6 +9,7 @@
#include "indexer/rank_table.hpp"
#include "indexer/scales.hpp"
#include "base/random.hpp"
#include "base/stl_helpers.hpp"
#include "std/iterator.hpp"
@ -46,22 +47,6 @@ struct ComparePreResult1
}
};
// Selects a fair random subset of size min(|n|, |k|) from [0, 1, 2, ..., n - 1].
vector<size_t> RandomSample(size_t n, size_t k, minstd_rand & rng)
{
vector<size_t> result(std::min(k, n));
iota(result.begin(), result.end(), 0);
for (size_t i = k; i < n; ++i)
{
size_t const j = rng() % (i + 1);
if (j < k)
result[j] = i;
}
return result;
}
void SweepNearbyResults(double eps, vector<PreResult1> & results)
{
NearbyPointsSweeper sweeper(eps);
@ -281,7 +266,7 @@ void PreRanker::FilterForViewportSearch()
if (m <= old)
{
for (size_t i : RandomSample(old, m, m_rng))
for (size_t i : base::RandomSample(old, m, m_rng))
results.push_back(m_results[bucket[i]]);
}
else
@ -289,7 +274,7 @@ void PreRanker::FilterForViewportSearch()
for (size_t i = 0; i < old; ++i)
results.push_back(m_results[bucket[i]]);
for (size_t i : RandomSample(bucket.size() - old, m - old, m_rng))
for (size_t i : base::RandomSample(bucket.size() - old, m - old, m_rng))
results.push_back(m_results[bucket[old + i]]);
}
}
@ -301,7 +286,7 @@ void PreRanker::FilterForViewportSearch()
else
{
m_results.clear();
for (size_t i : RandomSample(results.size(), BatchSize(), m_rng))
for (size_t i : base::RandomSample(results.size(), BatchSize(), m_rng))
m_results.push_back(results[i]);
}
}

View file

@ -44,6 +44,9 @@
39FD27381CC65AD000AFF551 /* timegm_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 39FD26E21CC65A0E00AFF551 /* timegm_test.cpp */; };
39FD27391CC65AD000AFF551 /* timer_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 39FD26E31CC65A0E00AFF551 /* timer_test.cpp */; };
39FD273B1CC65B1000AFF551 /* libbase.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 675341771A3F57BF00A0A8C3 /* libbase.a */; };
56B1A0741E69DE4D00395022 /* random.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 56B1A0711E69DE4D00395022 /* random.cpp */; };
56B1A0751E69DE4D00395022 /* random.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 56B1A0721E69DE4D00395022 /* random.hpp */; };
56B1A0761E69DE4D00395022 /* small_set.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 56B1A0731E69DE4D00395022 /* small_set.hpp */; };
670E39441C46C76900E9C0A6 /* sunrise_sunset.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 670E39421C46C76900E9C0A6 /* sunrise_sunset.cpp */; };
670E39451C46C76900E9C0A6 /* sunrise_sunset.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 670E39431C46C76900E9C0A6 /* sunrise_sunset.hpp */; };
671182F01C807C0A00CB8177 /* gmtime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 671182EE1C807C0A00CB8177 /* gmtime.cpp */; };
@ -157,6 +160,9 @@
39FD273D1CC65B1000AFF551 /* libplatform.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libplatform.a; path = "../../../omim-xcode-build/Debug/libplatform.a"; sourceTree = "<group>"; };
39FD27401CC65B2800AFF551 /* libindexer.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libindexer.a; path = "../../../omim-xcode-build/Debug/libindexer.a"; sourceTree = "<group>"; };
39FD27421CC65B4800AFF551 /* libcoding.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcoding.a; path = "../../../omim-xcode-build/Debug/libcoding.a"; sourceTree = "<group>"; };
56B1A0711E69DE4D00395022 /* random.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = random.cpp; sourceTree = "<group>"; };
56B1A0721E69DE4D00395022 /* random.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = random.hpp; sourceTree = "<group>"; };
56B1A0731E69DE4D00395022 /* small_set.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = small_set.hpp; sourceTree = "<group>"; };
670E39421C46C76900E9C0A6 /* sunrise_sunset.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sunrise_sunset.cpp; sourceTree = "<group>"; };
670E39431C46C76900E9C0A6 /* sunrise_sunset.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = sunrise_sunset.hpp; sourceTree = "<group>"; };
671182EE1C807C0A00CB8177 /* gmtime.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gmtime.cpp; sourceTree = "<group>"; };
@ -311,6 +317,9 @@
675341791A3F57BF00A0A8C3 /* base */ = {
isa = PBXGroup;
children = (
56B1A0711E69DE4D00395022 /* random.cpp */,
56B1A0721E69DE4D00395022 /* random.hpp */,
56B1A0731E69DE4D00395022 /* small_set.hpp */,
675341851A3F57E400A0A8C3 /* array_adapters.hpp */,
675341861A3F57E400A0A8C3 /* assert.hpp */,
675341871A3F57E400A0A8C3 /* base.cpp */,
@ -420,6 +429,7 @@
675341D11A3F57E400A0A8C3 /* cache.hpp in Headers */,
675341E31A3F57E400A0A8C3 /* math.hpp in Headers */,
3446C6731DDCA96300146687 /* levenshtein_dfa.hpp in Headers */,
56B1A0751E69DE4D00395022 /* random.hpp in Headers */,
675341E21A3F57E400A0A8C3 /* macros.hpp in Headers */,
672DD4C51E0425600078E13C /* observer_list.hpp in Headers */,
675341EF1A3F57E400A0A8C3 /* rolling_hash.hpp in Headers */,
@ -452,6 +462,7 @@
675341FA1A3F57E400A0A8C3 /* src_point.hpp in Headers */,
674A7E2F1C0DB03D003D48E1 /* timegm.hpp in Headers */,
675341F71A3F57E400A0A8C3 /* shared_buffer_manager.hpp in Headers */,
56B1A0761E69DE4D00395022 /* small_set.hpp in Headers */,
67B52B611AD3C84E00664C17 /* thread_checker.hpp in Headers */,
672DD4BE1E0425600078E13C /* cancellable.hpp in Headers */,
675341CB1A3F57E400A0A8C3 /* array_adapters.hpp in Headers */,
@ -601,6 +612,7 @@
67E40EC81E4DC0D500A6D200 /* small_set_test.cpp in Sources */,
6753420E1A3F57E400A0A8C3 /* timer.cpp in Sources */,
675341F61A3F57E400A0A8C3 /* shared_buffer_manager.cpp in Sources */,
56B1A0741E69DE4D00395022 /* random.cpp in Sources */,
675341DA1A3F57E400A0A8C3 /* exception.cpp in Sources */,
675341F91A3F57E400A0A8C3 /* src_point.cpp in Sources */,
675342031A3F57E400A0A8C3 /* strings_bundle.cpp in Sources */,