Simplify the graph code a bit. This also will allow us easily to find

all paths from point A to point B, which we'll want to do later.

This should also get rid of an annoying bug that I couldn't figure out.


git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@34560 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Richard Heck 2010-05-31 21:27:17 +00:00
parent 6fe2fec87d
commit 50a81deff4
2 changed files with 26 additions and 64 deletions

View File

@ -45,12 +45,12 @@ bool Graph::bfs_init(int s, bool clear_visited)
} }
void Graph::clearMarks() void Graph::clearPaths()
{ {
Arrows::iterator it = arrows_.begin(); vector<Vertex>::iterator it = vertices_.begin();
Arrows::iterator const en = arrows_.end(); vector<Vertex>::iterator en = vertices_.end();
for (; it != en; ++it) for (; it != en; ++it)
it->marked = false; it->path.clear();
} }
@ -159,21 +159,14 @@ bool Graph::isReachable(int from, int to)
Graph::EdgePath const Graph::getPath(int from, int to) Graph::EdgePath const Graph::getPath(int from, int to)
{ {
EdgePath path; static const EdgePath path;
if (from == to) if (from == to)
return path; return path;
if (to < 0 || !bfs_init(from)) if (to < 0 || !bfs_init(from))
return path; return path;
// In effect, the way this works is that we construct a sub-graph clearPaths();
// by starting at "from" and following the arrows outward. Instead
// of actually constructing a sub-graph, though, we "mark" the
// arrows we traverse as we go. Once we hit "to", we abort the
// marking process and then call getMarkedPath() to reconstruct
// the marked path.
bool found = false;
clearMarks();
while (!Q_.empty()) { while (!Q_.empty()) {
int const current = Q_.front(); int const current = Q_.front();
Q_.pop(); Q_.pop();
@ -187,53 +180,23 @@ Graph::EdgePath const Graph::getPath(int from, int to)
if (!vertices_[cv].visited) { if (!vertices_[cv].visited) {
vertices_[cv].visited = true; vertices_[cv].visited = true;
Q_.push(cv); Q_.push(cv);
(*cit)->marked = true; // NOTE If we wanted to collect all the paths, then
// we just need to collect them here and not worry
// about "visited".
EdgePath lastpath = vertices_[(*cit)->from].path;
lastpath.push_back((*cit)->id);
vertices_[cv].path = lastpath;
} }
if (cv == to) { if (cv == to) {
found = true; return vertices_[cv].path;
break;
} }
} }
} }
if (!found) // failure
return path;
getMarkedPath(from, to, path);
return path; return path;
} }
// We assume we have marked the graph, as in getPath(). We also
// assume that we have done so in such a way as to guarantee a
// marked path from "from" to "to".
// We then start at "to" and find the arrow leading to it that
// has been marked. We add that to the path we are constructing,
// step back on that arrow, and continue the process (i.e., recurse).
void Graph::getMarkedPath(int from, int to, EdgePath & path) {
if (from == to) {
reverse(path.begin(), path.end());
return;
}
// find marked in_arrow
vector<Arrow *>::const_iterator it = vertices_[to].in_arrows.begin();
vector<Arrow *>::const_iterator const en = vertices_[to].in_arrows.end();
for (; it != en; ++it)
if ((*it)->marked)
break;
if (it == en) {
// debug code to try to figure out what's up.
LYXERR0("Failed to find marked arrow.\n"
"From: " << from << ", To: " << to);
dumpGraph();
LASSERT(false, /* */);
path.clear();
return;
}
path.push_back((*it)->id);
getMarkedPath(from, (*it)->from, path);
}
void Graph::init(int size) void Graph::init(int size)
{ {
vertices_ = vector<Vertex>(size); vertices_ = vector<Vertex>(size);
@ -252,6 +215,9 @@ void Graph::addEdge(int from, int to)
} }
// At present, we do not need this debugging code, but
// I am going to leave it here in case we need it again.
#if 0
void Graph::dumpGraph() const void Graph::dumpGraph() const
{ {
vector<Vertex>::const_iterator it = vertices_.begin(); vector<Vertex>::const_iterator it = vertices_.begin();
@ -262,16 +228,15 @@ void Graph::dumpGraph() const
std::vector<Arrow *>::const_iterator iit = it->in_arrows.begin(); std::vector<Arrow *>::const_iterator iit = it->in_arrows.begin();
std::vector<Arrow *>::const_iterator ien = it->in_arrows.end(); std::vector<Arrow *>::const_iterator ien = it->in_arrows.end();
for (; iit != ien; ++iit) for (; iit != ien; ++iit)
LYXERR0("From " << (*iit)->from << " to " << (*iit)->to LYXERR0("From " << (*iit)->from << " to " << (*iit)->to);
<< ". Marked: " << (*iit)->marked);
LYXERR0("Out arrows..."); LYXERR0("Out arrows...");
iit = it->out_arrows.begin(); iit = it->out_arrows.begin();
ien = it->out_arrows.end(); ien = it->out_arrows.end();
for (; iit != ien; ++iit) for (; iit != ien; ++iit)
LYXERR0("From " << (*iit)->from << " to " << (*iit)->to LYXERR0("From " << (*iit)->from << " to " << (*iit)->to);
<< ". Marked: " << (*iit)->marked);
} }
} }
#endif
} // namespace lyx } // namespace lyx

View File

@ -46,20 +46,18 @@ public:
private: private:
/// ///
bool bfs_init(int, bool clear_visited = true); bool bfs_init(int, bool clear_visited = true);
/// clears the "marks" on the arrows. should be called /// clears the paths from a previous search. should be
/// before any new marking begins. /// called before each new one.
void clearMarks(); void clearPaths();
/// used to recover a marked path /// used to recover a marked path
void getMarkedPath(int from, int to, EdgePath & path); void getMarkedPath(int from, int to, EdgePath & path);
///
void dumpGraph() const;
/// these represent the arrows connecting the nodes of the graph. /// these represent the arrows connecting the nodes of the graph.
/// this is the basic representation of the graph: as a bunch of /// this is the basic representation of the graph: as a bunch of
/// arrows. /// arrows.
struct Arrow { struct Arrow {
/// ///
Arrow(int f, int t, int i): Arrow(int f, int t, int i):
from(f), to(t), id(i), marked(false) {} from(f), to(t), id(i) {}
/// the vertex at the tail of the arrow /// the vertex at the tail of the arrow
int from; int from;
/// the vertex at the head /// the vertex at the head
@ -67,9 +65,6 @@ private:
/// an id for this arrow, e.g., for use in describing paths /// an id for this arrow, e.g., for use in describing paths
/// through the graph /// through the graph
int id; int id;
/// used for "marking" paths, i.e., constructing sub-graphs
/// without really doing so.
bool marked;
}; };
/// a container for the arrows /// a container for the arrows
/// we use a list because we want pointers to the arrows, /// we use a list because we want pointers to the arrows,
@ -86,6 +81,8 @@ private:
std::vector<Arrow *> out_arrows; std::vector<Arrow *> out_arrows;
/// used in the search routines /// used in the search routines
bool visited; bool visited;
///
EdgePath path;
}; };
/// a container for the vertices /// a container for the vertices
/// the index into the vector functions as the identifier by which /// the index into the vector functions as the identifier by which