Как я могу написать симуляции в Erlang? - PullRequest
3 голосов
/ 05 марта 2010

Я хочу сделать некоторые числовые вещи в 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, чтобы у каждого процесса был один элемент списка?Как я могу делать вычисления, общаясь с «соседями», чтобы соседи знали, где находятся их соседи, без указания каждого?Как мне собрать данные в список?

В конце концов, возможно ли вообще решить эту проблему в Эрланге?

Спасибо за вашу помощь.

Ответы [ 5 ]

3 голосов
/ 05 марта 2010

Ответ на оригинальный вопрос:

-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 голос
/ 06 марта 2010

Эта итерационная модель великолепна. Но что вы делаете, если в списке больше элементов, чем три, и каждому члену нужны его соседи? Этот пример будет более динамичным. Функциональное программирование - это другой способ мышления. Но я думаю - как новичок - что у него такой же потенциал, как у C. Что мне делать, когда я хочу написать:

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

Спасибо за все ваши подсказки. Они действительно полезны. Я делаю этот симулятор просто для удовольствия :). Я работал над такой симуляцией в C. И мне просто было интересно, будет ли она динамически работать в Erlang.

0 голосов
/ 17 марта 2010

Я что-то пробовал, но не получилось. Следующий код должен порождать один процесс на элемент списка, но каким-то образом, если я дам ему список из 4 элементов, он не остановит создание процессов и crash тогда Часть, где ошибка - я думаю - происходит, отмечена как% BUG. Simulation: Simulate / 2 запускает все, то есть Simulation: Simulate ([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).
0 голосов
/ 15 марта 2010

Я бы попробовал стандартный шаблон функции для обработки списка

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

Конечно, для правильной работы с началом и концом списка необходимы несколько дополнительных функциональных предложений.

0 голосов
/ 05 марта 2010

Это абсолютно возможно (но если вы хотите делать чисто численные расчеты, вам может потребоваться пересмотреть их, если только это не интеллектуальное упражнение, к которому вы стремитесь - или вы можете посмотреть на использование фреймворка, подобного http://discoproject.org/).

Однако, похоже, вы еще не освоили базовые приемы программирования с процессами в Erlang, поэтому я предлагаю вам начать с этого. (Например, возьмите книгу Джо Армстронга и поэкспериментируйте с примерами.) Как только вы разберетесь с ней - что не займет много времени - у вас не должно возникнуть особых проблем с поиском различных способов структурирования такой программы.

...