ebb_run.erl 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. -module(ebb_run).
  2. -include("../include/ebb_prim.hrl").
  3. %%% Evaulation
  4. -export([linearize/1, run_linear/2, run_linear/1]).
  5. %%% Simplification
  6. -export([simpl/1]).
  7. %%%-----------------------------------------------------------------------------
  8. %%% Evaluation
  9. %%%-----------------------------------------------------------------------------
  10. linearize(Op) ->
  11. fun(Args) -> run_linear(Op, Args) end.
  12. run_linear(Op) ->
  13. run_linear(Op, []).
  14. run_linear(Op, Args) ->
  15. case ebb_prim:is_operation(Op) andalso
  16. ebb_prim:in_arity(Op) == length(Args) of
  17. true -> do_run_linear(Op, Args);
  18. false -> erlang:error(badargs, [Op, Args])
  19. end.
  20. do_run_linear(#value{value=X}, []) ->
  21. list_output(X);
  22. do_run_linear(#func{code=F}, Args) ->
  23. list_output(apply(F, Args));
  24. do_run_linear(#pipe{ops=Ops}, Args) ->
  25. lists:foldl(fun do_run_linear/2, Args, Ops);
  26. do_run_linear(#par{ops=Ops}, Args) ->
  27. {Result, []} =
  28. lists:foldl(
  29. fun(Op, {Results, Remaining}) ->
  30. {Args1, Rest} = lists:split(ebb_prim:in_arity(Op), Remaining),
  31. {[do_run_linear(Op, Args1) | Results], Rest}
  32. end,
  33. {[], Args}, Ops),
  34. lists:append(lists:reverse(Result));
  35. do_run_linear(#route{map=M}, Args) ->
  36. [ lists:nth(I, Args) || I <- M ];
  37. do_run_linear(#sync{}, Args) ->
  38. Args;
  39. do_run_linear(#split{}, Args) ->
  40. Args;
  41. do_run_linear(#merge{}, Args) ->
  42. Args;
  43. do_run_linear(#switch{map=M}, [Tag | Args]) ->
  44. do_run_linear(element(2, lists:keyfind(Tag, 1, M)), Args).
  45. list_output(X) ->
  46. if is_list(X) -> X;
  47. is_tuple(X) -> tuple_to_list(X);
  48. true -> [X]
  49. end.
  50. %%%-----------------------------------------------------------------------------
  51. %%% Simplification
  52. %%%-----------------------------------------------------------------------------
  53. simpl(Pipe = #pipe{ops=Inside}) ->
  54. flatten(Pipe#pipe{ops=simpl_pipe([ simpl(O) || O <- Inside ])});
  55. simpl(Par = #par{ops=Inside}) ->
  56. flatten(Par#par{ops=simpl_par([ simpl(O) || O <- Inside ])});
  57. simpl(Switch = #switch{map=Map}) ->
  58. Switch#switch{map=[ {Tag, simpl(Op)} || {Tag, Op} <- Map ]};
  59. simpl(Op) ->
  60. case ebb_prim:is_operation(Op) of
  61. true -> Op;
  62. false -> erlang:error(badarg, [Op])
  63. end.
  64. simpl_pipe(Ops) ->
  65. lists:reverse(lists:foldl(fun simpl_pipe/2, [], Ops)).
  66. simpl_pipe(#pipe{ops=Ops}, Acc) ->
  67. lists:reverse(Ops, Acc);
  68. simpl_pipe(Par = #par{}, [Any | Acc]) ->
  69. simpl_pipe_par(Any, Par) ++ Acc;
  70. simpl_pipe(R2 = #route{in=N}, Acc) ->
  71. case {R2 == ebb_flow:id(N), Acc} of
  72. {true, _} -> Acc;
  73. {false, [R1 = #route{} | Rest]} ->
  74. R3 = #route{in=N3} = simpl_pipe_route(R1, R2),
  75. case R3 == ebb_flow:id(N3) of
  76. true -> Rest;
  77. false -> [R3 | Rest]
  78. end;
  79. {false, _} -> [R2 | Acc]
  80. end;
  81. simpl_pipe(#split{size=N}, [#merge{size=N} | Acc]) ->
  82. Acc;
  83. simpl_pipe(#merge{size=N}, [#split{size=N} | Acc]) ->
  84. Acc;
  85. simpl_pipe(Op, Acc) ->
  86. [Op | Acc].
  87. simpl_pipe_par(Par1 = #par{ops=Ops1}, Par2 = #par{ops=Ops2}) ->
  88. case zip_pars(Ops1, Ops2) of
  89. [{Ops1, Ops2}] -> [Par2, Par1];
  90. Zip -> [permute_pipe_par(Zip)]
  91. end;
  92. simpl_pipe_par(Any, Par = #par{ops=Ops}) ->
  93. case zip_pars([Any], Ops) of
  94. [{Any, Ops}] -> [Any, Par];
  95. Zip -> [permute_pipe_par(Zip)]
  96. end.
  97. permute_pipe_par(Zip) ->
  98. ebb_prim:par(
  99. lists:flatten(
  100. [ case {O1, O2} of
  101. {[_|_], [_|_]} ->
  102. [simpl(ebb_prim:pipe(
  103. [ flatten(ebb_prim:par(X))
  104. || X <- [O1, O2] ]))];
  105. {_, _} -> [O1, O2]
  106. end
  107. || {O1, O2} <- Zip ])).
  108. zip_pars(Par1, Par2) ->
  109. zip_pars(1, Par1, [], 1, Par2, [], []).
  110. zip_pars(_, _Par1 = [], Prev1,
  111. _, Par2, Prev2,
  112. Acc) ->
  113. lists:reverse([ {lists:reverse(Prev1), lists:reverse(Prev2, Par2)} | Acc ]);
  114. zip_pars(_, Par1, Prev1,
  115. _, _Par2 = [], Prev2,
  116. Acc) ->
  117. lists:reverse([ {lists:reverse(Prev1, Par1), lists:reverse(Prev2)} | Acc ]);
  118. zip_pars(M, _Par1 = [Op1|Rest1], Prev1,
  119. N, _Par2 = [Op2|Rest2], Prev2,
  120. Acc) ->
  121. case {M+ebb_prim:out_arity(Op1), N+ebb_prim:in_arity(Op2), Prev2} of
  122. {_, N, []} ->
  123. zip_pars(M, [Op1|Rest1], Prev1,
  124. N, Rest2, [],
  125. [ {[], Op2} | Acc ]);
  126. {I, I, _} ->
  127. zip_pars(I, Rest1, [],
  128. I, Rest2, [],
  129. [ {lists:reverse([Op1|Prev1]), lists:reverse([Op2|Prev2])}
  130. | Acc ]);
  131. {M2, N2, _} when M2 < N2 ->
  132. zip_pars(M2, Rest1, [Op1|Prev1],
  133. N, [Op2|Rest2], Prev2,
  134. Acc);
  135. {M2, N2, _} when N2 < M2 ->
  136. zip_pars(M, [Op1|Rest1], Prev1,
  137. N2, Rest2, [Op2|Prev2],
  138. Acc)
  139. end.
  140. simpl_pipe_route(#route{in=In, map=M1}, #route{map=M2}) ->
  141. ebb_prim:route(In, [ lists:nth(I, M1) || I <- M2 ]).
  142. simpl_par(Ops) ->
  143. lists:reverse(lists:foldl(fun simpl_par/2, [], Ops)).
  144. simpl_par(#par{ops=Ops}, Acc) ->
  145. lists:reverse(Ops, Acc);
  146. simpl_par(#route{in=0, out=0, map=[]}, Acc) ->
  147. Acc;
  148. simpl_par(R2 = #route{}, [R1 = #route{} | Acc]) ->
  149. [simpl_par_route(R1, R2) | Acc];
  150. simpl_par(Op, Acc) ->
  151. [Op | Acc].
  152. simpl_par_route(#route{in=In1, map=M1}, #route{in=In2, map=M2}) ->
  153. ebb_prim:route(In1+In2,
  154. lists:append(M1, [ S2+In1 || S2 <- M2 ])).
  155. flatten(#pipe{in=N, out=N, ops=[]}) ->
  156. ebb_flow:id(N);
  157. flatten(#pipe{ops=[Single]}) ->
  158. Single;
  159. flatten(#par{in=N, out=N, ops=[]}) ->
  160. ebb_flow:id(N);
  161. flatten(#par{ops=[Single]}) ->
  162. Single;
  163. flatten(Op) ->
  164. Op.