Lines that start with %
are comments
Most programming langues have methods and functions. Prolog has predicates which succeed or fail and can pass values along in variables.
Predicates are denoted by their name and arity as such, transpose/2
.
Most programming languages use assignment, but Prolog uses unification. For the special case of solving math expressions Prolog has is/2
:- use_module(library(clpfd)).
Is a directive :- that brings in a library named clpfd. clpfd is used for constraints normally but in this case is used to access the transpose/2
predicate.
dot(V1, V2, N) :-
maplist(product,V1,V2,P),
sumlist(P,N).
dot/3
is a predicate that takes in two vectors, I am guessing implemented as Prolog list in this case, and binds the dot product as N
.
maplist/4 applies the product/3 predicate to the values in V1
and V2
to create the list P
.
sumlist/2 adds up the list of values in P
and binds N
.
product(N1,N2,N3) :- N3 is N1*N2.
product/3
is a helper predicate to take two numbers N1
and N2
and multiply them.
N3 is N1*N2
can be thought of as N3 = (N1 * N2)
mmult(M1, M2, M3) :-
transpose(M2,MT),
maplist(mm_helper(MT), M1, M3).
transpose/2 is the typical array transpose.
maplist/3
applies the helper predicate mm_helper/3
using MT
and M1
to bind M3
.
mm_helper(M2, I1, M3) :-
maplist(dot(I1), M2, M3).
maplist/3
applies dot/3
to I1
and M2
to bind M3
.
I take it you took the code from RosettaCode or it crossed paths with such.
Example run:
?- mmult([[1,2],[3,4]],[[5,6],[7,8]],R).
R = [[19, 22], [43, 50]] ;
true.
Verification of example.
From comment.
What does I1 represents in mm_helper predicate?
See trace below for details
The signature of mm_helper/3
is mm_helper(M2, I1, M3)
so the second parameter contains I1
. From the lines in the trace
Exit: (11) mm_helper([[5, 7], [6, 8]], [3, 4], [43, 50])
the second parameter is [3,4]
.
Call: (10) mm_helper([[5, 7], [6, 8]], [1, 2], _3596)
the second parameter is [1,2]
.
So I2
is a row slice of the first matrix.
Be careful of what you ask for, you might get more than expected? :)
Full trace of run:
This is only here because of a question in the comment.
[trace] ?- mmult([[1,2],[3,4]],[[5,6],[7,8]],R).
Call: (8) mmult([[1, 2], [3, 4]], [[5, 6], [7, 8]], _3238)
Unify: (8) mmult([[1, 2], [3, 4]], [[5, 6], [7, 8]], _3238)
Call: (9) clpfd:transpose([[5, 6], [7, 8]], _3536)
Unify: (9) clpfd:transpose([[5, 6], [7, 8]], _3536)
Call: (10) error:must_be(list(list), [[5, 6], [7, 8]])
Unify: (10) error:must_be(list(list), [[5, 6], [7, 8]])
Exit: (10) error:must_be(list(list), [[5, 6], [7, 8]])
Call: (10) clpfd:lists_transpose([[5, 6], [7, 8]], _3540)
Unify: (10) clpfd:lists_transpose([[5, 6], [7, 8]], _3540)
Call: (11) clpfd:'__aux_maplist/2_same_length+1'([[7, 8]], [5, 6])
Unify: (11) clpfd:'__aux_maplist/2_same_length+1'([[7, 8]], [5, 6])
Call: (12) lists:same_length([5, 6], [7, 8])
Unify: (12) lists:same_length([5, 6], [7, 8])
Exit: (12) lists:same_length([5, 6], [7, 8])
Call: (12) clpfd:'__aux_maplist/2_same_length+1'([], [5, 6])
Unify: (12) clpfd:'__aux_maplist/2_same_length+1'([], [5, 6])
Exit: (12) clpfd:'__aux_maplist/2_same_length+1'([], [5, 6])
Exit: (11) clpfd:'__aux_maplist/2_same_length+1'([[7, 8]], [5, 6])
^ Call: (11) apply:foldl(transpose_, [5, 6], _3548, [[5, 6], [7, 8]], _3552)
^ Unify: (11) apply:foldl(clpfd:transpose_, [5, 6], _3554, [[5, 6], [7, 8]], _3558)
Call: (12) apply:foldl_([5, 6], _3552, clpfd:transpose_, [[5, 6], [7, 8]], _3558)
Unify: (12) apply:foldl_([5, 6], [_3536|_3538], clpfd:transpose_, [[5, 6], [7, 8]], _3564)
Call: (13) clpfd:transpose_(5, _3536, [[5, 6], [7, 8]], _3562)
Unify: (13) clpfd:transpose_(5, _3536, [[5, 6], [7, 8]], _3562)
Call: (14) clpfd:'__aux_maplist/4_list_first_rest+0'([[5, 6], [7, 8]], _3536, _3560)
Unify: (14) clpfd:'__aux_maplist/4_list_first_rest+0'([[5, 6], [7, 8]], [_3542|_3544], [_3548|_3550])
Call: (15) clpfd:list_first_rest([5, 6], _3542, _3548)
Unify: (15) clpfd:list_first_rest([5, 6], 5, [6])
Exit: (15) clpfd:list_first_rest([5, 6], 5, [6])
Call: (15) clpfd:'__aux_maplist/4_list_first_rest+0'([[7, 8]], _3544, _3550)
Unify: (15) clpfd:'__aux_maplist/4_list_first_rest+0'([[7, 8]], [_3554|_3556], [_3560|_3562])
Call: (16) clpfd:list_first_rest([7, 8], _3554, _3560)
Unify: (16) clpfd:list_first_rest([7, 8], 7, [8])
Exit: (16) clpfd:list_first_rest([7, 8], 7, [8])
Call: (16) clpfd:'__aux_maplist/4_list_first_rest+0'([], _3556, _3562)
Unify: (16) clpfd:'__aux_maplist/4_list_first_rest+0'([], [], [])
Exit: (16) clpfd:'__aux_maplist/4_list_first_rest+0'([], [], [])
Exit: (15) clpfd:'__aux_maplist/4_list_first_rest+0'([[7, 8]], [7], [[8]])
Exit: (14) clpfd:'__aux_maplist/4_list_first_rest+0'([[5, 6], [7, 8]], [5, 7], [[6], [8]])
Exit: (13) clpfd:transpose_(5, [5, 7], [[5, 6], [7, 8]], [[6], [8]])
Call: (13) apply:foldl_([6], _3538, clpfd:transpose_, [[6], [8]], _3588)
Unify: (13) apply:foldl_([6], [_3566|_3568], clpfd:transpose_, [[6], [8]], _3594)
Call: (14) clpfd:transpose_(6, _3566, [[6], [8]], _3592)
Unify: (14) clpfd:transpose_(6, _3566, [[6], [8]], _3592)
Call: (15) clpfd:'__aux_maplist/4_list_first_rest+0'([[6], [8]], _3566, _3590)
Unify: (15) clpfd:'__aux_maplist/4_list_first_rest+0'([[6], [8]], [_3572|_3574], [_3578|_3580])
Call: (16) clpfd:list_first_rest([6], _3572, _3578)
Unify: (16) clpfd:list_first_rest([6], 6, [])
Exit: (16) clpfd:list_first_rest([6], 6, [])
Call: (16) clpfd:'__aux_maplist/4_list_first_rest+0'([[8]], _3574, _3580)
Unify: (16) clpfd:'__aux_maplist/4_list_first_rest+0'([[8]], [_3584|_3586], [_3590|_3592])
Call: (17) clpfd:list_first_rest([8], _3584, _3590)
Unify: (17) clpfd:list_first_rest([8], 8, [])
Exit: (17) clpfd:list_first_rest([8], 8, [])
Call: (17) clpfd:'__aux_maplist/4_list_first_rest+0'([], _3586, _3592)
Unify: (17) clpfd:'__aux_maplist/4_list_first_rest+0'([], [], [])
Exit: (17) clpfd:'__aux_maplist/4_list_first_rest+0'([], [], [])
Exit: (16) clpfd:'__aux_maplist/4_list_first_rest+0'([[8]], [8], [[]])
Exit: (15) clpfd:'__aux_maplist/4_list_first_rest+0'([[6], [8]], [6, 8], [[], []])
Exit: (14) clpfd:transpose_(6, [6, 8], [[6], [8]], [[], []])
Call: (14) apply:foldl_([], _3568, clpfd:transpose_, [[], []], _3618)
Unify: (14) apply:foldl_([], [], clpfd:transpose_, [[], []], [[], []])
Exit: (14) apply:foldl_([], [], clpfd:transpose_, [[], []], [[], []])
Exit: (13) apply:foldl_([6], [[6, 8]], clpfd:transpose_, [[6], [8]], [[], []])
Exit: (12) apply:foldl_([5, 6], [[5, 7], [6, 8]], clpfd:transpose_, [[5, 6], [7, 8]], [[], []])
^ Exit: (11) apply:foldl(clpfd:transpose_, [5, 6], [[5, 7], [6, 8]], [[5, 6], [7, 8]], [[], []])
Exit: (10) clpfd:lists_transpose([[5, 6], [7, 8]], [[5, 7], [6, 8]])
Exit: (9) clpfd:transpose([[5, 6], [7, 8]], [[5, 7], [6, 8]])
Call: (9) '__aux_maplist/3_mm_helper+1'([[1, 2], [3, 4]], _3238, [[5, 7], [6, 8]])
Unify: (9) '__aux_maplist/3_mm_helper+1'([[1, 2], [3, 4]], [_3596|_3598], [[5, 7], [6, 8]])
Call: (10) mm_helper([[5, 7], [6, 8]], [1, 2], _3596)
Unify: (10) mm_helper([[5, 7], [6, 8]], [1, 2], _3596)
Call: (11) '__aux_maplist/3_dot+1'([[5, 7], [6, 8]], _3596, [1, 2])
Unify: (11) '__aux_maplist/3_dot+1'([[5, 7], [6, 8]], [_3602|_3604], [1, 2])
Call: (12) dot([1, 2], [5, 7], _3602)
Unify: (12) dot([1, 2], [5, 7], _3602)
Call: (13) '__aux_maplist/4_product+0'([1, 2], [5, 7], _3626)
Unify: (13) '__aux_maplist/4_product+0'([1, 2], [5, 7], [_3608|_3610])
Call: (14) product(1, 5, _3608)
Unify: (14) product(1, 5, _3608)
Call: (15) _3608 is 1*5
Exit: (15) 5 is 1*5
Exit: (14) product(1, 5, 5)
Call: (14) '__aux_maplist/4_product+0'([2], [7], _3610)
Unify: (14) '__aux_maplist/4_product+0'([2], [7], [_3620|_3622])
Call: (15) product(2, 7, _3620)
Unify: (15) product(2, 7, _3620)
Call: (16) _3620 is 2*7
Exit: (16) 14 is 2*7
Exit: (15) product(2, 7, 14)
Call: (15) '__aux_maplist/4_product+0'([], [], _3622)
Unify: (15) '__aux_maplist/4_product+0'([], [], [])
Exit: (15) '__aux_maplist/4_product+0'([], [], [])
Exit: (14) '__aux_maplist/4_product+0'([2], [7], [14])
Exit: (13) '__aux_maplist/4_product+0'([1, 2], [5, 7], [5, 14])
Call: (13) backward_compatibility:sumlist([5, 14], _3602)
Unify: (13) backward_compatibility:sumlist([5, 14], _3602)
Call: (14) lists:sum_list([5, 14], _3602)
Unify: (14) lists:sum_list([5, 14], _3602)
Exit: (14) lists:sum_list([5, 14], 19)
Exit: (13) backward_compatibility:sumlist([5, 14], 19)
Exit: (12) dot([1, 2], [5, 7], 19)
Call: (12) '__aux_maplist/3_dot+1'([[6, 8]], _3604, [1, 2])
Unify: (12) '__aux_maplist/3_dot+1'([[6, 8]], [_3644|_3646], [1, 2])
Call: (13) dot([1, 2], [6, 8], _3644)
Unify: (13) dot([1, 2], [6, 8], _3644)
Call: (14) '__aux_maplist/4_product+0'([1, 2], [6, 8], _3668)
Unify: (14) '__aux_maplist/4_product+0'([1, 2], [6, 8], [_3650|_3652])
Call: (15) product(1, 6, _3650)
Unify: (15) product(1, 6, _3650)
Call: (16) _3650 is 1*6
Exit: (16) 6 is 1*6
Exit: (15) product(1, 6, 6)
Call: (15) '__aux_maplist/4_product+0'([2], [8], _3652)
Unify: (15) '__aux_maplist/4_product+0'([2], [8], [_3662|_3664])
Call: (16) product(2, 8, _3662)
Unify: (16) product(2, 8, _3662)
Call: (17) _3662 is 2*8
Exit: (17) 16 is 2*8
Exit: (16) product(2, 8, 16)
Call: (16) '__aux_maplist/4_product+0'([], [], _3664)
Unify: (16) '__aux_maplist/4_product+0'([], [], [])
Exit: (16) '__aux_maplist/4_product+0'([], [], [])
Exit: (15) '__aux_maplist/4_product+0'([2], [8], [16])
Exit: (14) '__aux_maplist/4_product+0'([1, 2], [6, 8], [6, 16])
Call: (14) backward_compatibility:sumlist([6, 16], _3644)
Unify: (14) backward_compatibility:sumlist([6, 16], _3644)
Call: (15) lists:sum_list([6, 16], _3644)
Unify: (15) lists:sum_list([6, 16], _3644)
Exit: (15) lists:sum_list([6, 16], 22)
Exit: (14) backward_compatibility:sumlist([6, 16], 22)
Exit: (13) dot([1, 2], [6, 8], 22)
Call: (13) '__aux_maplist/3_dot+1'([], _3646, [1, 2])
Unify: (13) '__aux_maplist/3_dot+1'([], [], [1, 2])
Exit: (13) '__aux_maplist/3_dot+1'([], [], [1, 2])
Exit: (12) '__aux_maplist/3_dot+1'([[6, 8]], [22], [1, 2])
Exit: (11) '__aux_maplist/3_dot+1'([[5, 7], [6, 8]], [19, 22], [1, 2])
Exit: (10) mm_helper([[5, 7], [6, 8]], [1, 2], [19, 22])
Call: (10) '__aux_maplist/3_mm_helper+1'([[3, 4]], _3598, [[5, 7], [6, 8]])
Unify: (10) '__aux_maplist/3_mm_helper+1'([[3, 4]], [_3686|_3688], [[5, 7], [6, 8]])
Call: (11) mm_helper([[5, 7], [6, 8]], [3, 4], _3686)
Unify: (11) mm_helper([[5, 7], [6, 8]], [3, 4], _3686)
Call: (12) '__aux_maplist/3_dot+1'([[5, 7], [6, 8]], _3686, [3, 4])
Unify: (12) '__aux_maplist/3_dot+1'([[5, 7], [6, 8]], [_3692|_3694], [3, 4])
Call: (13) dot([3, 4], [5, 7], _3692)
Unify: (13) dot([3, 4], [5, 7], _3692)
Call: (14) '__aux_maplist/4_product+0'([3, 4], [5, 7], _3716)
Unify: (14) '__aux_maplist/4_product+0'([3, 4], [5, 7], [_3698|_3700])
Call: (15) product(3, 5, _3698)
Unify: (15) product(3, 5, _3698)
Call: (16) _3698 is 3*5
Exit: (16) 15 is 3*5
Exit: (15) product(3, 5, 15)
Call: (15) '__aux_maplist/4_product+0'([4], [7], _3700)
Unify: (15) '__aux_maplist/4_product+0'([4], [7], [_3710|_3712])
Call: (16) product(4, 7, _3710)
Unify: (16) product(4, 7, _3710)
Call: (17) _3710 is 4*7
Exit: (17) 28 is 4*7
Exit: (16) product(4, 7, 28)
Call: (16) '__aux_maplist/4_product+0'([], [], _3712)
Unify: (16) '__aux_maplist/4_product+0'([], [], [])
Exit: (16) '__aux_maplist/4_product+0'([], [], [])
Exit: (15) '__aux_maplist/4_product+0'([4], [7], [28])
Exit: (14) '__aux_maplist/4_product+0'([3, 4], [5, 7], [15, 28])
Call: (14) backward_compatibility:sumlist([15, 28], _3692)
Unify: (14) backward_compatibility:sumlist([15, 28], _3692)
Call: (15) lists:sum_list([15, 28], _3692)
Unify: (15) lists:sum_list([15, 28], _3692)
Exit: (15) lists:sum_list([15, 28], 43)
Exit: (14) backward_compatibility:sumlist([15, 28], 43)
Exit: (13) dot([3, 4], [5, 7], 43)
Call: (13) '__aux_maplist/3_dot+1'([[6, 8]], _3694, [3, 4])
Unify: (13) '__aux_maplist/3_dot+1'([[6, 8]], [_3734|_3736], [3, 4])
Call: (14) dot([3, 4], [6, 8], _3734)
Unify: (14) dot([3, 4], [6, 8], _3734)
Call: (15) '__aux_maplist/4_product+0'([3, 4], [6, 8], _3758)
Unify: (15) '__aux_maplist/4_product+0'([3, 4], [6, 8], [_3740|_3742])
Call: (16) product(3, 6, _3740)
Unify: (16) product(3, 6, _3740)
Call: (17) _3740 is 3*6
Exit: (17) 18 is 3*6
Exit: (16) product(3, 6, 18)
Call: (16) '__aux_maplist/4_product+0'([4], [8], _3742)
Unify: (16) '__aux_maplist/4_product+0'([4], [8], [_3752|_3754])
Call: (17) product(4, 8, _3752)
Unify: (17) product(4, 8, _3752)
Call: (18) _3752 is 4*8
Exit: (18) 32 is 4*8
Exit: (17) product(4, 8, 32)
Call: (17) '__aux_maplist/4_product+0'([], [], _3754)
Unify: (17) '__aux_maplist/4_product+0'([], [], [])
Exit: (17) '__aux_maplist/4_product+0'([], [], [])
Exit: (16) '__aux_maplist/4_product+0'([4], [8], [32])
Exit: (15) '__aux_maplist/4_product+0'([3, 4], [6, 8], [18, 32])
Call: (15) backward_compatibility:sumlist([18, 32], _3734)
Unify: (15) backward_compatibility:sumlist([18, 32], _3734)
Call: (16) lists:sum_list([18, 32], _3734)
Unify: (16) lists:sum_list([18, 32], _3734)
Exit: (16) lists:sum_list([18, 32], 50)
Exit: (15) backward_compatibility:sumlist([18, 32], 50)
Exit: (14) dot([3, 4], [6, 8], 50)
Call: (14) '__aux_maplist/3_dot+1'([], _3736, [3, 4])
Unify: (14) '__aux_maplist/3_dot+1'([], [], [3, 4])
Exit: (14) '__aux_maplist/3_dot+1'([], [], [3, 4])
Exit: (13) '__aux_maplist/3_dot+1'([[6, 8]], [50], [3, 4])
Exit: (12) '__aux_maplist/3_dot+1'([[5, 7], [6, 8]], [43, 50], [3, 4])
Exit: (11) mm_helper([[5, 7], [6, 8]], [3, 4], [43, 50])
Call: (11) '__aux_maplist/3_mm_helper+1'([], _3688, [[5, 7], [6, 8]])
Unify: (11) '__aux_maplist/3_mm_helper+1'([], [], [[5, 7], [6, 8]])
Exit: (11) '__aux_maplist/3_mm_helper+1'([]