Prolog function to create multiplication tables - prolog

I am trying to create a prolog function that gets a small multiplication table based on the first value pased to the function.
My code is currently as follows:
mult(n, [[[n, 1], n*1], [[n,2], n*2], [[n,3], n*3]]).
So for example I would like a query such as:
?- mult(5, R).
To display something like:
R = [[[5,1],5], [[5,2],10], [[5,3], 15]]
However, currently this query only returns false, how could I fix my code?

For example, like this. The capital letters for variable names are mandatory.
mult(N, [[[N, 1], N1], [[N,2], N2], [[N,3], N3]]) :-
N1 is 1*N,
N2 is 2*N,
N3 is 3*N.
or maybe:
mult(N, R) :-
numlist(1, 3, M),
maplist(x(N), M, R).
x(N, M, [[N, M], P]) :-
P is N * M.
You could also abuse findall to get the same result in a one-liner.
?- findall([[5,X],P], ( between(1, 3, X), P is 5*X ), R).
R = [[[5, 1], 5], [[5, 2], 10], [[5, 3], 15]].

mulTable(N,End):-
mulTable(N,1,End).
mulTable(_N,Start,End):-
Start > End.
mulTable(N,Counter,End):-
Counter =< End,
write(N),
write('X'),
write(Counter),
write('='),
Mul is N*Counter,
write(Mul),
nl,
NewCounter is Counter +1,
mulTable(N,NewCounter,End).

Related

Create a list of adjacencies by adjacency matrix

I need to write a program that will create a list of adjacencies based on the representation of the graph, given in the form of an adjacency matrix.
Examples
input - a list with lists of elements
[[0,1,1],[1,0,1],[1,1,0]].
output
[[0,2,3],[1,0,3],[1,2,0]]
I've tried this one:
indexof(Index, Item, List):-
nth1(Index, List, Item).
replace(I, L, E, K) :-
nth1(I, L, _, R),
nth1(I, K, E, R).
f([], []).
f([H|Tail], [Z|RezTail]):-
member(E,H),
E =:= 1,
indexof(X, E, H),
replace(X, H, X, Z),
f(Tail, RezTail).
Input - f([[0,1,1],[1,0,1],[1,1,0]], Z).
Output - Z = [[0, 2, 1], [1, 0, 1], [1, 1, 0]]
As you can see the problem is that after finding the first " 1 " the program goes into recursion and skips further items in the list. Is there any option how to avoid this?
How about
fh([], [], _).
fh([0|T1], [0|T2], I) :-
Ip is I+1,
fh(T1, T2,Ip).
fh([_|T1], [I|T2], I) :-
Ip is I+1,
fh(T1, T2, Ip).
f([], []).
f([H1|T1], [H2|T2]) :-
fh(H1, H2, 1),
f(T1, T2).
so:
?- f([[0,1,1],[1,0,1],[1,1,0]],X).
evaluates to:
X = [[0, 2, 3], [1, 0, 3], [1, 2, 0]]

create a list in prolog in range of two numbers

I want to build list of numbers that are in range of two given numbers.
For example: betweenRange(1,5,X)
will give the answer: X=[1,2,3,4,5].
any idea how to do that?
I've tried something like:
elementsBetween(N1, N2, [N1|_]):-
N2 =:= N1.
elementsBetween(N1, N2, List):-
N2 > N1, N2New is N2-1,
elementsBetween(N1, N2New, [N2|List]).
but its not working, some problem with backtracking after the recursion.
betweenToList(X,X,[X]) :- !.
betweenToList(X,Y,[X|Xs]) :-
X =< Y,
Z is X+1,
betweenToList(Z,Y,Xs).
Output:
?- betweenToList(1,5,X).
X = [1, 2, 3, 4, 5].
?- betweenToList(1,2,X).
X = [1, 2].
?- betweenToList(1,8,X).
X = [1, 2, 3, 4, 5, 6, 7, 8].
?- betweenToList(1,1,X).
X = [1].
?- betweenToList(1,0,X).
false.
Same logic by decreasing Y you can use reverse/2 (Easy to implement):
betweenDecYAux(X,X,[X]) :- !.
betweenDecYAux(X,Y,[Y|Ys]) :-
X =< Y,
Z is Y-1,
betweenDecYAux(X,Z,Ys).
betweenDecY(X,Y,R) :-
betweenDecYAux(X,Y,L),
reverse(L, R). % reverse [c,b,a] to [a,b,c]
Output:
?- betweenDecY(1,6,X).
X = [1, 2, 3, 4, 5, 6].
?- betweenDecY(2,8,X).
X = [2, 3, 4, 5, 6, 7, 8].
?- betweenDecY(1,0,X).
false.
Here's a simple solution:
betweenRange(Lo, Hi, Range) :- findall(N, between(Lo, Hi, N), Range).
It puts all Ns that satisfy between(Lo,Hi,N) into a list Range.

Prolog - Why does my definition for append_list not return the combined list?

% appends an element to the beginning of a list.
append_element(X, T, [X|T]).
% append a list to another list to create a combined list,
% by breaking the first list apart, and using append_element.
append_list([], L, L).
append_list([H|T], L, NewList) :-
append_element(H, L, NL),
append_list(T, NL, NL).
When I try to run append_list,
?- append_list([1,2], [3, 4, 5], NL).
I get back false. Instead of
NL = [2, 1, 3, 4, 5].
Why?

Matrix multiplication with Prolog

I have to write a predicate the predicate product/3 which receives two matrix and returns the matrix multiplication of them if possible or fail otherwise. (This means if the matrices fullfill the requirement [n x p] [p x y], then return the multiplication with dimensions [n x y])
Example:
product(M1, M2, R)
?- product([[1,2],[3,4],[5,6]], [[1,1,1],[1,1,1]], M).
M = [[3, 3, 3], [7, 7, 7], [11, 11, 11]];
No
For this I have two codes that index the nth row on a matrix rowI and that index the nth column columnI (I explain how they work in the code below).
%Predicate: rowI(M, I, RI)
%Input rowI([[1,2],[3,4],[5,6]], 2, RI).
% RI = [3,4];
rowI([H|_],1,H):-!.
rowI([_|T],I,X) :-
I1 is I-1,
rowI(T,I1,X).
% columnJ(M, J, CJ)
%Input columnJ([[1,2],[3,4],[5,6]], 1, CJ).
% CJ = [1,3,5];
columnJ([],_,[]).
columnJ([H|T], I, [R|X]):-
rowI(H, I, R),
columnJ(T,I,X).
product([H|T], M2, [R|X]):-
columnJ(M2, C, Z),
mult(H, Z , X),
product(T, M2 , X).
I was thinking somehow by grabbing the head of the M1 (which will be each row) and then multiplied for each column in M2 and after adding the multiplication this list will be the new row. So (C would have to be a counter starting from 1 to the length of M2and then mult I was just thinking on having it multiplying the lists. (mult is not defined at this point, just a guess).
Here I am trying to explain the way I am thinking it.. but there may be a simplier way. What do you think?
Compact code (with the help of higher order constructs maplist and foldl).
I left on purpose the expressions unevaluated, so the result could be reused in more general context:
:- module(matrix_multiply,
[matrix_multiply/3
,dot_product/3
]).
:- use_module(library(clpfd), [transpose/2]).
%% matrix_multiply(+X,+Y,-M) is det.
%
% X(N*P),Y(P*M),M(N*M)
%
matrix_multiply(X,Y,M) :-
transpose(Y,T),
maplist(row_multiply(T),X,M).
row_multiply(T,X,M) :-
maplist(dot_product(X),T,M).
dot_product([X|Xs],[T|Ts],M) :-
foldl(mul,Xs,Ts,X*T,M).
mul(X,T,M,M+X*T).
edit
usage (save in a file named matrix_multiply.pl):
?- [matrix_multiply].
?- matrix_multiply([[1,2],[3,4],[5,6]], [[1,1,1],[1,1,1]],R),maplist(maplist(is),C,R).
R = [[1*1+2*1, 1*1+2*1, 1*1+2*1], [3*1+4*1, 3*1+4*1, 3*1+4*1], [5*1+6*1, 5*1+6*1, 5*1+6*1]],
C = [[3, 3, 3], [7, 7, 7], [11, 11, 11]].
The numeric evaluation is explicitly requested by ,maplist(maplist(is),C,R).
R holds the symbolic expressions, C the values.
edit
Just to note that dependency from clpfd:transpose is easy to remove: here is an alternative 'one-liner' definition based on nth/3 and library(yall)
mat_transpose([R1|Rs],T) :- findall(V,(
nth1(Col,R1,_),
maplist({Col}/[R,C]>>nth1(Col,R,C),[R1|Rs],V)),T).

How to create a list of numbers that add up to a specific number

I need some help writing a predicate in Prolog that, given a number as input, returns a list of lists with numbers that add up to it.
Let's call the predicate addUpList/2, it should work like this:
?- addUpList(3,P).
P = [[1,2], [2,1], [1,1,1]]. % expected result
I'm having so much trouble figuring this out I'm beginning to think it's impossible. Any ideas? Thanks in advance.
Try this:
condense([], Rs, Rs).
condense([X|Xs], Ys, Zs) :-
condense(Xs, [X|Ys], Zs).
condense([X, Y|Xs], Ys, Zs) :-
Z is X + Y,
condense([Z|Xs], Ys, Zs).
condense(Xs, Rs) :-
condense(Xs, [], Rs).
expand(0, []).
expand(N, [1|Ns]) :-
N > 0,
N1 is N - 1,
expand(N1, Ns).
addUpList(N, Zs) :-
expand(N, Xs),
findall(Ys, condense(Xs, Ys), Zs).
Let me know what marks I get. :-)
The rule num_split/2 generates ways of splitting a number into a list, where the first element X is any number between 1 and N and the rest of the list is a split of N-X.
num_split(0, []).
num_split(N, [X | List]) :-
between(1, N, X),
plus(X, Y, N),
num_split(Y, List).
In order to get all such splits, just call findall/3 on num_split/2.
add_up_list(N, Splits) :-
findall(Split, num_split(N, Split), Splits).
Usage example:
?- add_up_list(4, Splits).
Splits =
[[1, 1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 3], [2, 1, 1], [2, 2], [3, 1], [4]].
See also the post by #hardmath which gives the same answer with a bit more explanation.
The example given in the Question suggests that compositions (ordered partitions) of any positive integer N &leq; 10 are wanted. Note however that the solution [3] for N=3 seems to have been omitted/overlooked. The number of compositions of N is 2^(N-1), so N=10 gives a long list but not an unmanageable one.
It is also desired to collect all such solutions into a list, something that findall/3 can do generically after we write a predicate composition/2 that generates them.
The idea is to pick the first summand, anything between 1 and N, subtract it from the total and recurse (stopping with an empty list when the total reaches zero). SWI-Prolog provides a predicate between/3 that can generate those possible first summands, and Amzi! Prolog provides a similar predicate for/4. For the sake of portability we write our own version here.
summand(Low,High,_) :-
Low > High,
!,
fail.
summand(Low,High,Low).
summand(Low,High,Val) :-
Now is Low + 1,
summand(Now,High,Val).
composition(0,[ ]).
composition(N,[H|T]) :-
summand(1,N,H),
M is N - H,
composition(M,T).
Given the above Prolog source code, compiled or interpreted, a list of all solutions can be had in this way:
?- findall(C,composition(3,C),L).
C = H126
L = [[1, 1, 1], [1, 2], [2, 1], [3]]
Of course some arrangement of such a list of solutions or the omission of the singleton list might be required for your specific application, but this isn't clear as the Question is currently worded.
There are plenty of great answers to this question already, but here is another solution to this problem for you to consider. This program differs from the others in that it is very efficient, and generates non-redundant solutions of lists which are assumed to represent sets of integers which add up to the specified number.
gen(N, L) :-
gen(N-1, N, N, FL),
dup_n(FL, L).
gen(C-F, M, M, [C-F]).
gen(C-F, S, M, [C-F|R]) :-
S < M, C > 1,
C0 is C - 1,
F0 is floor(M / C0),
S0 is S + (C0 * F0),
gen(C0-F0, S0, M, R).
gen(C-F, S, M, R) :-
F > 0,
F0 is F - 1,
S0 is S - C,
gen(C-F0, S0, M, R).
dup_n([], []).
dup_n([_-0|R], L) :-
!, dup_n(R, L).
dup_n([V-F|R], [V|L]) :-
F0 is F - 1,
dup_n([V-F0|R], L).
Your implementation of addUpList/2 can be achieved by:
addUpList(N, P) :-
findall(L, gen(N, L), P).
Which should give you the following behaviour:
?- addUpList(4,L).
L = [[4], [3, 1], [2, 2], [2, 1, 1], [1, 1, 1, 1]].
Note that the list containing one 2 and two 1s only appears once in this result set; this is because gen/4 computes unique sets of integers which add up to the specified number.
This answer is somewhere between
#Kaarel's answer and
#sharky's "efficient" answer.
Like #sharky's code, we impose an ordering relation between adjacent list items to restrict the size of the solution space---knowing how to inflate it if we ever need to. So the solution sets of break_down/2 and gen/2 by #sharky are equal (disregarding list reversal).
And as for performance, consider:
?- time((break_down(40,_),false)).
% 861,232 inferences, 0.066 CPU in 0.066 seconds (100% CPU, 13127147 Lips)
false.
?- time((gen(40,_),false)).
% 8,580,839 inferences, 0.842 CPU in 0.842 seconds (100% CPU, 10185807 Lips)
false.

Resources