Getting array/list element index - algorithm

I was trying to solve this little problem from LeetCode:
-module(two_sum).
-export([main/2]).
-spec main(List :: list(), Target :: non_neg_integer()) -> list().
%%%==================================================================
%%% Export
%%%==================================================================
main(List, Target) ->
P = [{string:str(List, [X]), string:str(List, [Y]), X + Y} || X <- List, Y <- List, Y > X andalso X + Y =:= Target],
io:format("Result: ~w~n", [P]).
%%[X + Y || X <- List, Y <- List, Y > X].
%%iterate(List, Target, 0, {}).
%%%==================================================================
%%% Internal
%%%==================================================================
iterate([], _Target, _Sum, _Result) -> {};
iterate([H | T], Target, Sum, Result) ->
%%io:format("H >> ~w; T >> ~w, Target >> ~w~n", [H, T, Target]).
Acc = Sum + H,
case Acc =:= Target of
true -> erlang:append_element(Result, H);
false -> iterate(T, Target, Acc, Result)
end.
My questions are:
Is there a more efficient way to get the element's index from an array/list? Currently I'm using this: {string:str(List, [X]), but I'm not sure if that's correct, although it gets the job done.
If I happen to get, for instance, a result like this: R = [{1,2,9},{1,3,13},{1,4,17},{2,3,18},{2,4,22},{3,4,26}], how do I pattern match for {1,2,9}, knowing that 9 is Target? I tried [{X1, X2, Target}] = R...but it didn't like it!

How about this. For each element, check its sum with each subsequent element in the list, carrying along the two indices, to be used to report to the user if a match is found.
find_indices(Target, [_H | T] = L) ->
find_indices(Target, L, T, 0, 1).
find_indices(_Target, [_], [], _I, _J) ->
io:format("No match~n");
find_indices(Target, [_Curr | LeftRest], [], I, _J) ->
find_indices(Target, LeftRest, tl(LeftRest), I + 1, I + 2);
find_indices(Target, [Curr | _LeftRest], [Other | _RightRest], I, J)
when Target =:= Curr + Other ->
io:format("Match at indices ~p and ~p: ~p + ~p = ~p~n",
[I, J, Curr, Other, Target]),
ok;
find_indices(Target, L, [_Other | RightRest], I, J) ->
find_indices(Target, L, RightRest, I, J + 1).
Example:
1> index:find_indices(7, [1,2,3,4,5,6]).
Match at indices 2 and 3: 3 + 4 = 7
ok
2> index:find_indices(11, [1,2,3,4,5,6]).
Match at indices 4 and 5: 5 + 6 = 11
ok
3> index:find_indices(12, [1,2,3,4,5,6]).
No match
ok
4> index:find_indices(4, [1,2,3,4,5,6]).
Match at indices 0 and 2: 1 + 3 = 4
ok

Related

How can labeling/2 generate solutions starting from the midpoint of a domain?

Having a list with independent variables, whose domain is 1..N, how can we use labeling/2 so it starts producing solutions starting from the middle?
The flags i tried are [bisect], [enum], [max], [min], [ff], but no matter which i picked, i can't make it work.
My code is:
:-use_module(library(clpfd)).
combos(EMPLOYEES,POSTS,LIST):-
LIMIT is POSTS-EMPLOYEES+1,
length(LIST,EMPLOYEES),
LIST ins 1..LIMIT,
sum(LIST,#=,POSTS),
labeling([bisect],LIST).
after setting a query, for example:
?-combos(2,10,LIST).
i want it to return:
L = [5,5];
L = [4,6];
L = [6,4] ...
instead of:
L = [1,9];
L = [2,8];
L = [3,7] ...
As a rule of thumb, whenever you try to extend the functionality of clpfd, try to reuse as much as possible. It seems that you want solutions first whose sum of distances to the center is as small as possible.
combos2(EMPLOYEES,POSTS,LIST):-
LIMIT is POSTS-EMPLOYEES+1,
length(LIST,EMPLOYEES),
LIST ins 1..LIMIT,
sum(LIST,#=,POSTS),
Mid is (LIMIT+1) div 2, %%
maplist(dist(Mid), LIST, DISTS), %%
sum(DISTS,#=,Totaldist), %%
labeling([],[Totaldist|LIST]).
dist(Mid, E, D) :-
D #= abs(Mid-E).
?- combos2(2,10,L).
L = [5,5]
; L = [4,6]
; L = [6,4]
; L = [3,7]
; L = [7,3]
; ... .
Here you go!
combos(2,S,L) :- b2(S,L).
combos(C,S,[A|L]) :-
C > 2,
b2(S,[A,B]),
D is C-1,
combos(D,B,L).
b2(S,L) :- B is S-1, bisector(B,L).
bisector(Y,[A,B]) :-
odd(Y),
M is div(1+Y,2),
Z is M-1,
range(D,0,Z),
bisec1(D,M,A,B).
bisector(Y,[A,B]) :-
even(Y),
M is 1+Y,
Z is Y/2-1,
range(D,0,Z),
bisec2(D,M,A,B).
bisec1(0,M,M,M).
bisec1(D,M,A,B) :- D > 0, A is M + D, A > 0, B is M - D, B > 0.
bisec1(D,M,A,B) :- D > 0, A is M - D, A > 0, B is M + D, B > 0.
bisec2(D,M,A,B) :- A is (M+2*D+1)/2, A > 0, B is (M-2*D-1)/2, B > 0.
bisec2(D,M,A,B) :- A is (M-2*D-1)/2, A > 0, B is (M+2*D+1)/2, B > 0.
even(X) :- 0 is mod(X, 2).
odd(X) :- 1 is mod(X, 2).
range(M,M,_).
range(X,M,N) :- P is M + 1, P =< N, range(X,P,N).

catch badarg error in the supervisor function

Here I have a program that does some simple mathematical operations. The program is running with a supervisor.
However sometimes the program would crash as I run it. Especially when I first time run calc_sup_start_link() and then some times with calc_test(). Anyone has any idea ? The program is as follows:
calc_sup_start_link() ->
spawn_link(fun calc_sup/0).
calc_sup() ->
process_flag(trap_exit, true),
{ok, _Pid} = calc_start_link(),
receive
{'EXIT', _From, normal} ->
ok;
{'EXIT', _From, _Reason} ->
calc_sup() % Crash: restart
end.
calc_start_link() ->
S = spawn_link(fun calc_loop/0),
register(calc, S),
{ok, S}
calc_loop() ->
receive
{add, P, A, B} ->
P ! {add_reply, A + B},
calc_loop();
{mul, P, A, B} ->
{_, _, N} = now(),
if N rem 5 =/= 0 -> ok end,
P ! {mul_reply, A * B},
calc_loop()
end.
calc_add(A, B) ->
calc ! {add, self(), A, B},
receive
{add_reply, C} -> C
end.
calc_mul(A, B) ->
calc ! {mul, self(), A, B},
receive
{mul_reply, C} -> C
end.
calc_client(X, Y, Z) ->
Q = calc_mul(X, Y),
timer:sleep(500),
R = calc_add(Q, 3),
timer:sleep(500),
calc_mul(R, Z).
calc_test() ->
io:format("Running calc_client(2, 4, 5)~n"),
R = calc_client(2, 4, 5),
io:format("calc_client(2, 4, 5) returned ~p~n", [R]).
I think it crash in this bloc:
calc_loop() ->
receive
{add, P, A, B} ->
P ! {add_reply, A + B},
calc_loop();
{mul, P, A, B} ->
{_, _, N} = now(),
if N rem 5 =/= 0 -> ok end, %% if doesn't work as in C or java !!!
P ! {mul_reply, A * B},
calc_loop()
end.
in fact if N is a multiple of 5, (N rem 5) == 0 and there is no branch to evaluate the result of if, and in erlang all the statement have to return a value. You can verify in the shell:
1> if ((11 rem 5) =/= 0) -> ok end.
ok
2> if ((10 rem 5) =/= 0) -> ok end.
** exception error: no true branch found when evaluating an if expression
3> if ((10 rem 5) =/= 0) -> ok; true -> false end.
false
4>
In your case you should write:
calc_loop() ->
receive
{add, P, A, B} ->
P ! {add_reply, A + B},
calc_loop();
{mul, P, A, B} ->
{_, _, N} = now(),
case (N rem 5) of
0 -> P ! {mul_reply, A * B},
calc_loop();
_ -> ok
end
end.
this will perform the multiplication and loop if N is multiple of 5; and it will terminate with reason normal in other cases (I am not sure it is what you want to do since the if expression is not complete)
if your write tail recursion all by yourself,
the better way is always call external functions(for the code only save two version in memory).
like this :
change calc_loop() to ?MODULE:calc_loop().
it will always call the newest version of code.
http://www.erlang.org/doc/reference_manual/code_loading.html#id88331

Factors of a number

So I am relatively new to Prolog, and while this problem is easy in many other languages I am having a lot of trouble with it. I want to generate a List of factors for a number N. I have already built a predicate that tells me if a number is a factor:
% A divides B
% A is a factor of B
divides(A,B) :- A =\= 0, (B mod A) =:= 0.
% special case where 1 // 2 would be 0
factors(1,[1]) :- !.
% general case
factors(N,L):- N > 0, factor_list(1, N, L).
factor_list(S,E,L) :- S =< E // 2, f_list(S,E,L).
f_list(S,E,[]) :- S > E // 2, !.
f_list(S,E,[S|T]) :- divides(S,E), !, S1 is S+1, f_list(S1, E, T).
f_list(S,E,L) :- S1 is S+1, f_list(S1,E,L).
Any help would be appreciated.
EDIT
I pretty much changed my entire solution, but for some reason predicates like factors(9, [1]) return true, when I only want factors(9, [1,3]) to return true. Any thoughts?
Here's why factors(9,[1]) is true: the timing of attempted instantiations (that is to say, unifications) is off:
f_list(S,E,[]) :- S > E // 2, !.
f_list(S,E,[S|T]) :- divides(S,E), !, S1 is S+1, f_list(S1, E, T).
f_list(S,E,L) :- S1 is S+1, f_list(S1,E,L).
%% flist(1,9,[1]) -> (2nd clause) divides(1,9), S1 is 2, f_list(2,9,[]).
%% flist(2,9,[]) -> (3rd clause) S1 is 3, f_list(3,9,[]).
%% ...
%% flist(5,9,[]) -> (1st clause) 5 > 9 // 2, !.
because you pre-specify [1], when it reaches 3 the tail is [] and the match with the 2nd clause is prevented by this, though it would succeed due to divides/2.
The solution is to move the unifications out of clauses' head into the body, and make them only at the appropriate time, not sooner:
f_list(S,E,L) :- S > E // 2, !, L=[].
f_list(S,E,L) :- divides(S,E), !, L=[S|T], S1 is S+1, f_list(S1, E, T).
f_list(S,E,L) :- S1 is S+1, f_list(S1,E,L).
The above usually is written with the if-else construct:
f_list(S,E,L) :-
( S > E // 2 -> L=[]
; divides(S,E) -> L=[S|T], S1 is S+1, f_list(S1, E, T)
; S1 is S+1, f_list(S1, E, L)
).
Also you can simplify the main predicate as
%% is not defined for N =< 0
factors(N,L):-
( N =:= 1 -> L=[1]
; N >= 2 -> f_list(1,N,L)
).
Personally, I use a somewhat simpler looking solution:
factors(1,[1]):- true, !.
factors(X,[Factor1|T]):- X > 0,
between(2,X,Factor1),
NewX is X // Factor1, (X mod Factor1) =:= 0,
factors(NewX,T), !.
This one only accepts an ordered list of the factors.
Here is a simple enumeration based procedure.
factors(M, [1 | L]):- factors(M, 2, L).
factors(M, X, L):-
residue(M, X, M1),
((M==M1, L=L1); (M1 < M, L=[X|L1])),
((M1=1, L1=[]); (M1 > X, X1 is X+1, factors(M1, X1, L1))).
residue(M, X, M1):-
((M < X, M1=M);
(M >=X, MX is M mod X,
(MX=0, MM is M/X, residue(MM, X, M1);
MX > 0, M1=M))).

How to solve this puzzle in Prolog?

I am trying to solve a puzzle in Prolog that involves taking a square of numbers (a list of a list of numbers) and returning the list of the greatest combination of numbers starting at the top and going down, row by row. Each move must be either down, down to the right, or down to the left.
I've been trying to do this for a while now, does anyone have a place I could begin?
For example, on the board
[[0, 2, 1, 0],
[0, 1, 1, 0],
[0,10,20,30]]
the best move would be [1, 2, 3] for 33 points.
So here is how you could do it. I know it's kinda wordy, that probably is because I'm not really fluent in Prolog either...
% Lookup a value in a list by it's index.
% this should be built into prolog?
at(0, [H|_], H).
at(N, [_|T], X) :-
N > 0,
N1 is N - 1,
at(N1, T, X).
% like Haskell's maximumBy; takes a predicate, a
% list and an initial maximum value, finds the
% maximum value in a list
maxby(_, [], M, M).
maxby(P, [H|T], M0, M) :-
call(P, H, M0, M1),
maxby(P, T, M1, M).
% which of two paths has the bigger score?
maxval(path(C, I), path(C1, _), path(C, I)) :- C >= C1.
maxval(path(C0, _), path(C, I), path(C, I)) :- C0 < C.
% generate N empty paths as a starting value for
% our search
initpaths(N, Ps) :-
findall(path(0, []),
between(0, N, _),
Ps).
% given the known best paths to all indexes in the previous
% line and and index I in the current line, select the best
% path leading to I.
select(Ps, I, N, P) :-
I0 is I-1,
I1 is I+1,
select(Ps, I0, N, path(-1, []), P0),
select(Ps, I, N, P0, P1),
select(Ps, I1, N, P1, P).
% given the known best paths to the previous line (Ps),
% an index I and a preliminary choice P0, select the path
% leading to the index I (in the previous line) if I is within
% the range 0..N and its score is greater than the preliminary
% choice. Stay with the latter otherwise.
select(_, I, _, P0, P0) :- I < 0.
select(_, I, N, P0, P0) :- I > N.
select(Ps, I, _, P0, P) :-
at(I, Ps, P1),
maxby(maxval, [P0], P1, P).
% given the known best paths to the previous line (P1),
% and a Row, which is the current line, extend P1 to a
% new list of paths P indicating the best paths to the
% current line.
update(P1, P, Row, N) :-
findall(path(C, [X|Is]),
( between(0, N, X)
, select(P1, X, N, path(C0, Is))
, at(X, Row, C1)
, C is C0 + C1),
P).
% solve the puzzle by starting with a list of empty paths
% and updating it as long as there are still more rows in
% the square.
solve(Rows, Score, Path) :-
Rows = [R|_],
length(R, N0),
N is N0 - 1,
initpaths(N, IP),
solve(N, Rows, IP, Score, Path).
solve(_, [], P, Score, Path) :-
maxby(maxval, P, path(-1, []), path(Score, Is0)),
reverse(Is0, Path).
solve(N, [R|Rows], P0, Score, Path) :-
update(P0, P1, R, N),
solve(N, Rows, P1, Score, Path).
Shall we try it out? Here are your examples:
?- solve([[0,2,1,0], [0,1,1,0], [0,10,20,30]], Score, Path).
Score = 33,
Path = [1, 2, 3] ;
false.
?- solve([[0,1,1], [0,2,1], [10,0,0]], Score, Path).
Score = 13,
Path = [1, 1, 0] ;
false.
My prolog is a bit shaky. In fact all I remember about prolog is that it's declarative.
Here is some haskell code to find the value of the max path. Finding the trace should be an easy next step, but a bit more complicated to code up I imagine. I suppose a very elegant solution for the trace would be using monads.
maxValue :: [ [ Int ] ] -> Int
maxValue p = maximum $ maxValueHelper p
maxValueHelper :: [ [ Int ] ] -> [ Int ]
maxValueHelper [ row ] = row
maxValueHelper ( row : restOfRows ) = combine row ( maxValueHelper restOfRows )
combine :: [ Int ] -> [ Int ]-> [ Int ]
combine [ x ] [ y ] = [ x + y ]
combine ( x1 : x2 : lx ) ( y1 : y2 : ly ) =
let ( z2 : lz ) = combine ( x2 : lx ) ( y2 : ly )
in
( max ( x1 + y1 ) ( x1 + y2 ) : max ( x2 + y1 ) z2 : lz )
main :: IO()
main = print $ maxValue [[0,2,1,0], [0,1,1,0], [0,10,20,30]]
?- best_path_score([[0, 2, 1, 0],[0, 1, 1, 0],[0,10,20,30]], P, S).
P = [1, 2, 3],
S = 33.
with this definition
best_path_score(Rs, BestPath, BestScore) :-
aggregate_all(max(Score, Path), a_path(Rs, Path, Score), max(BestScore, BestPath)).
a_path([R|Rs], [P|Ps], Score) :-
nth0(P, R, S0),
a_path(Rs, P, Ps, S),
Score is S0 + S.
a_path([], _, [], 0).
a_path([R|Rs], P, [Q|Qs], T) :-
( Q is P - 1 ; Q is P ; Q is P + 1 ),
nth0(Q, R, S0),
a_path(Rs, Q, Qs, S),
T is S0 + S.

Sicstus Prolog - Weight of a word

I've got a problem about how to weigh a word.
Every single letter in a word has specific weight, I need to calculate the total weight of the word.
For example:
A-E = 1, F-O = 2, P-Z = 3.
If the word is "PEN", the answer will be "Weight = 6",
cuz P = 3, E = 1 and N = 2.
I've tried:
word_weight([X], W):-
X = 65 -> W = 1;
X = 66 -> W = 3.
word_weight([X,Y],W):-
X = 65 -> W1 = 1;
X = 66 -> W1 = 3,
Y = 65 -> W2 = 1;
Y = 66 -> W2 = 3,
W is W1 + W2.
word_weight([X|Y], W):-
X = 65 -> W = 1;
X = 66 -> W = 3,
word_weight(Y, W).
Running res:
| ?- word_weight("B",W).
W = 3 ?
yes
It only works with one letter. How to make it works with many letters? And the answers will be the total value of the weight.
The following program works with SWI-Prolog. It will be surely easy to adapt it to Sicstus Prolog.
char_weight(C, 1) :- C >= 65, C =< 69.
char_weight(C, 2) :- C >= 70, C =< 79.
char_weight(C, 3) :- C >= 80, C =< 90.
word_weight([], 0).
word_weight([Char| Chars], Weight) :-
char_weight(Char, W),
word_weight(Chars, Ws),
Weight is W + Ws.
How about
weight(C, 1) :- char_code('A') =< C, C =< char_code('E').
weight(C, 2) :- char_code('F') =< C, C =< char_code('O').
weight(C, 3) :- char_code('P') =< C, C =< char_code('Z').
word_weight(S, W) :- string(S), !, string_list(S, L), word_weight(L, W).
word_weight([], 0).
word_weight([H|T], W) :- W is weight(H) + word_weight(T).
in ECLiPSe-CLP, string_list/2 converts a string into a list of numberic character codes, char_code/2 gets the numeric code of a character.
Edit:
Oops, I should have read your question completely:
Wen using ->/2, you should use brackets and don't hesitate to use indentation:
( Condition ->
IfBranch
;
ElseBranch
),
RestProg.
Your second clause is a bit unreadable. But for this excercise you shouldn't need ->/2 at all.
Your third clause only works for a single-letter string, because it first unifies W with the value for X and then wants to unify W with the weight of X. This only works if Y and X have the same weight.

Resources