如何在Erlang中编写模拟?

时间:2010-03-05 11:31:58

标签: list functional-programming erlang process simulation

我想在Erlang中做一些像这样的数字:

你有一个包含以下值的数组:

[2,3,4]

在每次迭代中,您计算​​

0.1 * [n-1] + 0.7 *[n] + 0.2 * [n+1]

这成为new [n]

If n == 0 then [n-1] = 0. If [n] == length of array then [n] = 0.

所以我试了一个例子:

[2,3,4]

计算:

  

0.1 * 0 + 0.7 * 2 + 0.2 * 3 = 2

     

0.1 * 2 + 0.7 * 3 + 0.2 * 4 = 3.1

     

0.1 * 3 + 0.7 * 4 + 0.2 * 0 = 3.1

所以[2,3,4]在一次迭代后变为[2, 3.1, 3.1]

我知道如何用像C这样的非功能性语言来写这个。 但我很难想象,如何在Erlang中完成。 我找到了一些关于如何将文件读入列表的教程。所以这 不是问题。

如何生成不同的Erlang进程,每个进程都有一个列表元素? 如何通过与“邻居”进行交流来进行计算,以便邻居知道他们的邻居在哪里,而不指定每个? 如何将数据收集到列表中?

最终,是否有可能在Erlang中解决这个问题?

感谢您的帮助。

5 个答案:

答案 0 :(得分:3)

回答原始问题:

-module(simulation).
-export([start/0]).

f([N0, N1, N2]) ->
    M0 =            0.7 * N0 + 0.2 * N1,
    M1 = 0.1 * N0 + 0.7 * N1 + 0.2 * N2,
    M2 = 0.1 * N1 + 0.7 * N2,
    [M0, M1, M2].

iterate(List, Iterations) ->
    iterate(1, List, Iterations).

iterate(_Iteration, List, 0) ->
    List;
iterate(Iteration, List = [N0, N1, N2], MoreIterations) ->
    io:format("~.5f  ~.5f  ~.5f~n", [N0, N1, N2]),
    NextList = f(List),
    iterate(Iteration + 1, NextList, MoreIterations-1).

start() ->
    iterate([2.0, 3.0, 4.0], 10),
    ok.

任意列表长度的广义答案:

-module(simulation2).
-export([start/0]).

f(Prev, Current, Next) ->
    0.1 * Prev + 0.7 * Current + 0.2 * Next.

transform(List) ->
    transform(0.0, List, 0.0).

transform(_First, [], _Last) ->
    [];
transform(First, [X], Last) ->
    Y = f(First, X, Last),
    [Y];
transform(First, [X1, X2 | More], Last) ->
    Y1 = f(First, X1, X2),
    [Y1 | transform(X1, [X2 | More], Last)].

iterate(List, Iterations) ->
    iterate(1, List, Iterations).

iterate(_Iteration, List, 0) ->
    List;
iterate(Iteration, List, MoreIterations) ->
    io:format("~p~n", [List]),
    NextList = transform(List),
    iterate(Iteration + 1, NextList, MoreIterations-1).

start() ->
    iterate([1.0, 2.0, 3.0, 4.0, 5.0], 10),
    ok.

答案 1 :(得分:1)

迭代模式很棒。但是,如果列表中的元素多于三个并且每个成员都需要他的邻居,那么你会怎么做?这个例子会更有活力。 功能编程是一种不同的思维方式。但我认为 - 作为一个新手 - 它具有与C相同的潜力。 当我想写的时候,我该怎么办:

start() ->
    iterate([2.0, 3.0, 4.0, 5.0, ...], 10),
    ok.

感谢你的所有提示。他们真的很有帮助。 我正在做这个模拟只是为了好玩:)。我在C中进行了这样的模拟。我只是想知道它是否能在Erlang中动态运行。

答案 2 :(得分:0)

这绝对是可能的(但如果你想做的是纯粹的数值计算,你可能想重新考虑,除非你正在进行智力练习 - 或者你可以看看使用像http://discoproject.org/这样的框架)。

但是,你似乎还没有完全掌握在Erlang中使用进程编程的基本技术,所以我建议你从这开始。 (例如,获取Joe Armstrong的书并使用这些例子。)一旦你进入它 - 这不需要很长时间 - 你应该不会有很多麻烦找出构建这样一个程序的一些不同方法。

答案 3 :(得分:0)

我会尝试标准功能模式来处理列表

iter([], Acc) ->
    lists:reverse(Acc);
iter([H|Tail], Acc) ->
    iter(Tail, [do_something_with(H)|Acc]).

并将其扩展为在其模式中使用三个值,以处理公式处理为新值的三个值:

...
iter([H1,H2,H3|Tail], Acc) ->
    iter([H2,H3|Tail], [do_something_with(H1,H2,H3)|Acc]);
...

当然,这需要一些额外的函数子句来正确处理列表的开头和结尾。

答案 4 :(得分:0)

我尝试了一些东西,但失败了。下面的代码应该为每个列表元素生成一个进程,但不知怎的,如果我给它一个4个元素的列表,它将不会停止创建进程,然后崩溃。错误 - 我认为 - 发生的部分标有%BUG。 模拟:模拟/ 2开始一切,即模拟:模拟([1,2,3,4],7),其中7是迭代次数。编号为0的元素是单独创建的,因为它永远不会更改它的值。进程应该获得前一个和下一个邻居的PID,以便它们可以交换它们的值。我尝试使用debuger im()调试它。但它崩溃了。我看到创建了太多进程。不知怎的,我现在没有发现错误。也许你注意到一些完全错误的东西?

-module(simulation).
-compile(export_all).
%-export().

f(Prev, Current, Next) ->
    0.1 * Prev + 0.7 * Current + 0.2 * Next.

simulate([], _Iteration) -> [];
simulate([X], 0) -> [X];
simulate([X], Iteration) -> simulate([f(0.0, X, 0.0)], Iteration - 1);
simulate(Liste, 0) -> Liste;
simulate(Liste, Iteration) ->
    PidStarter = self(),
    {Number, ProcList} = startProcesses(Liste, Iteration, PidStarter), %BUG
    Connector = spawn(fun() -> simProcessStarter(0.0, PidStarter, Iteration, 0) end), %untested
    [H1, H2 | _] = ProcList,
    H1 ! {startinformation, Connector, H2}, %untested
    ReversedProcList = lists:reverse(ProcList),
    [L1, L2 | _] = ReversedProcList,
    L1 ! {startinformation, L2, Connector},%untested
    fold(ProcList),%untested
    evaluate(Number, []).%untested

fold([]) -> ready;
fold([_X1]) -> ready;
fold([_X1, _X2]) -> ready;
fold([X1, X2, X3 | Tail]) ->
    X2 ! {statusinformation, X1, X3},
    fold([X2, X3 | Tail]).

evaluate(0, List) ->
    List;
evaluate(N, List) ->
    receive 
        {N, Current} -> 
            Result = [Current | List]
    end,
    evaluate(N-1, Result).

% returns {number of processes, list of processes started}
startProcesses(Liste, Iteration, PidStarter) -> startProcesses(Liste, 0, Iteration, [], PidStarter).

startProcesses([], N, _Iteration, List, _PidStarter) -> {N, lists:reverse(List)};
startProcesses([H | T], N, Iteration, List, PidStarter) ->
    startProcesses([T], N + 1, Iteration, [spawn(fun() -> simProcessStarter(H, PidStarter, Iteration, N + 1) end) | List], PidStarter).

simProcessStarter(Current, PidStarter, Iteration, Number) ->
    receive 
        {startinformation, PidPrev, PidNext} -> 
            Result = simProcess(Current, PidPrev, self(), PidNext, Iteration, Number)
    end,
    PidStarter ! Result.

simProcess(Current, _PidPrev, _PidCurrent, _PidNext, 0, Number) ->
    {Number, Current};
simProcess(Current, PidPrev, PidCurrent, PidNext, Iteration, Number) ->
    PidNext ! {prev, PidCurrent, Current, Iteration},
    receive
        {prev, PidPrev, Prev, Iteration} -> Prev
    end,
    PidPrev ! {next, PidCurrent, Current, Iteration},
    receive
        {next, PidNext, Next, Iteration} -> Next
    end,
    New = f(Prev, Current, Next),
    simProcess(New, PidPrev, PidCurrent, PidNext, Iteration-1, Number).