如何在 Erlang 中编写模拟?

发布于 2024-08-24 08:20:56 字数 800 浏览 10 评论 0原文

我想在 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 中解决这个问题吗?

感谢您的帮助。

I want to do some numerical stuff in Erlang like this:

You've got an array with the following values:

[2,3,4]

In each iteration, you calculate

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

This becomes the new [n].

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

So I try an example:

[2,3,4]

calculations:

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

So [2,3,4] becomes to [2, 3.1, 3.1] after one iteration.

I know how to write this in a non-functional language like C.
But I have difficulties to imagine, how this could be done in Erlang.
I found some tutorials on how you read a file to a list. So this
is not the problem.

How can I spawn different Erlang processes that each process has one element of the list?
How can I do calculations by communicating with 'the neighbors', so that the neighbors know where their neigbors are generically, without specifying each?
How can I collect the data into a list?

Eventually, is it possible to solve that problem in Erlang at all?

Thanks for your help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

咆哮 2024-08-31 08:20:56

原始问题的答案:

-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.

Answer for original question:

-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.

Generalized answer for arbitrary list lengths:

-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.
莫多说 2024-08-31 08:20:56

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

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

谢谢你的所有提示。他们真的很有帮助。
我做这个模拟只是为了好玩:)。我用 C 语言进行了这样的模拟。我只是想知道它是否可以在 Erlang 中动态地工作。

That iterate pattern is great. But what do you do, if the list has more elements than three and every member needs his neighbors? This example would be more dynamic.
Functional programming is a different way of thinking. But I think - as a novice - that it has the same potential as C.
What shall I do, when I want to write:

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

Thanks for all your hints. They are really helpful.
I'm doing this simulation just for fun :). I worked on such a simulation in C. And I just wondered whether it would work dynamically in Erlang.

仙女山的月亮 2024-08-31 08:20:56

这绝对是可能的(但如果您想做的是纯数值计算,您可能需要重新考虑,除非这是您追求的智力练习 - 或者您可以考虑使用像 http://discoproject.org/)。

然而,您似乎还没有完全掌握在 Erlang 中进行进程编程的基本技术,所以我建议您从这里开始。 (例如,获取乔·阿姆斯特朗(Joe Armstrong)的书并尝试其中的示例。)一旦您进入其中(这不会花费很长时间),您应该不会遇到太多困难来找出构建此类程序的一些不同方法。

It's absolutely possible (but if it's pure numerical calculations you want to do, you might want to reconsider, unless it's the intellectual exercise you're after - or you could look at using a framework like http://discoproject.org/).

However, it seems that you haven't quite picked up the basic techniques of programming with processes in Erlang yet, so I suggest you start with that. (For example, get Joe Armstrong's book and play around with the examples.) Once you get into it - which doesn't take long - you shouldn't have much trouble figuring out some different ways of structuring such a program.

心欲静而疯不止 2024-08-31 08:20:56

我会尝试使用标准函数模式来处理列表

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]);
...

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

I would try the standard function pattern for processing a list

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

and extend it to use three values in its pattern as appropriate to deal with the three values your formula processes into the new value:

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

Of course, this needs a few extra function clauses to properly deal with the beginning and the end of the list.

老娘不死你永远是小三 2024-08-31 08:20:56

我尝试了一些东西,但失败了。下面的代码应该为每个列表元素生成一个进程,但不知何故,如果我给它一个包含 4 个元素的列表,它不会停止创建进程并崩溃。我认为发生错误的部分用 %BUG 标记。
模拟:模拟/ 2开始一切,即模拟:模拟([1,2,3,4],7),其中7是迭代次数。数字为 0 的元素是单独创建的,因为它永远不应该改变它的值。进程应该获取前一个和下一个邻居的 PID,以便它们可以交换它们的值。我尝试使用调试器 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).

I tried something, but failed. The following code should spawn one process per list element but somehow if I give it a list of 4 elements, it will not stop creating processes and crash then. The part where the bug - I think - occurs is marked with %BUG.
simulation:simulate/2 starts everything, i.e. simulation:simulate([1,2,3,4],7), where 7 is the number of iterations. The element with the number 0 is created separately because it should never change it's value. The processes should get the PID of there previous and next neighbours so that they can exchange their values. I tried to debug it with the debuger im(). But it crashes. I saw that too many processes are created. Somehow, I don't find the mistake at the moment. Perhaps you notice something that's totally wrong?

-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).
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文