Problem27 -並列版-

30分プログラム、その299。- Problem27を並列で計算するように書き直した。
計算が遅いので、並列で計算して力づくで解いてしまう戦略。一応、並列版のmapを定義したり、io:formatがボトルネックにならないように別プロセスで出力するようにしたいりと、工夫はしてある。
それだけで、たいぶ時間がかかってしまったので、実際にマルチコアマシンで走らせるのはまた明日。

使い方

$ erlc problem27.erl
$ erl -noshell -s problem27 main 999

ソースコード

-module(log).
-compile([export_all]).

loop() ->
    receive
	{Format,Args} ->
	    io:format(Format,Args),
	    loop()
    end.

start() ->
    register(log,spawn(fun loop/0)).

log(Format,Args) ->
    log ! {Format,Args}.
-module(problem27).
-compile([export_all]).

poly(A,B,N) ->
    N*N + A*N + B.

times(N,F) ->
    M = F(N),
    case lists:member(M,prime_srv:get(M)) of
	true ->
	    times(N+1,F);
	_ ->
	    N
    end.
    
times(F) ->
    times(0,F).

combination(As,Bs) ->
    lists:flatmap(
      fun(A)-> lists:map(fun (B)-> {A,B} end,Bs) end,
      As).

split(N,Xs) ->
    try lists:split(N,Xs) of
	{Ys,Zs} -> [Ys|split(N,Zs)]
    catch  _:_ ->
	    [Xs]
    end.

loop(0,Xs) ->
    Xs;
loop(N,Xs) ->
    receive
	X ->
	    loop(N-1,[X|Xs])
    end.

pmap(N,F,Xs) ->
    Size = length(Xs) div N,
    Yss = split(Size,Xs),
    S = self(),
    lists:map(fun(Ys)-> spawn(fun()-> lists:map(fun(Y)-> S ! F(Y) end,
						Ys) end) end,
	      Yss),
    loop(length(Xs),[]).

solve(From,To) ->
    As = lists:seq(From,To),
    Bs = combination(As,As),
    Xs = pmap(10,fun ({A,B}) -> C = times(fun(N)->poly(A,B,N) end),
				log:log("(~p,~p) ~p~n",[A,B,C]),
				{C,A,B} end,
	      Bs),
    lists:max(Xs).

init()->
    log:start(),
    prime_srv:start().

main([X]) ->
    init(),
    From = - list_to_integer(atom_to_list(X)),
    To = list_to_integer(atom_to_list(X)),
    io:format("The answer: ~p~n",[solve(From,To)]),
    init:stop().