Skip to content

Commit 74d9575

Browse files
dfs: attempt to fix
1 parent 28b1ae9 commit 74d9575

File tree

3 files changed

+93
-61
lines changed

3 files changed

+93
-61
lines changed

gap/attr.gi

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -702,7 +702,7 @@ function(D)
702702
data.out[data.count] := record.child;
703703
end;
704704
for i in DigraphVertices(D) do
705-
if record.preorder[i] <> -1 then
705+
if not IsBound(record.preorder[i]) then
706706
continue;
707707
fi;
708708
ExecuteDFS(record, data, i, DFSDefault,

gap/oper.gi

Lines changed: 63 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1388,10 +1388,10 @@ end);
13881388
InstallMethod(DigraphPath, "for a digraph by out-neighbours and two pos ints",
13891389
[IsDigraphByOutNeighboursRep, IsPosInt, IsPosInt],
13901390
function(D, u, v)
1391-
local verts, record, out, path_info, PostOrderFunc, AncestorFunc, AddToPath;
1391+
local N, record, PreOrderFunc, AncestorFunc, nodes, edges, current;
13921392

1393-
verts := DigraphVertices(D);
1394-
if not (u in verts and v in verts) then
1393+
N := DigraphNrVertices(D);
1394+
if u > N or v > N then
13951395
ErrorNoReturn("the 2nd and 3rd arguments <u> and <v> must be ",
13961396
"vertices of the 1st argument <D>,");
13971397
elif IsDigraphEdge(D, u, v) then
@@ -1404,39 +1404,58 @@ function(D, u, v)
14041404
and DigraphConnectedComponents(D).id[u] <>
14051405
DigraphConnectedComponents(D).id[v] then
14061406
return fail;
1407+
elif OutDegreeOfVertex(D, u) = 0
1408+
or (HasInNeighbours(D) and InDegreeOfVertex(D, v) = 0) then
1409+
return fail;
14071410
fi;
14081411
record := NewDFSRecord(D);
1409-
path_info := Stack();
1410-
AddToPath := function(current, child)
1411-
local edge;
1412-
edge := Position(OutNeighborsOfVertex(D, current), child);
1413-
Push(path_info, edge);
1414-
Push(path_info, child);
1415-
end;
1416-
AncestorFunc := function(record, data)
1417-
if u = v and record.child = u and Size(data) = 0 then
1418-
AddToPath(record.current, record.child);
1419-
record.preorder[v] := DigraphNrVertices(D) + 1;
1420-
fi;
1421-
end;
1422-
PostOrderFunc := function(record, data)
1423-
if record.child <> u and
1424-
record.preorder[record.child] <= record.preorder[v] then
1425-
AddToPath(record.current, record.child);
1426-
fi;
1427-
end;
1428-
ExecuteDFS(record, path_info, u,
1429-
DFSDefault, PostOrderFunc,
1430-
AncestorFunc, DFSDefault);
1431-
if Size(path_info) <= 1 then
1412+
if u <> v then
1413+
# if v is reachable from u, then u is an ancestor of v, and so at some
1414+
# point v will be encountered for the first time, and PreOrderFunc will be
1415+
# called.
1416+
PreOrderFunc := function(record, data)
1417+
if record.current = v then
1418+
record.stop := true;
1419+
fi;
1420+
end;
1421+
AncestorFunc := DFSDefault;
1422+
else
1423+
# if u is reachable from u, then u will be encountered as an ancestor of
1424+
# itself, but PreOrderFunc won't be called (because u has already been
1425+
# discovered).
1426+
PreOrderFunc := DFSDefault;
1427+
AncestorFunc := function(record, data)
1428+
if record.child = v then
1429+
record.stop := true;
1430+
fi;
1431+
end;
1432+
fi;
1433+
ExecuteDFS(record,
1434+
fail,
1435+
u,
1436+
PreOrderFunc,
1437+
DFSDefault,
1438+
AncestorFunc,
1439+
DFSDefault);
1440+
if not record.stop then
14321441
return fail;
14331442
fi;
1434-
out := [[u], []];
1435-
while Size(path_info) <> 0 do
1436-
Add(out[1], Pop(path_info));
1437-
Add(out[2], Pop(path_info));
1443+
nodes := [v];
1444+
edges := [];
1445+
current := v;
1446+
if u = v then
1447+
# Go one back from v to the last node in the tree
1448+
current := record.current;
1449+
Add(nodes, current);
1450+
Add(edges, Position(OutNeighboursOfVertex(D, current), u));
1451+
fi;
1452+
# Follow the path from current (which is a descendant of u) back to u
1453+
while current <> u do
1454+
Add(edges, record.edge[current]);
1455+
current := record.parent[current];
1456+
Add(nodes, current);
14381457
od;
1439-
return out;
1458+
return [Reversed(nodes), Reversed(edges)];
14401459
end);
14411460

14421461
InstallMethod(IsDigraphPath, "for a digraph and list",
@@ -2042,12 +2061,12 @@ function(D, root)
20422061
end;
20432062

20442063
ExecuteDFS(record,
2045-
data,
2046-
root,
2047-
PreOrderFunc,
2048-
DFSDefault,
2049-
AncestorFunc,
2050-
DFSDefault);
2064+
data,
2065+
root,
2066+
PreOrderFunc,
2067+
DFSDefault,
2068+
AncestorFunc,
2069+
DFSDefault);
20512070
return data.result;
20522071
end);
20532072

@@ -2254,9 +2273,10 @@ function(graph)
22542273
record.child := -1;
22552274
record.current := -1;
22562275
record.stop := false;
2257-
record.parent := ListWithIdenticalEntries(DigraphNrVertices(graph), -1);
2258-
record.preorder := ListWithIdenticalEntries(DigraphNrVertices(graph), -1);
2259-
record.postorder := ListWithIdenticalEntries(DigraphNrVertices(graph), -1);
2276+
record.parent := [fail];
2277+
record.preorder := [fail];
2278+
record.postorder := [fail];
2279+
record.edge := [fail];
22602280
return record;
22612281
end);
22622282

@@ -2279,8 +2299,9 @@ end);
22792299
InstallGlobalFunction(ExecuteDFS,
22802300
function(record, data, start, PreOrderFunc, PostOrderFunc, AncestorFunc,
22812301
CrossFunc)
2282-
if not IsEqualSet(RecNames(record), ["stop", "graph", "child", "parent",
2283-
"preorder", "postorder", "current"]) then
2302+
if not IsEqualSet(RecNames(record),
2303+
["stop", "graph", "child", "parent", "preorder",
2304+
"postorder", "current", "edge"]) then
22842305
ErrorNoReturn("the 1st argument <record> must be created with ",
22852306
"NewDFSRecord,");
22862307
fi;

src/dfs.c

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,16 @@ Obj ExecuteDFS(Obj self, Obj args) {
3232
Obj AncestorFunc = ELM_PLIST(args, 6);
3333
Obj CrossFunc = ELM_PLIST(args, 7);
3434

35-
DIGRAPHS_ASSERT(NARG_FUNC(PreorderFunc) == 2);
36-
DIGRAPHS_ASSERT(IS_FUNC(AncestorFunc));
37-
DIGRAPHS_ASSERT(NARG_FUNC(AncestorFunc) == 2);
38-
DIGRAPHS_ASSERT(IS_FUNC(PostOrderFunc));
39-
DIGRAPHS_ASSERT(NARG_FUNC(PostOrderFunc) == 2);
40-
DIGRAPHS_ASSERT(IS_FUNC(PreorderFunc));
4135
DIGRAPHS_ASSERT(IS_PREC(record));
4236
DIGRAPHS_ASSERT(IS_INTOBJ(start));
37+
// DIGRAPHS_ASSERT(NARG_FUNC(PreorderFunc) == 2);
38+
DIGRAPHS_ASSERT(IS_FUNC(PreorderFunc));
39+
DIGRAPHS_ASSERT(IS_FUNC(PostOrderFunc));
40+
// DIGRAPHS_ASSERT(NARG_FUNC(PostOrderFunc) == 2);
41+
DIGRAPHS_ASSERT(IS_FUNC(AncestorFunc));
42+
// DIGRAPHS_ASSERT(NARG_FUNC(AncestorFunc) == 2);
4343
DIGRAPHS_ASSERT(IS_FUNC(CrossFunc));
44-
DIGRAPHS_ASSERT(NARG_FUNC(CrossFunc) == 2);
44+
// DIGRAPHS_ASSERT(NARG_FUNC(CrossFunc) == 2);
4545

4646
Obj D = ElmPRec(record, RNamName("graph"));
4747
Int N = DigraphNrVertices(D);
@@ -51,7 +51,7 @@ Obj ExecuteDFS(Obj self, Obj args) {
5151
"the third argument <start> must be a vertex in your graph,", 0L, 0L);
5252
}
5353
Int top = 0;
54-
Obj stack = NEW_PLIST(T_PLIST_CYC, N);
54+
Obj stack = NEW_PLIST(T_PLIST_CYC, 0);
5555
AssPlist(stack, ++top, start);
5656

5757
UInt preorder_num = 0;
@@ -62,12 +62,14 @@ Obj ExecuteDFS(Obj self, Obj args) {
6262
Obj parent = ElmPRec(record, RNamName("parent"));
6363
Obj postorder = ElmPRec(record, RNamName("postorder"));
6464
Obj preorder = ElmPRec(record, RNamName("preorder"));
65+
Obj edge = ElmPRec(record, RNamName("edge"));
6566

66-
DIGRAPHS_ASSERT(LEN_PLIST(parent) == N);
67-
DIGRAPHS_ASSERT(LEN_PLIST(postorder) == N);
68-
DIGRAPHS_ASSERT(LEN_PLIST(preorder) == N);
67+
DIGRAPHS_ASSERT(LEN_PLIST(parent) == 1);
68+
DIGRAPHS_ASSERT(LEN_PLIST(postorder) == 1);
69+
DIGRAPHS_ASSERT(LEN_PLIST(preorder) == 1);
70+
DIGRAPHS_ASSERT(LEN_PLIST(edge) == 1);
6971

70-
SET_ELM_PLIST(parent, INT_INTOBJ(start), start);
72+
AssPlist(parent, INT_INTOBJ(start), start);
7173

7274
Obj neighbors = FuncOutNeighbours(self, D);
7375
DIGRAPHS_ASSERT(IS_PLIST(neighbors));
@@ -77,22 +79,27 @@ Obj ExecuteDFS(Obj self, Obj args) {
7779
Int RNamStop = RNamName("stop");
7880

7981
while (top > 0) {
82+
if (ElmPRec(record, RNamStop) == True) {
83+
break;
84+
}
8085
current = INT_INTOBJ(ELM_PLIST(stack, top--));
8186
DIGRAPHS_ASSERT(current != 0);
8287
if (current < 0) {
8388
Int child = -1 * current;
8489
AssPRec(record, RNamChild, INTOBJ_INT(child));
8590
AssPRec(record, RNamCurrent, ELM_PLIST(parent, child));
8691
CALL_2ARGS(PostOrderFunc, record, data);
87-
SET_ELM_PLIST(postorder, child, INTOBJ_INT(++postorder_num));
92+
AssPlist(postorder, child, INTOBJ_INT(++postorder_num));
8893
CHANGED_BAG(record);
8994
continue;
90-
} else if (INT_INTOBJ(ELM_PLIST(preorder, current)) > 0) {
95+
} else if (current <= LEN_PLIST(preorder)
96+
&& ELM_PLIST(preorder, current) != 0
97+
&& ELM_PLIST(preorder, current) != Fail) {
9198
continue;
9299
} else {
93100
AssPRec(record, RNamCurrent, INTOBJ_INT(current));
94101
CALL_2ARGS(PreorderFunc, record, data);
95-
SET_ELM_PLIST(preorder, current, INTOBJ_INT(++preorder_num));
102+
AssPlist(preorder, current, INTOBJ_INT(++preorder_num));
96103
CHANGED_BAG(record);
97104
AssPlist(stack, ++top, INTOBJ_INT(-1 * current));
98105
}
@@ -105,11 +112,15 @@ Obj ExecuteDFS(Obj self, Obj args) {
105112
for (UInt j = 0; j < LEN_LIST(succ); ++j) {
106113
UInt v = INT_INTOBJ(ELM_LIST(succ, LEN_LIST(succ) - j));
107114
AssPRec(record, RNamChild, INTOBJ_INT(v));
108-
if (INT_INTOBJ(ELM_PLIST(preorder, v)) == -1) {
109-
SET_ELM_PLIST(parent, v, INTOBJ_INT(current));
115+
if (v > LEN_PLIST(preorder) || ELM_PLIST(preorder, v) == 0
116+
|| ELM_PLIST(preorder, v) == Fail) {
117+
AssPlist(parent, v, INTOBJ_INT(current));
118+
AssPlist(edge, v, INTOBJ_INT(LEN_LIST(succ) - j));
110119
CHANGED_BAG(record);
111120
AssPlist(stack, ++top, INTOBJ_INT(v));
112-
} else if (INT_INTOBJ(ELM_PLIST(postorder, v)) == -1) {
121+
} else if (current > LEN_PLIST(preorder)
122+
|| ELM_PLIST(preorder, current) != 0
123+
|| ELM_PLIST(preorder, current) != Fail) {
113124
CALL_2ARGS(AncestorFunc, record, data);
114125
} else if (INT_INTOBJ(ELM_PLIST(preorder, v))
115126
< INT_INTOBJ(ELM_PLIST(preorder, current))) {

0 commit comments

Comments
 (0)