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.