Przeglądaj źródła

Added the ebb_run module for simplification and evaluation of operations.

Paul Downen 14 lat temu
rodzic
commit
c43fe3c918
1 zmienionych plików z 129 dodań i 0 usunięć
  1. 129 0
      src/ebb_run.erl

+ 129 - 0
src/ebb_run.erl

@@ -0,0 +1,129 @@
+-module(ebb_run).
+-include("../include/ebb_prim.hrl").
+
+%%% Evaulation
+-export([linearize/1, run_linear/2, run_linear/1]).
+
+%%% Simplification
+-export([simpl/1]).
+
+%%%-----------------------------------------------------------------------------
+%%% Evaluation
+%%%-----------------------------------------------------------------------------
+
+linearize(Op) ->
+    fun(Args) -> run_linear(Op, Args) end.
+
+run_linear(Op) ->
+    run_linear(Op, []).
+
+run_linear(Op, Args) ->
+    case ebb_prim:is_operation(Op) andalso
+	ebb_prim:in_arity(Op) == length(Args) of
+	true  -> do_run_linear(Op, Args);
+	false -> erlang:error(badargs, [Op, Args])
+    end.
+
+do_run_linear(#value{value=X}, []) ->
+    list_output(X);
+do_run_linear(#func{code=F}, Args) ->
+    list_output(apply(F, Args));
+do_run_linear(#pipe{ops=Ops}, Args) ->
+    lists:foldl(fun do_run_linear/2, Args, Ops);
+do_run_linear(#par{ops=Ops}, Args) ->
+    {Result, []} =
+	lists:foldl(
+	  fun(Op, {Results, Remaining}) ->
+		  {Args1, Rest} = lists:split(ebb_prim:in_arity(Op), Remaining),
+		  {[do_run_linear(Op, Args1) | Results], Rest}
+	  end,
+	  {[], Args}, Ops),
+    lists:append(lists:reverse(Result));
+do_run_linear(#route{map=M}, Args) ->
+    [ lists:nth(I, Args) || I <- M ];
+do_run_linear(#sync{}, Args) ->
+    Args;
+do_run_linear(#split{}, Args) ->
+    Args;
+do_run_linear(#merge{}, Args) ->
+    Args;
+do_run_linear(#switch{map=M}, [Tag | Args]) ->
+    do_run_linear(element(2, lists:keyfind(Tag, 1, M)), Args).
+
+list_output(X) ->
+    if is_list(X) -> X;
+       is_tuple(X) -> tuple_to_list(X);
+       true -> [X]
+    end.
+    
+%%%-----------------------------------------------------------------------------
+%%% Simplification
+%%%-----------------------------------------------------------------------------
+
+simpl(Op = #pipe{ops=Inside}) ->
+    flatten(Op#pipe{ops=simpl_pipe([ simpl(O) || O <- Inside ])});
+simpl(Op = #par{ops=Inside}) ->
+    flatten(Op#par{ops=simpl_par([ simpl(O) || O <- Inside ])});
+simpl(Op) ->
+    Op.
+
+simpl_pipe(Ops) ->
+    lists:reverse(lists:foldl(fun simpl_pipe/2, [], Ops)).
+
+simpl_pipe(#pipe{ops=Ops}, Acc) ->
+    lists:reverse(Ops, Acc);
+simpl_pipe(Par2 = #par{}, [Par1 = #par{} | Acc]) ->
+    lists:append(simpl_pipe_par(Par1, Par2), Acc);
+simpl_pipe(R2 = #route{in=N}, Acc) ->
+    case {R2 == ebb_flow:id(N), Acc} of
+	{true, _} -> Acc;
+	{false, [R1 = #route{} | Rest]} ->
+	    [simpl_pipe_route(R1, R2) | Rest];
+	{false, _} -> [R2 | Acc]
+    end;
+simpl_pipe(#split{size=N}, [#merge{size=N} | Acc]) ->
+    Acc;
+simpl_pipe(#merge{size=N}, [#split{size=N} | Acc]) ->
+    Acc;
+simpl_pipe(Op, Acc) ->
+    [Op | Acc].
+
+simpl_pipe_par(Par1 = #par{in=In, ops=Ops1}, Par2 = #par{out=Out, ops=Ops2}) ->
+    ZOps = lists:zip(Ops1, Ops2),
+    Match = lists:all(fun({O1,O2}) -> ebb_prim:can_connect(O1, O2) end, ZOps),
+    case Match of
+	true -> [#par{in=In, out=Out,
+		      ops=[ ebb_prim:pipe([O1,O2]) || {O1, O2} <- ZOps ]}];
+	false -> [Par1, Par2]
+    end.
+
+simpl_pipe_route(#route{in=In, map=M1}, #route{out=Out, map=M2}) ->
+    #route{in=In, out=Out, map=[ lists:nth(I, M1) || I <- M2 ]}.
+
+simpl_par(Ops) ->
+    lists:reverse(lists:foldl(fun simpl_par/2, [], Ops)).
+
+simpl_par(#par{ops=Ops}, Acc) ->
+    lists:reverse(Ops, Acc);
+simpl_par(#route{in=0, out=0, map=[]}, Acc) ->
+    Acc;
+simpl_par(R2 = #route{}, [R1 = #route{} | Acc]) ->
+    [simpl_par_route(R1, R2) | Acc];
+simpl_par(Op, Acc) ->
+    [Op | Acc].
+
+simpl_par_route(#route{in=In1, out=Out1, map=M1},
+		#route{in=In2, out=Out2, map=M2}) ->
+    #route{in=In1+In2, out=Out1+Out2,
+	   map=lists:append(M1, [ S2+In1 || S2 <- M2 ])}.
+
+flatten(#pipe{in=N, out=N, ops=[]}) ->
+    ebb_flow:id(N);
+flatten(#pipe{ops=[Single]}) ->
+    Single;
+flatten(#par{in=N, out=N, ops=[]}) ->
+    ebb_flow:id(N);
+flatten(#par{ops=[Single]}) ->
+    Single;
+flatten(Op) ->
+    Op.