Commit e8c72926 authored by Kučera Petr RNDr. Ph.D.'s avatar Kučera Petr RNDr. Ph.D.
Browse files

Subgraphs

parent eb3c22e0
......@@ -122,5 +122,28 @@ main([[maybe_unused]] int argc, char *argv[])
std::ofstream f(cfg.debug.section_graph_info);
sg->PrintSectionInfo(f);
}
Loco::TrainRoutes routes(input_data, sg);
auto tp_zababov = input_data.mTrafficPoints.Find("Bod Zababov");
tp_zababov->Print(std::cout, "", "");
auto tp_divisov = input_data.mTrafficPoints.Find("Bod Divisov");
tp_divisov->Print(std::cout, "", "");
auto tp_kopanky = input_data.mTrafficPoints.Find("Bod Kopanky");
tp_kopanky->Print(std::cout, "", "");
auto tp_petrov = input_data.mTrafficPoints.Find("Bod Petrov");
tp_petrov->Print(std::cout, "", "");
auto subg_zababov_divisov = sg->Subgraph(tp_zababov, tp_divisov);
{
std::ofstream f("data/graph/subg_zababov_divisov.dot");
sg->PrintSubgraph(f, subg_zababov_divisov, "subg_zababov_divisov");
}
auto subg_divisov_kopanky = sg->Subgraph(tp_divisov, tp_kopanky);
{
std::ofstream f("data/graph/subg_divisov_kopanky.dot");
sg->PrintSubgraph(f, subg_divisov_kopanky, "subg_divisov_kopanky");
}
auto subg_kopanky_petrov = sg->Subgraph(tp_kopanky, tp_petrov);
{
std::ofstream f("data/graph/subg_kopanky_petrov.dot");
sg->PrintSubgraph(f, subg_kopanky_petrov, "subg_kopanky_petrov");
}
// Loco::TrainRoutes routes(input_data, sg);
}
......@@ -13,6 +13,7 @@
#include <algorithm>
#include <numeric>
#include <queue>
#include <unordered_set>
#include "section_graph.h"
......@@ -50,6 +51,7 @@ Loco::SectionGraph::AddInfoForSection(const LogicalGraph &logical_graph,
{
auto [vertices, len] = logical_graph.FindSectionVertices(sect);
mSectionId[sect] = mSections.size();
bool has_physical_node = false;
for (const auto &v : vertices)
{
if (std::holds_alternative<PointCPtr>(v))
......@@ -58,8 +60,10 @@ Loco::SectionGraph::AddInfoForSection(const LogicalGraph &logical_graph,
continue;
}
mNodeSections[std::get<NodeCPtr>(v)].push_back(mSections.size());
has_physical_node = true;
}
mSections.emplace_back(std::move(sect), std::move(vertices), len);
mSections.emplace_back(std::move(sect), std::move(vertices), len,
has_physical_node);
}
std::ostream &
......@@ -81,13 +85,20 @@ Loco::SectionGraph::PrintGraph(std::ostream &os) const
return os << "}" << std::endl;
}
std::ostream &
Loco::SectionGraph::PrintVertex(std::ostream &os, unsigned i) const
{
os << kTabString << "v" << i << " [label=\""
<< mSections[i].mSection->Ident() << "\"]" << std::endl;
return os;
}
std::ostream &
Loco::SectionGraph::PrintVertices(std::ostream &os) const
{
for (unsigned i = 0; i < mSections.size(); ++i)
{
os << kTabString << "v" << i << " [label=\""
<< mSections[i].mSection->Ident() << "\"]" << std::endl;
PrintVertex(os, i);
}
return os;
}
......@@ -127,12 +138,60 @@ Loco::SectionGraph::SectionInfo::Print(std::ostream &os, unsigned id) const
void
Loco::SectionGraph::BuildNeighbours()
{
#if 0
BuildPairs(mPointSections, [](auto &sect) -> std::vector<unsigned> & {
return sect.mNeighbours;
});
#endif
for (const auto &[point, sects] : mPointSections)
{
if (sects.size() == 1)
{
continue;
}
// The following should avoid shortcuts around station tracks
// TODO: It should be made more general, this is too specific
// Why the sections in the input data can share more than one point
// anyway?
unsigned middle = sects.size();
for (unsigned i = 0; i < sects.size(); ++i)
{
if (!mSections[sects[i]].mHasPhysicalNode)
{
middle = i;
break;
}
}
if (middle != sects.size())
{
for (unsigned i = 0; i < sects.size(); ++i)
{
if (i != middle)
{
mSections[sects[i]].mNeighbours.push_back(sects[middle]);
mSections[sects[middle]].mNeighbours.push_back(sects[i]);
}
}
}
else
{
for (unsigned i = 0; i < sects.size(); ++i)
{
for (unsigned j = i + 1; j < sects.size(); ++j)
{
mSections[sects[i]].mNeighbours.push_back(sects[j]);
mSections[sects[j]].mNeighbours.push_back(sects[i]);
}
}
}
}
std::vector<unsigned> buffer;
for (auto &sect : mSections)
{
std::vector<unsigned> buffer;
std::sort(sect.mNeighbours.begin(), sect.mNeighbours.end());
auto last = std::unique(sect.mNeighbours.begin(), sect.mNeighbours.end());
sect.mNeighbours.erase(last, sect.mNeighbours.end());
buffer.clear();
std::set_difference(sect.mNeighbours.begin(), sect.mNeighbours.end(),
sect.mConflicts.begin(), sect.mConflicts.end(),
std::back_inserter(buffer));
......@@ -314,16 +373,31 @@ Loco::SectionGraph::NewSubgraphWithIds(std::vector<unsigned> sources,
sources, targets,
std::unordered_map<unsigned, SGSubgraph::NodeInfo>());
}
std::cout << "sources:";
for (unsigned i : sources)
{
std::cout << " " << i;
}
std::cout << std::endl;
std::cout << "targets:";
for (unsigned i : targets)
{
std::cout << " " << i;
}
std::cout << std::endl;
// Run BFS from sources,
// Mark the nodes which have path from the source (CLOSED and TERMINAL at the
// end)
// Store all possible predecessors of all nodes
std::vector<SEARCH_STATE> state(mSections.size(), SEARCH_STATE::UNVISITED);
std::vector<std::vector<unsigned>> pred(mSections.size());
const unsigned max_dist = mSections.size() + 1;
std::vector<unsigned> dist(mSections.size(), max_dist);
std::queue<unsigned> q;
for (auto i : sources)
{
state[i] = SEARCH_STATE::OPEN;
dist[i] = 0;
q.push(i);
}
for (auto i : targets)
......@@ -337,9 +411,19 @@ Loco::SectionGraph::NewSubgraphWithIds(std::vector<unsigned> sources,
if (state[nb] == SEARCH_STATE::UNVISITED)
{
q.push(nb);
dist[nb] = dist[q.front()] + 1;
state[nb] = SEARCH_STATE::OPEN;
}
pred[nb].push_back(q.front());
// TODO: We only taky shortest paths which maybe does not capture all
// possible situations
// TODO: Use DFS and do not allow backward edges
// DFS has to start from all source nodes
// But problem is if there is a path from one source to another
// So the shortest paths are the best bet for now
if (state[nb] != SEARCH_STATE::CLOSED)
{
pred[nb].push_back(q.front());
}
}
if (state[q.front()] != SEARCH_STATE::TERMINAL)
{
......@@ -369,7 +453,7 @@ Loco::SectionGraph::NewSubgraphWithIds(std::vector<unsigned> sources,
q.push(p);
back_state[p] = SEARCH_STATE::OPEN;
}
succ[q.front()].push_back(p);
succ[p].push_back(q.front());
}
if (back_state[q.front()] != SEARCH_STATE::TERMINAL)
{
......@@ -444,3 +528,30 @@ Loco::SectionGraph::Subgraph(const TrafficPointCPtr &source,
mSubgraphs.insert({std::move(key), subg});
return subg;
}
std::ostream &
Loco::SectionGraph::PrintSubgraph(std::ostream &os, const SGSubgraphCPtr &subg,
const std::string &label) const
{
os << "digraph " << label << " {" << std::endl;
os << kTabString << "rankdir=\"LR\"" << std::endl;
for (const auto &[id, info] : subg->mSections)
{
PrintVertex(os, id);
}
for (const auto &[id, info] : subg->mSections)
{
for (unsigned succ : info.mSucc)
{
os << kTabString << "v" << id << " -> v" << succ << " [color=blue]"
<< std::endl;
}
for (unsigned pred : info.mPred)
{
os << kTabString << "v" << pred << " -> v" << id << " [color=red]"
<< std::endl;
}
}
os << "}" << std::endl;
return os;
}
......@@ -52,13 +52,14 @@ namespace Loco
unsigned mConflictGroupId{};
std::vector<unsigned> mNeighbours;
std::vector<unsigned> mConflicts;
bool mHasPhysicalNode;
SectionInfo() = default;
SectionInfo(SectionCPtr sect,
std::vector<LogicalGraph::Vertex> vertices,
length_type len)
length_type len, bool has_physical_node)
: mSection(std::move(sect)), mVertices(std::move(vertices)),
mLength(len)
mLength(len), mHasPhysicalNode(has_physical_node)
{
}
......@@ -98,6 +99,7 @@ namespace Loco
SGPlaceCPtr PlaceOfSection(unsigned section_id) const;
std::vector<unsigned>
SectionIds(const std::vector<SectionCPtr> &sect) const;
std::ostream &PrintVertex(std::ostream &os, unsigned i) const;
std::ostream &PrintVertices(std::ostream &os) const;
SGSubgraphCPtr NewSubgraphWithIds(std::vector<unsigned> sources,
std::vector<unsigned> targets) const;
......@@ -118,6 +120,9 @@ namespace Loco
SGSubgraphCPtr Subgraph(const TrafficPointCPtr &source,
const TrafficPointCPtr &target) const;
std::ostream &PrintSubgraph(std::ostream &os, const SGSubgraphCPtr &subg,
const std::string &label) const;
};
using SectionGraphCPtr = std::shared_ptr<const SectionGraph>;
......
......@@ -58,4 +58,7 @@ Loco::TrainRouteGraph::AddElement(unsigned start)
mElements.emplace_back(start, mSectionGraph->Subgraph(
mTrain->StopAt(start).TrafficPoint(),
mTrain->StopAt(start + 1).TrafficPoint()));
std::cout << "Element " << mTrain->Ident() << "@" << start << std::endl;
mSectionGraph->PrintSubgraph(std::cout, mElements.back().mSubgraph,
"subg_" + std::to_string(start));
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment