1: %% 2: %% %CopyrightBegin% 3: %% 4: %% Copyright Ericsson AB 2000-2012. All Rights Reserved. 5: %% 6: %% The contents of this file are subject to the Erlang Public License, 7: %% Version 1.1, (the "License"); you may not use this file except in 8: %% compliance with the License. You should have received a copy of the 9: %% Erlang Public License along with this software. If not, it can be 10: %% retrieved online at http://www.erlang.org/. 11: %% 12: %% Software distributed under the License is distributed on an "AS IS" 13: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 14: %% the License for the specific language governing rights and limitations 15: %% under the License. 16: %% 17: %% %CopyrightEnd% 18: %% 19: -module(digraph_utils_SUITE). 20: 21: %-define(debug, true). 22: -ifdef(debug). 23: -define(line, put(line, ?LINE), ). 24: -else. 25: -include_lib("test_server/include/test_server.hrl"). 26: -endif. 27: 28: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 29: init_per_group/2,end_per_group/2]). 30: 31: -export([simple/1, loop/1, isolated/1, topsort/1, subgraph/1, 32: condensation/1, tree/1]). 33: 34: 35: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 36: 37: suite() -> [{ct_hooks,[ts_install_cth]}]. 38: 39: all() -> 40: [simple, loop, isolated, topsort, subgraph, 41: condensation, tree]. 42: 43: groups() -> 44: []. 45: 46: init_per_suite(Config) -> 47: Config. 48: 49: end_per_suite(_Config) -> 50: ok. 51: 52: init_per_group(_GroupName, Config) -> 53: Config. 54: 55: end_per_group(_GroupName, Config) -> 56: Config. 57: 58: 59: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 60: 61: simple(doc) -> []; 62: simple(suite) -> []; 63: simple(Config) when is_list(Config) -> 64: ?line G = digraph:new(), 65: ?line add_vertices(G, [a]), 66: ?line add_edges(G, [{b,c},{b,d},{e,f},{f,g},{g,e},{h,h},{i,i},{i,j}]), 67: ?line 10 = length(digraph_utils:postorder(G)), 68: ?line 10 = length(digraph_utils:preorder(G)), 69: ?line ok = evall(digraph_utils:components(G), 70: [[a],[b,c,d],[e,f,g],[h],[i,j]]), 71: ?line ok = evall(digraph_utils:strong_components(G), 72: [[a],[b],[c],[d],[e,f,g],[h],[i],[j]]), 73: ?line ok = evall(digraph_utils:cyclic_strong_components(G), 74: [[e,f,g],[h],[i]]), 75: ?line true = path(G, e, e), 76: ?line false = path(G, e, j), 77: ?line false = path(G, a, a), 78: ?line false = digraph_utils:topsort(G), 79: ?line false = digraph_utils:is_acyclic(G), 80: ?line ok = eval(digraph_utils:loop_vertices(G), [h,i]), 81: ?line ok = eval(digraph_utils:reaching([e], G), [e,f,g]), 82: ?line ok = eval(digraph_utils:reaching_neighbours([e], G), [e,f,g]), 83: ?line ok = eval(digraph_utils:reachable([e], G), [e,f,g]), 84: ?line ok = eval(digraph_utils:reachable_neighbours([e], G), [e,f,g]), 85: ?line ok = eval(digraph_utils:reaching([b], G), [b]), 86: ?line ok = eval(digraph_utils:reaching_neighbours([b], G), []), 87: ?line ok = eval(digraph_utils:reachable([b], G), [b,c,d]), 88: ?line ok = eval(digraph_utils:reachable_neighbours([b], G), [c,d]), 89: ?line ok = eval(digraph_utils:reaching([h], G), [h]), 90: ?line ok = eval(digraph_utils:reaching_neighbours([h], G), [h]), 91: ?line ok = eval(digraph_utils:reachable([h], G), [h]), 92: ?line ok = eval(digraph_utils:reachable_neighbours([h], G), [h]), 93: ?line ok = eval(digraph_utils:reachable([e,f], G), [e,f,g]), 94: ?line ok = eval(digraph_utils:reachable_neighbours([e,f], G), [e,f,g]), 95: ?line ok = eval(digraph_utils:reachable([h,h,h], G), [h]), 96: ?line true = digraph:delete(G), 97: ok. 98: 99: loop(doc) -> []; 100: loop(suite) -> []; 101: loop(Config) when is_list(Config) -> 102: ?line G = digraph:new(), 103: ?line add_vertices(G, [a,b]), 104: ?line add_edges(G, [{a,a},{b,b}]), 105: ?line ok = evall(digraph_utils:components(G), [[a],[b]]), 106: ?line ok = evall(digraph_utils:strong_components(G), [[a],[b]]), 107: ?line ok = evall(digraph_utils:cyclic_strong_components(G), [[a],[b]]), 108: ?line [_,_] = digraph_utils:topsort(G), 109: ?line false = digraph_utils:is_acyclic(G), 110: ?line ok = eval(digraph_utils:loop_vertices(G), [a,b]), 111: ?line [_,_] = digraph_utils:preorder(G), 112: ?line [_,_] = digraph_utils:postorder(G), 113: ?line ok = eval(digraph_utils:reaching([b], G), [b]), 114: ?line ok = eval(digraph_utils:reaching_neighbours([b], G), [b]), 115: ?line ok = eval(digraph_utils:reachable([b], G), [b]), 116: ?line ok = eval(digraph_utils:reachable_neighbours([b], G), [b]), 117: ?line true = path(G, a, a), 118: ?line true = digraph:delete(G), 119: ok. 120: 121: isolated(doc) -> []; 122: isolated(suite) -> []; 123: isolated(Config) when is_list(Config) -> 124: ?line G = digraph:new(), 125: ?line add_vertices(G, [a,b]), 126: ?line ok = evall(digraph_utils:components(G), [[a],[b]]), 127: ?line ok = evall(digraph_utils:strong_components(G), [[a],[b]]), 128: ?line ok = evall(digraph_utils:cyclic_strong_components(G), []), 129: ?line [_,_] = digraph_utils:topsort(G), 130: ?line true = digraph_utils:is_acyclic(G), 131: ?line ok = eval(digraph_utils:loop_vertices(G), []), 132: ?line [_,_] = digraph_utils:preorder(G), 133: ?line [_,_] = digraph_utils:postorder(G), 134: ?line ok = eval(digraph_utils:reaching([b], G), [b]), 135: ?line ok = eval(digraph_utils:reaching_neighbours([b], G), []), 136: ?line ok = eval(digraph_utils:reachable([b], G), [b]), 137: ?line ok = eval(digraph_utils:reachable_neighbours([b], G), []), 138: ?line false = path(G, a, a), 139: ?line true = digraph:delete(G), 140: ok. 141: 142: topsort(doc) -> []; 143: topsort(suite) -> []; 144: topsort(Config) when is_list(Config) -> 145: ?line G = digraph:new(), 146: ?line add_edges(G, [{a,b},{b,c},{c,d},{d,e},{e,f}]), 147: ?line ok = eval(digraph_utils:topsort(G), [a,b,c,d,e,f]), 148: ?line true = digraph:delete(G), 149: ok. 150: 151: subgraph(doc) -> []; 152: subgraph(suite) -> []; 153: subgraph(Config) when is_list(Config) -> 154: ?line G = digraph:new([acyclic]), 155: ?line add_edges(G, [{b,c},{b,d},{e,f},{f,fg,fgl,g},{f,fg2,fgl2,g},{g,e}, 156: {h,h},{i,i},{i,j}]), 157: ?line add_vertices(G, [{b,bl},{f,fl}]), 158: ?line SG = digraph_utils:subgraph(G, [u1,b,c,u2,f,g,i,u3]), 159: ?line [b,c,f,g,i] = lists:sort(digraph:vertices(SG)), 160: ?line {b,bl} = digraph:vertex(SG, b), 161: ?line {c,[]} = digraph:vertex(SG, c), 162: ?line {fg,f,g,fgl} = digraph:edge(SG, fg), 163: ?line {fg2,f,g,fgl2} = digraph:edge(SG, fg2), 164: ?line {_, {_, acyclic}} = lists:keysearch(cyclicity, 1, digraph:info(SG)), 165: ?line true = digraph:delete(SG), 166: 167: ?line SG1 = digraph_utils:subgraph(G, [f, g, h], 168: [{type, []}, {keep_labels, false}]), 169: ?line [f,g,h] = lists:sort(digraph:vertices(SG1)), 170: ?line {f,[]} = digraph:vertex(SG1, f), 171: ?line {fg,f,g,[]} = digraph:edge(SG1, fg), 172: ?line {_, {_, cyclic}} = lists:keysearch(cyclicity, 1, digraph:info(SG1)), 173: ?line true = digraph:delete(SG1), 174: 175: ?line SG2 = digraph_utils:subgraph(G, [f, g, h], 176: [{type, [acyclic]}, 177: {keep_labels, true}]), 178: ?line [f,g,h] = lists:sort(digraph:vertices(SG2)), 179: ?line {f,fl} = digraph:vertex(SG2, f), 180: ?line {fg,f,g,fgl} = digraph:edge(SG2, fg), 181: ?line {_, {_, acyclic}} = lists:keysearch(cyclicity, 1, digraph:info(SG2)), 182: ?line true = digraph:delete(SG2), 183: 184: ?line {'EXIT',{badarg,_}} = 185: (catch digraph_utils:subgraph(G, [f], [{invalid, opt}])), 186: ?line {'EXIT',{badarg,_}} = 187: (catch digraph_utils:subgraph(G, [f], [{keep_labels, not_Bool}])), 188: ?line {'EXIT',{badarg,_}} = 189: (catch digraph_utils:subgraph(G, [f], [{type, not_type}])), 190: ?line {'EXIT',{badarg,_}} = 191: (catch digraph_utils:subgraph(G, [f], [{type, [not_type]}])), 192: ?line {'EXIT',{badarg,_}} = 193: (catch digraph_utils:subgraph(G, [f], not_a_list)), 194: 195: ?line true = digraph:delete(G), 196: 197: ok. 198: 199: condensation(doc) -> []; 200: condensation(suite) -> []; 201: condensation(Config) when is_list(Config) -> 202: ?line G = digraph:new([]), 203: ?line add_edges(G, [{b,c},{b,d},{e,f},{f,fg,fgl,g},{f,fg2,fgl2,g},{g,e}, 204: {h,h},{j,i},{i,j}]), 205: ?line add_vertices(G, [q]), 206: ?line CG = digraph_utils:condensation(G), 207: ?line Vs = sort_2(digraph:vertices(CG)), 208: ?line [[b],[c],[d],[e,f,g],[h],[i,j],[q]] = Vs, 209: ?line Fun = fun(E) -> 210: {_E, V1, V2, _L} = digraph:edge(CG, E), 211: {lists:sort(V1), lists:sort(V2)} 212: end, 213: ?line Es = lists:map(Fun, digraph:edges(CG)), 214: ?line [{[b],[c]},{[b],[d]}] = lists:sort(Es), 215: ?line true = digraph:delete(CG), 216: ?line true = digraph:delete(G), 217: ok. 218: 219: tree(doc) -> ["OTP-7081"]; 220: tree(suite) -> []; 221: tree(Config) when is_list(Config) -> 222: ?line false = is_tree([], []), 223: ?line true = is_tree([a], []), 224: ?line false = is_tree([a,b], []), 225: ?line true = is_tree([{a,b}]), 226: ?line false = is_tree([{a,b},{b,a}]), 227: ?line true = is_tree([{a,b},{a,c},{b,d},{b,e}]), 228: ?line false = is_tree([{a,b},{a,c},{b,d},{b,e}, {d,e}]), 229: ?line false = is_tree([{a,b},{a,c},{b,d},{b,e}, {b,e}]), 230: ?line true = is_tree([{a,c},{c,b}]), 231: ?line true = is_tree([{b,a},{c,a}]), 232: %% Parallel edges. Acyclic and with one componets 233: %% (according to the digraph module). 234: ?line false = is_tree([{a,b},{a,b}]), 235: 236: ?line no = arborescence_root([], []), 237: ?line {yes, a} = arborescence_root([a], []), 238: ?line no = arborescence_root([a,b], []), 239: ?line {yes, a} = arborescence_root([{a,b}]), 240: ?line no = arborescence_root([{a,b},{b,a}]), 241: ?line {yes, a} = arborescence_root([{a,b},{a,c},{b,d},{b,e}]), 242: ?line no = arborescence_root([{a,b},{a,c},{b,d},{b,e}, {d,e}]), 243: ?line no = arborescence_root([{a,b},{a,c},{b,d},{b,e}, {b,e}]), 244: ?line {yes, a} = arborescence_root([{a,c},{c,b}]), 245: ?line no = arborescence_root([{b,a},{c,a}]), 246: 247: ?line false = is_arborescence([], []), 248: ?line true = is_arborescence([a], []), 249: ?line false = is_arborescence([a,b], []), 250: ?line true = is_arborescence([{a,b}]), 251: ?line false = is_arborescence([{a,b},{b,a}]), 252: ?line true = is_arborescence([{a,b},{a,c},{b,d},{b,e}]), 253: ?line false = is_arborescence([{a,b},{a,c},{b,d},{b,e}, {d,e}]), 254: ?line false = is_arborescence([{a,b},{a,c},{b,d},{b,e}, {b,e}]), 255: ?line true = is_arborescence([{a,c},{c,b}]), 256: ?line false = is_arborescence([{b,a},{c,a}]), 257: 258: %% Parallel edges. 259: ?line false = is_arborescence([{a,b},{a,b}]), 260: 261: ok. 262: 263: is_tree(Es) -> 264: is_tree([], Es). 265: 266: is_tree(Vs, Es) -> 267: gu(Vs, Es, is_tree). 268: 269: is_arborescence(Es) -> 270: is_arborescence([], Es). 271: 272: is_arborescence(Vs, Es) -> 273: gu(Vs, Es, is_arborescence). 274: 275: arborescence_root(Es) -> 276: arborescence_root([], Es). 277: 278: arborescence_root(Vs, Es) -> 279: gu(Vs, Es, arborescence_root). 280: 281: gu(Vs, Es, F) -> 282: G = digraph:new(), 283: add_vertices(G, Vs), 284: add_edges(G, Es), 285: Reply = digraph_utils:F(G), 286: true = digraph:delete(G), 287: Reply. 288: 289: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 290: 291: sort_2(L) -> 292: lists:sort(lists:map(fun(V) -> lists:sort(V) end, L)). 293: 294: path(G, V1, V2) -> 295: digraph:get_path(G, V1, V2) /= false. 296: 297: add_vertices(G, Vs) -> 298: lists:foreach(fun({V, Label}) -> digraph:add_vertex(G, V, Label); 299: (V) -> digraph:add_vertex(G, V) 300: end, Vs). 301: 302: add_edges(G, L) -> 303: Fun = fun({From, To}) -> 304: digraph:add_vertex(G, From), 305: digraph:add_vertex(G, To), 306: digraph:add_edge(G, From, To); 307: ({From, Edge, Label, To}) -> 308: digraph:add_vertex(G, From), 309: digraph:add_vertex(G, To), 310: digraph:add_edge(G, Edge, From, To, Label) 311: end, 312: lists:foreach(Fun, L). 313: 314: eval(L, E) -> 315: Expected = lists:sort(E), 316: Got = lists:sort(L), 317: if 318: Expected == Got -> 319: ok; 320: true -> 321: not_ok 322: end. 323: 324: evall(L, E) -> 325: F = fun(L1) -> lists:sort(L1) end, 326: Fun = fun(LL) -> F(lists:map(F, LL)) end, 327: 328: Expected = Fun(E), 329: Got = Fun(L), 330: if 331: Expected == Got -> 332: ok; 333: true -> 334: not_ok 335: end.