How to efficiently read thousand of lines from STDIN in Erlang? - erlang

I've stumbled upon an issue when reading thousands of lines from STDIN. This would have been an imaginary edge case until I found out that some tests for this problem require reading thousand of lines from STDIN. At first I thought that my algorithms were not optimal, and only by accident I've found out that only reading lines without any computations could make half of the test time out.
Here is part code that times out:
process_queries(0, _) -> ok;
process_queries(N, A) ->
case io:fread("", "~s~d~d") of
{ok, _} -> process_queries(N - 1, A)
%{ok, ["Q", L, R]} -> process_queries(N - 1, apply_q(L, R, A));
%{ok, ["U", Idx, Val]} -> process_queries(N - 1, apply_u(Idx, Val, A))
end
.
I deliberately left comments to show that all the computations were disabled. So this code timed out given N=7984.
Is there a better way of reading and processing thousands lines from STDIN in Erlang?
io:get_line gets only one line a time.
io:get_chars requires you to know how many character to get.

I'd suggest switching stdio to binary and then using io:get_line. Your data's format is pretty simple to parse by splitting on whitespace and converting two values to integers. The following code runs ~10 times faster than your code for me in a simple benchmark. I used escript to benchmark, which means it's highly likely that the difference is actually more than 10 times since escript parses and compiles the code on the fly.
process_queries_2(0, _) -> ok;
process_queries_2(N, A) ->
Line = io:get_line(""),
[X, Y0, Z0, _] = binary:split(Line, [<<$\s>>, <<$\n>>], [global]),
Y = binary_to_integer(Y0),
Z = binary_to_integer(Z0),
% use X, Y, Z
process_queries_2(N - 1, A).
Here's the code I used to benchmark:
main(["1"]) ->
ok = io:setopts(standard_io, [binary]),
process_queries(10000, {});
main(["2"]) ->
ok = io:setopts(standard_io, [binary]),
process_queries_2(10000, {}).%
$ time yes 'Q 100 200' | escript a.erl 1
yes 'Q 100 200' 4.64s user 0.11s system 93% cpu 5.063 total
escript a.erl 1 4.67s user 1.44s system 120% cpu 5.062 total
$ time yes 'Q 100 200' | escript a.erl 2
yes 'Q 100 200' 0.36s user 0.01s system 77% cpu 0.466 total
escript a.erl 2 0.40s user 0.10s system 106% cpu 0.464 total
The reason for the speedup is that Erlang Strings are linked lists, which are very inefficient both for CPU time and Memory usage compared to binaries, which is a sequential chunk of memory.

There is an excerpt from my solution. There are few tricks how to do it really efficient.
read_command(CP) ->
{ok, Line} = file:read_line(standard_io),
[C, A, B] = binary:split(Line, CP, [global, trim_all]),
{case C of <<"Q">> -> 'Q'; <<"U">> -> 'U' end,
binary_to_integer(A),
binary_to_integer(B)}.
read_commands(N, CP) ->
[ read_command(CP) || _ <- lists:seq(1, N) ].
execute(Array, L) ->
lists:foldl(fun({'Q', F, T}, A) ->
{Val, A2} = query(A, F, T),
file:write(standard_io, [integer_to_binary(Val), $\n]),
A2;
({'U', I, V}, A) ->
update(A, I, V)
end, Array, L).
read_int_line(CP) ->
{ok, Line} = file:read_line(standard_io),
[binary_to_integer(X) || X <- binary:split(Line, CP, [global, trim_all])].
main() ->
ok = io:setopts([binary]),
CP = binary:compile_pattern([<<" ">>, <<$\n>>]),
[N] = read_int_line(CP),
L = read_int_line(CP),
N = length(L),
[K] = read_int_line(CP),
execute(init(L), read_commands(K, CP)).
You have to write your own init/1, update/3 and query/3 of course.

Related

Find the length of the longest substring

I see questions similar like this ones, but eventually, for different programming languages. I'm trying to solve this little problem:
Given a string, find the length of the longest substring without
repeating characters. For example, the longest substring without
repeating letters for abcabcbb is abc, which the length is 3. For
bbbbb the longest substring is b, with the length of 1.
I don't need the anwer to it but why what I have so far fails in the second iteration.
1> longest_substring:main("abcabcbb").
H: 97, T: "bcabcbb", Sub: []
Is 97 in []? false
H: 98, T: "cabcbb", Sub: 97
** exception error: no function clause matching string:chr(97,98,1) (string.erl, line 99)
in function longest_substring:process/2 (src/leetcode/algorithms/longest_substring.erl, line 28)
2>
This is the source code:
-module(longest_substring).
-export([main/1]).
-spec main(S :: string()) -> string().
%%%==================================================================
%%% Export
%%%==================================================================
main(S) -> process(S, "").
%%%==================================================================
%%% Internal
%%%==================================================================
process([], Sub) -> string:len(Sub);
process([H | T], Sub) ->
io:format("H: ~w, T: ~p, Sub: ~p~n", [H, T, Sub]),
Found = string:chr(Sub, H),
io:format("Is ~w in ~p? ~p~n", [H, Sub, Found =/= 0]),
% Don't know how to make this `if` thing better...
if
Found > 0 -> process(T, H);
_ -> process(T, string:concat(Sub, H))
end.
You have two places where you are treating character H as a string, both within the if:
if
Found > 0 -> process(T, H);
_ -> process(T, string:concat(Sub, H))
end.
Both appearances of H here need to be [H] instead, to form a string from the single character. (Also, your final clause in the if needs to use true, not an underscore — you should be getting a compiler error about this.)
Currently your solution returns a number, not a string. It also fails to remember any longer substring that might appear early in the string. To fix that, you need to remember the longest substring you've seen so far, which means you need another accumulator:
-module(longest_substring).
-export([main/1]).
-spec main(S :: string()) -> string().
main(S) -> process(S, {0,[]}, {0,[]}).
process([], {LL,Last}, {LG,_}) when LL > LG -> Last;
process([], _, {_,Long}) -> Long;
process([H | T], {LL,Last}=Sub, {LG,_}=Long) ->
case string:rchr(Last, H) of
0 ->
process(T, {LL+1,string:concat(Last,[H])}, Long);
N ->
NewLast = {1+LL-N,string:substr(Last,N+1)++[H]},
process(T, NewLast,
case LL > LG of
true ->
Sub;
false ->
Long
end)
end.
The main/1 function passes two accumulators to process/3, each of which is a pair of a length and a list. The first accumulator tracks the current substring, and the second tracks the longest substring seen so far.
In the last clause of process/3, we first check if H is in the current substring; if not, we add it to the current substring, increase its length by 1, and call process/3 again with the tail of the string. But if H is found in the current substring, we calculate the new current substring using the return value of string:rchr/2 to preserve the longest portion of the previous substring that we can (the original solution does not do this). We then check to see if the length of the current substring is greater than the current longest substring, and if so, we make it the longest substring, or if not we throw it away and keep the current longest substring, and then continue with the tail of the string. (Note that we could also make this check for greater or equal instead of greater; this would make our function return the last longest substring we find rather than the first.)
The first two clauses of process/3 handle the case where the input string has been fully processed. They just decide if the current substring is longer than the longest seen so far and return the longer of the two. (The alternative of using a greater or equal comparison applies here as well.)
for fun, I propose you to avoid complex search. In this solution I create a process for each element of the list holding: the element itself, the Pid of the next process/element in the list, and the Pid of the caller.
To initiate the search, I send to each process/element an empty list.
Each time a process/element receives a list, it checks if its stored element is a member of the received list. If yes, the list is send back to the caller, if not the element is prepend to the list and the new list is sent to the next process/element to continue the evaluation.
The caller process simply waits for as many returned messages as it has sent.
I have added a stop message and a special case for the last element of the list.
-module (longer).
-compile([export_all]).
char_proc(V,Next,Caller) ->
receive
stop -> ok;
Str ->
case lists:member(V,Str) of
true -> Caller ! Str;
false -> send(Next,Caller,[V|Str])
end,
char_proc(V,Next,Caller)
end.
send(noproc,Caller,Str) -> Caller ! Str;
send(Next,_,Str) -> Next ! Str.
find(Str) ->
Me = self(),
Pids = tl(lists:reverse(lists:foldl(fun(X,Acc) -> Pid = spawn(?MODULE,char_proc,[X,hd(Acc),Me]), [Pid|Acc] end,[noproc],Str))),
[X ! [] || X <- Pids],
R = receive_loop(0,[],length(Str)),
[X ! stop || X <- Pids],
R.
receive_loop(N,S,0) -> {N,S};
receive_loop(N,S,I) ->
receive
M when length(M) > N ->
receive_loop(length(M),M,I-1);
_ ->
receive_loop(N,S,I-1)
end.
tested in the shell:
1> c(longer).
{ok,longer}
2> longer:find("abcdad").
{4,"abcd"}
3> longer:find("abcdadtfrseqgepz").
{9,"adtfrseqg"}
4> longer:find("aaaaaaaaaaaa").
{1,"a"}
5> longer:find("abcdatfrseqgepz").
{11,"bcdatfrseqg"}
6>
Note there is no guarantee about witch sub-string will be returned if it exists several solutions, it is very easy to modify the code to return either the first sub-string or all of them.

Split list into 2 lists of equal sum erlang

I want to know how to split a given list into two lists such that both lists have the same sum. I want to do that by using concurrency. I am doing this in erlang.
So, I'm doing something like this:
Read the list, if its sum is even, then proceed else fail. Take the first element of the list and check if it is greater than half of the sum, if not, then I add this element to a new list. Next, I take the second element of the list, check the sum of this element and that of the new list and do the same operation. And so on.. Such that when the sum in the new list is equal to half of the sum of the first list, it calls another function to send the remaining elements.
-module(piles_hw).
-compile(export_all).
start([]) -> 0;
start(List) ->
Total = lists:foldl(fun(X, Sum)-> X+Sum end,0,List),
if (Total rem 2) == 0 ->
Total/2,
copy_to_list_one([],List,start(List));
true ->
func_fail()
end.
copy_to_list_one(L1,[H|T],X)->
Y =lists:sum(L1)+H,
if Y<X ->
copy_to_list_one(lists:append(L1,[H]),lists:delete(H,[H|T]),X);
Y==X ->
take(lists:append(L1,[H]));
Y>X ->
copy_to_list_one(L1,lists:delete(H,[H|T]),X)
end;
copy_to_list_one(L1,[],X)->
copy_func_two([1,2,3,4,19,20,28,14,11],X).
copy_func_two([H|T],X)->
copy_to_list_one([],lists:append(T,[H]),X).
take(L3)->
io:format("~w",[L3]).
func_fail() ->
io:format("~n fail ~n").
But, in this way I go into an infinite loop sometimes. Could somebody help?
Edit:
Pascal was entirely correct: there is no algorithm (at least not that I could come up with) that can solve certain sets by running down the list one item at a time. (In particular when half the sum of the list equals X * N where X is present in the list N times.) I initially put a flawed algorithm here.
That got me excited in the nerdiest of ways, so here is an exhaustive algorithm involving the pairs of [{P, (List - P)} || P <- powerset(List)].
There are some lists:usort/1 shenanigans in there that I didn't clean up to uniquify the list prior to the final comparison (otherwise you get duplicate similar pairs, which is ugly). Anyway, ugly, but now correct:
comblit(List) ->
Power = powerset(List),
Lists = lists:usort([lists:sort([Z, lists:subtract(List, Z)]) || Z <- Power]),
Pairs = lists:map(fun([H|[B|[]]]) -> {H, B} end, Lists),
[{Z, X} || {Z, X} <- Pairs, lists:sum(Z) == lists:sum(X)].
powerset([H|T]) ->
Part = powerset(T),
powerset(Part, H, Part);
powerset([]) -> [[]].
powerset(A, Part, [H|T]) ->
powerset([[Part|H]|A], Part, T);
powerset(A, _, []) -> A.
This is still not a concurrent solution, but the path to making it concurrent is a lot more obvious now.
Thanks for pointing that out, Pascal. That was sort of fun.
I have this solution that is not concurrent:
-module(split).
-export([split/1,t_ok/0,t_too_long/0,t_fail/0,t_crash/0]).
%% [EDIT]
%% Don't use this code, it fails with negative integers!
% Exported
%% take a list and split it in 2 list which sum are equals
split(L=[_|_]) ->
T2 = lists:sum(L),
{ok, TRef} = timer:send_after(20000,too_long),
R = case T2 rem 2 of
1 -> {error,fail};
0 -> split(tl(L),[hd(L)],[],T2 div 2,hd(L),0)
end,
timer:cancel(TRef),
R.
% test
t_ok() -> split([1,2,3,4,5,6,7]).
t_too_long() -> split(lists:seq(1,3+4*100000)).
t_fail() -> split([2,4,6,10000,8,6]).
t_crash() -> split([]).
% private
split([H|Q],A,B,T,Asf,_Bsf) when H + Asf == T -> {ok,{[H|A],B ++ Q}};
split([H|Q],A,B,T,_Asf,Bsf) when H + Bsf == T -> {ok,{A ++ Q,[H|B]}};
split([H|Q],A,B,T,Asf,Bsf) when H + Asf > T, H + Bsf < T -> c_split(Q,A,[H|B],T,Asf,Bsf+H);
split([H|Q],A,B,T,Asf,Bsf) when H + Asf < T, H + Bsf > T -> c_split(Q,[H|A],B,T,Asf+H,Bsf);
split([H|Q],A,B,T,Asf,Bsf) when H + Asf < T, H + Bsf < T ->
case c_split(Q,A,[H|B],T,Asf,Bsf+H) of
{error,fail} -> c_split(Q,[H|A],B,T,Asf+H,Bsf);
R -> R
end;
split([],A,B,_T,_T,_T)-> {ok,{A,B}};
split(_,_,_,_,_,_) -> {error,fail}.
c_split(L,A,B,T,Asf,Bsf) ->
receive
too_long -> {error,too_long}
after 0 ->
split(L,A,B,T,Asf,Bsf)
end.
To turn it concurrent, you could replace the line 0 -> split(tl(L),[hd(L)],[],T2 div 2,hd(L),0) by a call to a function which spawn_link several processes (as much as there are core available) which start the split/6 function with different initial conditions. The split/6 must have a 7th parameter: the Pid of the main process where it will send back its answer. The main process wait for answers and stop
if a solution is found
if all processes fail to find one
if the time out occurs
I have edited the code following #Odobenus remark (but it still fail on [] -> {ok,[],[]} :o), and I also made a concurrent version. The funny thing is that for this kind of problem, and with the input list I use (a lists:seq) there are so many solution that any start sequence I choose can give a solution, so the concurrent version is slower.

Counting down from N to 1

I'm trying to create a list and print it out, counting down from N to 1. This is my attempt:
%% Create a list counting down from N to 1 %%
-module(list).
-export([create_list/1]).
create_list(N) when length(N)<hd(N) ->
lists:append([N],lists:last([N])-1),
create_list(lists:last([N])-1);
create_list(N) ->
N.
This works when N is 1, but otherwise I get this error:
172> list:create_list([2]).
** exception error: an error occurred when evaluating an arithmetic expression
in function list:create_list/1 (list.erl, line 6)
Any help would be appreciated.
You should generally avoid using append or ++, which is the same thing, when building lists. They both add elements to the end of a list which entails making a copy of the list every time. Sometimes it is practical but it is always faster to work at the front of the list.
It is a bit unclear in which order you wanted the list so here are two alternatives:
create_up(N) when N>=1 -> create_up(1, N). %Create the list
create_up(N, N) -> [N];
create_up(I, N) ->
[I|create_up(I+1, N)].
create_down(N) when N>1 -> %Add guard test for safety
[N|create_down(N-1)];
create_down(1) -> [1].
Neither of these are tail-recursive. While tail-recursion is nice it doesn't always give as much as you would think, especially when you need to call a reverse to get the list in the right order. See Erlang myths for more information.
The error is lists:last([N])-1. Since N is an array as your input, lists:last([N]) will return N itself. Not a number you expect. And if you see the warning when compiling your code, there is another bug: lists:append will not append the element into N itself, but in the return value. In functional programming, the value of a variable cannot be changed.
Here's my implementation:
create_list(N) ->
create_list_iter(N, []).
create_list_iter(N, Acc) ->
case N > 0 of
true -> NewAcc = lists:append(Acc, [N]),
create_list_iter(N-1, NewAcc);
false -> Acc
end.
If I correctly understand your question, here is what you'll need
create_list(N) when N > 0 ->
create_list(N, []).
create_list(1, Acc) ->
lists:reverse([1 | Acc]);
create_list(N, Acc) ->
create_list(N - 1, [N | Acc]).
If you work with lists, I'd suggest you to use tail recursion and lists construction syntax.
Also, to simplify your code - try to use pattern matching in function declarations, instead of case expressions
P.S.
The other, perhaps, most simple solution is:
create_list(N) when N > 0 ->
lists:reverse(lists:seq(1,N)).

How does Erlang schedule work for multicore CPU machines?

I am learning Erlang and am quite impressed how easy it is to parallelize work. To practice a bit I dug up the good old Fibanocci sequence. In the following code I try to take advantage of parallelization by computing the expensive products three at a time.
-module (fib4).
-export ( [main/1] ).
main (N) ->
fib (list_to_integer (atom_to_list (hd (N) ) ) ),
halt (0).
path (1, Acc) -> Acc;
path (N, Acc) when N rem 2 =:= 0 ->
path (N - 1, [step | Acc] );
path (N, Acc) ->
path ( (N - 1) div 2, [jump | Acc] ).
fib (N) -> fib (1, 1, path (N, [] ) ).
fib (N, Nplus1, [Last] ) ->
case Last of
step -> Nplus1;
jump -> N * N + Nplus1 * Nplus1
end;
fib (N, Nplus1, [jump | T] ) ->
Pid = self (),
spawn (fun () -> Pid ! {n1sq, Nplus1 * Nplus1} end),
spawn (fun () -> Pid ! {mul, 2 * N * Nplus1} end),
spawn (fun () -> Pid ! {nsq, N * N} end),
{Nsq, N1sq, Mul} = loop (0, 0, 0),
fib (Nsq + N1sq, N1sq + Mul, T);
fib (N, Nplus1, [step | T] ) ->
fib (Nplus1, N + Nplus1, T).
loop (Nsq, N1sq, Mul) ->
receive
{nsq, Val} ->
if
N1sq > 0 andalso Mul > 0 -> {Val, N1sq, Mul};
true -> loop (Val, N1sq, Mul)
end;
{n1sq, Val} ->
if
Mul > 0 andalso Nsq > 0 -> {Nsq, Val, Mul};
true -> loop (Nsq, Val, Mul)
end;
{mul, Val} ->
if
N1sq > 0 andalso Nsq > 0 -> {Nsq, N1sq, Val};
true -> loop (Nsq, N1sq, Val)
end
end.
I am running this code on a Phenom X4 and during the minute it takes on my machine to calculate fib(10000000) only one to two cores are working and the others are idling around.
My questions are:
Who decides onto how many cores the worker threads are distributed? The Erlang node or my OS (ubuntu with 2.6.38 in my case)?
Do I lose speed due to the fact that two or three cores are idling?
Erlang's default behavior has historically been to run one scheduler, which is basically a native OS thread, which chooses Erlang tasks to run from a queue. With the advent of multi-core and multi-processor systems, the runtime was extended to take advantage. Starting the runtime with -smp enabled will cause the runtime to create multiple schedulers, usually one per logical CPU. You can manually specify the number of schedulers with the -S flag e.g. -S 16.
This is documented in the Erlang Run-Time System Reference Manual.
A deeper discussion of SMP support can be found in this discussion thread.
EDIT
I should also point out that, as of R12B, SMP is enabled by default on platforms that support it (equivalent to the -smp auto flag). If you're curious about your own runtime, the following quote from the discussion thread will be of interest:
You can see what was chosen at the first line of printout from the
"erl" command. E.g.
Erlang (BEAM) emulator version 5.6.4 [source] [smp:4] [asynch-threads:0] .....
The "[smp:4]" above tells that the SMP VM is run and with 4 schedulers.
The reason you see so little parallelism is that your program is basically sequential. All the work is being done in one process in the fib/3 function. The processes you spawn all just send a message and then die and the spawning process synchronously waits for these messages so there is no real concurrency. You could just as well just call the loop/3 function directly with these values.
Otherwise it is as others have mentioned that Erlang automatically uses all the multiple cores available and distributes processes across these where possible. In your case however there is little need to do this and no gain so the system does not do it.
This is actually one of the more difficult things in writing concurrent applications. It is not enough to just spread things into many processes, you actually have to make sure that these processes actually run concurrently. It means rethinking your algorithms, which can be difficult.
Erlang does not use threads in the traditional sense. The Erlang VM creates one system thread for each hardware core of the CPU. When you start a thread in Erlang, you are really creating a "task", which is different from a system thread. Erlang manages these tasks inside of the VM.
Depending on VM and it's configuration, these tasks may or may not be mapped to individual CPU cores, which I believe is what you are seeing here.
There is an interesting blog article you might like here.

Overuse of guards in Erlang?

I have the following function that takes a number like 5 and creates a list of all the numbers from 1 to that number so create(5). returns [1,2,3,4,5].
I have over used guards I think and was wondering if there is a better way to write the following:
create(N) ->
create(1, N).
create(N,M) when N =:= M ->
[N];
create(N,M) when N < M ->
[N] ++ create(N + 1, M).
The guard for N < M can be useful. In general, you don't need a guard for equality; you can use pattern-matching.
create(N) -> create(1, N).
create(M, M) -> [M];
create(N, M) when N < M -> [N | create(N + 1, M)].
You also generally want to write functions so they are tail-recursive, in which the general idiom is to write to the head and then reverse at the end.
create(N) -> create(1, N, []).
create(M, M, Acc) -> lists:reverse([M | Acc]);
create(N, M, Acc) when N < M -> create(N + 1, M, [N | Acc]).
(Of course, with this specific example, you can alternatively build the results in the reverse order going down to 1 instead of up to M, which would make the lists:reverse call unnecessary.)
If create/2 (or create/3) is not exported and you put an appropriate guard on create/1, the extra N < M guard might be overkill. I generally only check on the exported functions and trust my own internal functions.
create(N,N) -> [N];
create(N,M) -> [N|create(N + 1, M)]. % Don't use ++ to prefix a single element.
This isn't quite the same (you could supply -5), but it behaves the same if you supply meaningful inputs. I wouldn't bother with the extra check anyway, since the process will crash very quickly either way.
BTW, you have a recursion depth problem with the code as-is. This will fix it:
create(N) ->
create(1, N, []).
create(N, N, Acc) -> [N|Acc];
create(N, M, Acc) -> create(N, M - 1, [M|Acc]).
I don't really think you have over used guards. There are two cases:
The first is the explicit equality test in the first clause of create/2
create(N, M) when N =:= M -> [M];
Some have suggested transforming this to use pattern matching like
create(N, N) -> [N];
In this case it makes no difference as the compiler internally transforms the pattern matching version to what you have written. You can safely pick which version you think feels best in each case.
In the second case you need some form of sanity check that the value of the argument in the range you expect it to be. Doing in every loop is unnecessary and I would move it to an equivalent test in create/1:
create(M) when M > 1 -> create(1, M).
If you want to use an accumulator I would personally use the count version as it saves reversing the list at the end. If the list is not long I think the difference is very small and you can pick the version which feels most clear to you. Anyway, it is very easy to change later if you find it to be critical.

Resources