Why "..." appears in my answer of matrix in Prolog - matrix

I made a little code for creating a matrix of coordinates (like a chessboard), it's the following:
createMatrix(N,M,R) :- creaMatriu(N,M,A), reversed(R,A).
creaMatriu(N,0,[T]) :- creafila(N,0,T),!.
creaMatriu(N,M,[T|C]) :- creafila(N,M,T), M1 is M-1, creaMatriu(N,M1,C).
creafila(0,M,[[M,0]]):-!.
creafila(N,M,[[M,N]|C]) :-N1 is N-1,creafila(N1,M,C).
reversed(A, B) :- reversed(B, [], A).
reversed([A|B], C, D) :- reverse(N,A),reversed(B, [N|C], D).
reversed([], A, A).
The first time I executed it went well, but when i incremented the dimensions of the matrix, the "dots" at the end of the matrix begin to appear incrementing one coordinate as the dimension rises, as like this:
?- createMatrix(1,1,R).
R = [[[0, 0], [0, 1]], [[1, 0], [1, 1]]] .
?- createMatrix(2,1,R).
R = [[[0, 0], [0, 1], [0, 2]], [[1, 0], [1, 1], [1, 2]]] .
?- createMatrix(2,2,R).
R = [[[0, 0], [0, 1], [0, 2]], [[1, 0], [1, 1], [1, 2]], [[2, 0], [2, 1], [2, 2]]] .
?- createMatrix(3,2,R).
R = [[[0, 0], [0, 1], [0, 2], [0, 3]], [[1, 0], [1, 1], [1, 2], [1, 3]], [[2, 0], [2, 1], [2, 2], [2, 3]]] .
?- createMatrix(3,3,R).
R = [[[0, 0], [0, 1], [0, 2], [0, 3]], [[1, 0], [1, 1], [1, 2], [1, 3]], [[2, 0], [2, 1], [2, 2], [2, 3]], [[3, 0], [3, 1], [3, 2], [3|...]]] .
?- createMatrix(4,3,R).
R = [[[0, 0], [0, 1], [0, 2], [0, 3], [0, 4]], [[1, 0], [1, 1], [1, 2], [1, 3], [1, 4]], [[2, 0], [2, 1], [2, 2], [2, 3], [2|...]], [[3, 0], [3, 1], [3, 2], [3|...], [...|...]]] .
?- createMatrix(4,4,R).
R = [[[0, 0], [0, 1], [0, 2], [0, 3], [0, 4]], [[1, 0], [1, 1], [1, 2], [1, 3], [1, 4]], [[2, 0], [2, 1], [2, 2], [2, 3], [2|...]], [[3, 0], [3, 1], [3, 2], [3|...], [...|...]], [[4, 0], [4, 1], [4|...], [...|...]|...]] .
Anyone have any clue why this happens?
Thank you!

By default, the toplevel loop of SWI prints terms up to depth 10. Deeper parts are replaced by ... You can extend that depth or remove that limit by setting the depth to 0.
?- length(L,10).
L = [_A,_B,_C,_D,_E,_F,_G,_H,_I|...].
?- current_prolog_flag(toplevel_print_options,V).
V = [quoted(true),portray(true),max_depth(10),spacing(next_argument)].
?- set_prolog_flag(toplevel_print_options, [quoted(true), portray(true), max_depth(0), spacing(next_argument)]).
true.
?- length(L,10).
L = [_A,_B,_C,_D,_E,_F,_G,_H,_I,_J].
— update: in newer versions of SWI, another flag must be changed:
?- current_prolog_flag(T,V), atom_concat(_,options,T).
T = answer_write_options,
V = [quoted(true),portray(true),max_depth(10),spacing(next_argument)]
; true.
?- set_prolog_flag(answer_write_options, [quoted(true), portray(true), max_depth(0), spacing(next_argument)]).
true.

Related

Accumulator for each_with_object keeps re-initializing

I'm trying to write a generalized cartesian product, where input data of [n1, n2, ...ni] produces output data that is an array of [m1, m2, ...mi] for all mj such that 0 <= mj < nj. I understand the routine below would produce a somewhat folded version of that, but I'm trying to keep the example code as simple as possible. My immediate problem is that the second block variable (accumulator), which I understand is supposed to update for each iteration of the block, is not doing so:
#!/usr/bin/ruby
def gcp(dims)
first = dims.shift
dims.each_with_object((0...first).to_a) do |dim, v|
puts "\nv: #{v}, dim: #{dim}"
p v.product((0...dim).to_a)
end
end
gcp([3,2,4])
This produces the following output:
v: [0, 1, 2], dim: 2
[[0, 0], [0, 1], [1, 0], [1, 1], [2, 0], [2, 1]]
v: [0, 1, 2], dim: 4
[[0, 0], [0, 1], [0, 2], [0, 3], [1, 0], [1, 1], [1, 2], [1, 3], [2, 0], [2, 1], [2, 2], [2, 3]]
The p method is a passthrough, so the return value of the block should be [[0, 0], [0, 1], [1, 0], [1, 1], [2, 0], [2, 1]] on the first iteration, and that should be the value of v on the second iteration, unless I gravely misunderstand each_with_object.
Each iteration gets the same object, so you either need to mutate the object inside the block, or use reduce.
def gcp(dims)
first = dims.shift
dims.reduce((0...first).to_a) do |v, dim|
puts "\nv: #{v}, dim: #{dim}"
p v.product((0...dim).to_a)
end
end
gcp([3,2,4])
Results in:
v: [0, 1, 2], dim: 2
[[0, 0], [0, 1], [1, 0], [1, 1], [2, 0], [2, 1]]
v: [[0, 0], [0, 1], [1, 0], [1, 1], [2, 0], [2, 1]], dim: 4
[[[0, 0], 0], [[0, 0], 1], [[0, 0], 2], [[0, 0], 3], [[0, 1], 0], [[0, 1], 1], [[0, 1], 2], [[0, 1], 3], [[1, 0], 0], [[1, 0], 1], [[1, 0], 2], [[1, 0], 3], [[1, 1], 0], [[1, 1], 1], [[1, 1], 2], [[1, 1], 3], [[2, 0], 0], [[2, 0], 1], [[2, 0], 2], [[2, 0], 3], [[2, 1], 0], [[2, 1], 1], [[2, 1], 2], [[2, 1], 3]]
I confess I don't fully understand the question, but I've addressed a similar problem that may explain why v is not being updated by your code.
Let's step through your code, returning the desired result rather than displaying it along the way.
dims = [3,2,4]
first = dims.shift
#=> 3
dims
#=> [2, 4] dims
The expression
dims.each_with_object((0...first).to_a) do |dim, v|
v.product((0...dim).to_a)
end
is effectively the same as
v = []
dims.each do |dim|
v.product((0...dim).to_a)
end
v #=> []
That v is still an empty array at the end should not be a surprise, as the value of v is not altered within the loop. The return value of v.product((0...dim).to_a) is shot out into space, never to be seen again. You need an assignment statement within the loop.
Now consider the following.
dims = [3,2,4]
v = []
dims.each do |n|
v << (0...n).to_a
end
v #=> [[0, 1, 2], [0, 1], [0, 1, 2, 3]]
(or v.push((0..n).to_a)). To use Enumerable#each_with_object we would modify the above code by removing the first (v = []) and last (v) statements, changing each to each_with_object([]) (the argument being the initial value of the object the method will return) and add a block variable v, which holds the object:
dims.each_with_object([]) do |n,v|
v << (0...n).to_a
end
#=> [[0, 1, 2], [0, 1], [0, 1, 2, 3]]
We can simplify this using Emumerable#map:
dims.map do |n|
(0...n).to_a
end
#=> [[0, 1, 2], [0, 1], [0, 1, 2, 3]]
Depending on your needs, you may prefer using Emumerable#flat_map:
dims.flat_map do |n|
(0...n).to_a
end
#=> [0, 1, 2, 0, 1, 0, 1, 2, 3]

Creating a list of Domino

I'm trying to get a sorted list of Domino with a list of Domino
My code currently looks like:
listdomino(_,[],[],[]).
listdomino([I,J],M,Start,Fin):-
(( member([J,K],M),
delete(M,[J,K],M2),
append([[J,K]],Fin1,Fin),
listdomino([I,K],M2,Start,Fin1)
)
;
( member([K,I],M),
delete(M,[K,I],M2),
append(Start1,[[K,I]],Start),
listdomino([K,J],M2,Start1,Fin)
)
).
listdominoSorted(X,M,Out):-
append(Start,[X],K),
append(K,Fin,Out),
listdomino(X,M,Start,Fin).
Actual outcome:
?- listdominoSorted([1,2],[[2,1],[2,2]],L).
L = [[1, 2], [2, 2], [2, 1]] ;
L = [[2, 1], [1, 2], [2, 2]] ;
L = [[2, 1], [1, 2], [2, 2]] ;
L = [[2, 2], [2, 1], [1, 2]] ;
The program returns [[2, 1], [1, 2], [2, 2]] twice
and doesn't exit after that.
Desired outcome:
?- listdominoSorted([1,2],[[2,1],[2,2]],L).
L = [[1, 2], [2, 2], [2, 1]] ;
L = [[2, 1], [1, 2], [2, 2]] ;
L = [[2, 2], [2, 1], [1, 2]] ;
false
How can I solve this problem?
I looked at your code for a minute or two but after seeing the use of delete/3 the warning bells went off and I looked at other examples. While this related answer does not answer your question, the statement
I suggest instead to have a quick check for validity, and let Prolog work out the insertion points.
lead me to trying a generate and test methodology for which Prolog is well suited.
First the test part:
No dominoes are valid.
domino_test([]).
One domino is valid.
domino_test([[_,_]]).
When ever two dominoes share the same counts (D_1) they are valid.
This is recursively valid.
domino_test([[_,D_1],[D_1,D_2]|T]) :-
domino_test([[D_1,D_2]|T]).
Next to generate the values.
This is really just a permutation of the dominoes.
?- permutation([[1,2],[2,1],[2,2]],P).
P = [[1, 2], [2, 1], [2, 2]] ;
P = [[1, 2], [2, 2], [2, 1]] ;
P = [[2, 1], [1, 2], [2, 2]] ;
P = [[2, 1], [2, 2], [1, 2]] ;
P = [[2, 2], [1, 2], [2, 1]] ;
P = [[2, 2], [2, 1], [1, 2]] ;
false.
Putting the permutation with the test in one predicates gives:
list_domino(L,P) :-
permutation(L,P),
domino_test(P).
All of the code
domino_test([]).
domino_test([[_,_]]).
domino_test([[_,D_1],[D_1,D_2]|T]) :-
domino_test([[D_1,D_2]|T]).
list_domino(L,P) :-
permutation(L,P),
domino_test(P).
Example:
?- list_domino([[1,2],[2,1],[2,2]],P).
P = [[1, 2], [2, 2], [2, 1]] ;
P = [[2, 1], [1, 2], [2, 2]] ;
P = [[2, 2], [2, 1], [1, 2]] ;
false.
I suspect your given test case is a simple case and there needs to be a modification to this, but I will let you check it and see.

Only one array is returned where I am expecting array of array in Ruby

When I run the following in irb, it returns what I want. But when I run rspec -c intersection_spec.rb, it returns [[0,0]]. Why don't I get the desired results with rspec?
What am I doing wrong here?
intersection.rb
class Intersection
def self.create_arr(xa1, ya1, xa2, ya2)
((xa1.to_i)..(xa2.to_i)).to_a.product(((ya1.to_i)..(ya2.to_i)).to_a)
end
end
intersection_spec.rb
require './spec_helper'
require './intersection.rb'
describe Intersection do
#xa1 = 0.0
#ya1 = 0.0
#xa2 = 5.0
#ya2 = 5.0
#xb1 = 1.0
#yb1 = 1.0
#xb2 = 4.0
#yb2 = 4.0
specify{ expect(Intersection.create_arr(#xa1, #ya1, #xa2, #ya2)).to eq [[0,0],
[0,1], [0,2], [0,3], [0,4], [0,5], [1,0], [1,1], [1,2], [1,3], [1,4], [1,5],
[2,0], [2,1], [2,2], [2,3], [2,4], [2,5], [3,0], [3,1], [3,2], [3,3], [3,4],
[3,5], [4,0], [4,1], [4,2], [4,3], [4,4], [4,5], [5,0], [5,1], [5,2], [5,3],
[5,4], [5,5]] }
end
Run rspec.
rspec -c intersection_spec.rb
expected: [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4], [0, 5], [1, 0], [1, 1],
[1, 2], [1, 3], [1, 4], [1, 5], [2, 0], [2, 1], [2, 2], [2, 3], [2, 4], [2, 5],
[3, 0], [3, 1], [3, 2], [3, 3], [3, 4], [3, 5], [4, 0], [4, 1], [4, 2], [4, 3],
[4, 4], [4, 5], [5, 0], [5, 1], [5, 2], [5, 3], [5, 4], [5, 5]]
got: [[0, 0]]
In irb
irb(main):029:0> #xa1 = 0.0
=> 0.0
irb(main):030:0> #ya1 = 0.0
=> 0.0
irb(main):031:0> #xa2 = 5.0
=> 5.0
irb(main):032:0> #ya2 = 5.0
=> 5.0
irb(main):033:0> #xb1 = 1.0
=> 1.0
irb(main):034:0> #yb1 = 1.0
=> 1.0
irb(main):035:0> #xb2 = 4.0
=> 4.0
irb(main):036:0> #yb2 = 4.0
=> 4.0
irb(main):037:0> def self.create_arr(xa1, ya1, xa2, ya2)
irb(main):038:1> ((xa1.to_i)..(xa2.to_i)).to_a.product(((ya1.to_i)..(ya2.to_i)).to_a)
irb(main):039:1> end
=> nil
irb(main):040:0> create_arr(#xa1, #ya1, #xa2, #ya2)
=> [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4], [0, 5], [1, 0], [1, 1], [1, 2],
[1, 3], [1, 4], [1, 5], [2, 0], [2, 1], [2, 2], [2, 3], [2, 4], [2, 5], [3, 0],
[3, 1], [3, 2], [3, 3], [3, 4], [3, 5], [4, 0], [4, 1], [4, 2], [4, 3], [4, 4],
[4, 5], [5, 0], [5, 1], [5, 2], [5, 3], [5, 4], [5, 5]]
I can't say for sure why it fails your way, but I noticed it does work when you don't make the initial coordinates instance variables, so
#xa1 = 0.0
#ya1 = 0.0
#xa2 = 5.0
#ya2 = 5.0
becomes
xa1 = 0.0
ya1 = 0.0
xa2 = 5.0
ya2 = 5.0
then pass those into #create_array.

How to find all possible indices of an array

Supposing we have an array with this shape: [2, 5]. The possible index combinations are:
[
[0, 0],
[0, 1],
[0, 2],
[0, 3],
[0, 4],
[1, 0],
[1, 1],
[1, 2],
[1, 3],
[1, 4]
]
If the array has n dimension(s), is there a simple way to generate the indices in Ruby?
This should work:
def coordinates(first, *others)
(0...first).to_a.product(*others.map { |to| (0...to).to_a })
end
coordinates(2, 5)
#=> [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4],
# [1, 0], [1, 1], [1, 2], [1, 3], [1, 4]]
coordinates(4, 3, 3)
#=> [[0, 0, 0], [0, 0, 1], [0, 0, 2],
# [0, 1, 0], [0, 1, 1], [0, 1, 2],
# [0, 2, 0], [0, 2, 1], [0, 2, 2],
# [1, 0, 0], [1, 0, 1], [1, 0, 2],
# [1, 1, 0], [1, 1, 1], [1, 1, 2],
# [1, 2, 0], [1, 2, 1], [1, 2, 2],
# [2, 0, 0], [2, 0, 1], [2, 0, 2],
# [2, 1, 0], [2, 1, 1], [2, 1, 2],
# [2, 2, 0], [2, 2, 1], [2, 2, 2],
# [3, 0, 0], [3, 0, 1], [3, 0, 2],
# [3, 1, 0], [3, 1, 1], [3, 1, 2],
# [3, 2, 0], [3, 2, 1], [3, 2, 2]]
Here you go. It may not be pretty, but it seems to work.
def gen_indices(dimensions, solutions = [], current=[], level = 0)
if level < dimensions.length
dimensions[level].times do |i|
current << i
if level == dimensions.length - 1
solutions << current.clone
else
gen_indices(dimensions, solutions, current, level + 1)
end
current.pop
end
end
solutions
end
p gen_indices([4,3,2])
Not sure this is totally correct, but it should help you on the right track:
def combinations(dimensions)
dimensions.inject([]){|total, dimension|
dim = (0...dimension).to_a
total.empty? ? dim : total.product(dim)
}.map(&:flatten)
end
p combinations([2, 5]) #=> [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4], [1, 0], [1, 1], [1, 2], [1, 3], [1, 4]]
p combinations([2, 2, 2]) #=> [[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]]
Try:
a = [[0,1],[0,1,2,3,4]]
res = a[0].product(a[1])

Counting subsets with given sizes of a set

Given a set C with n elements (duplicates allowed) and a partition P of n
P = {i1, i2, ... / i1+i2+... = n}
how many different decompositions of C in subsets of size i1, i2, ... are there ?
Example :
C = {2 2 2 3}
P = {2 2}
C = {2 2} U {2 3}
P = {1 1 2}
C = {2} U {2} U {2 3}
C = {2} U {3} U {2 2}
P = {1 3}
C = {2} U {2 2 3}
C = {3} U {2 2 2}
I have a solution, but it is inefficient when C has more than a dozen of elements.
Thanks in advance
Philippe
The fact that the order of decomposition does not matter to you makes it much harder. That is, you are viewing {2 2} U {2 3} as the same as {2 3} U {2 2}. Still I have an algorithm that is better than what you have, but is not great.
Let me start it with a realistically complicated example. Our set will be A B C D E F F F F G G G G. The partition will be 1 1 1 1 2 2 5.
My first simplification will be to represent the information we care about in the set with the data structure [[2, 4], [5, 1]], meaning 2 elements are repeated 4 times, and 5 are repeated once.
My second apparent complication will be to represent the partition with [[5, 1, 1], [2, 2, 1], [4, 1, 1]. The pattern may not be obvious. Each entry is of the form [size, count, frequency]. So the one distinct instance of 2 partitions of size 2 turn into [2, 2, 1]. We're not using frequency yet, but it is counting distinguishable piles of the same size and commonness.
Now we're going to recurse as follows. We'll take the most common element, and find all of the ways to use it up. So in our case we take one of the piles of size 4, and find that we can divide it as follows, rearranging each remaining partition strategy in lexicographic order:
[4] leaving [[1, 1, 1], [2, 2, 1], [1, 4, 1]] = [[2, 2, 1], [1, 4, 1], [1, 1, 1]].
[3, [1, 0], 0] leaving [[2, 1, 1], [1, 1, 1], [2, 1, 1], [1, 4, 1]] = [[2, 1, 2], [1, 4, 1], [1, 1, 1]. (Note that we're now using frequency.)
[3, 0, 1] leaving [[2, 1, 1], [2, 2, 1], [0, 1, 1], [1, 3, 1]] = [[2, 2, 1], [2, 1, 1], [1, 3, 1]]
[2, [2, 0], 0] leaving [[3, 1, 1], [0, 1, 1], [2, 1, 1], [1, 4, 1]] = [[3, 1, 1], [2, 1, 1], [1, 4, 1]]
[2, [1, 1], 0] leaving [[3, 1, 1], [1, 2, 1], [1, 4, 1]] = [[3, 1, 1], [1, 4, 1], [1, 2, 1]]
[2, [1, 0], [1]] leaving [[3, 1, 1], [1, 1, 1], [2, 1, 1], [0, 1, 1], [1, 3, 1]] = [[3, 1, 1], [2, 1, 1], [1, 4, 1], [1, 1, 1]]
[2, 0, [1, 1]] leaving `[[3, 1, 1], [2, 2, 1], [0, 2, 1], [1, 2, 1]] = [[3, 1, 1], [2, 2, 1], [1, 2, 1]]1
[1, [2, 1]] leaving [[4, 1, 1], [0, 1, 1], [1, 1, 1], [1, 4, 1]] = [[4, 1, 1], [1, 4, 1], [1, 1, 1]]
[1, [2, 0], [1]] leaving [[4, 1, 1], [0, 1, 1], [2, 1, 1], [0, 1, 1], [1, 3, 1]] = [[4, 1, 1], [2, 1, 1], [1, 3, 1]]
[1, [1, 0], [1, 1]] leaving [[4, 1, 1], [1, 1, 1], [2, 1, 1], [0, 2, 1], [1, 2, 1]] = [[4, 1, 1], [2, 1, 1], [1, 2, 1], [1, 1, 1]]
[1, 0, [1, 1, 1]] leaving [[4, 1, 1], [2, 2, 1], [0, 3, 1], [1, 1, 1]] = [[4, 1, 1], [2, 2, 1], [1, 1, 1]]
[0, [2, 2]] leaving [[5, 1, 1], [0, 2, 1], [1, 4, 1]] = [[5, 1, 1], [1, 4, 1]]
[0, [2, 1], [1]] leaving [[5, 1, 1], [0, 1, 1], [1, 1, 1], [0, 1, 1], [1, 3, 1]] = [[5, 1, 1], [1, 3, 1], [1, 1, 1]]
[0, [2, 0], [1, 1]] leaving [[5, 1, 1], [0, 2, 1], [2, 1, 1], [0, 2, 1], [1, 2, 1]] = [[5, 1, 1], [2, 1, 1], [1, 2, 1]]
[0, [1, 1], [1, 1]] leaving [[5, 1, 1], [1, 2, 1], [0, 2, 1], [1, 2, 1]] = [[5, 1, 1,], [1, 2, 2]]
[0, [1, 0], [1, 1, 1]] leaving [[5, 1, 1], [1, 1, 1], [2, 1, 1], [0, 3, 1], [1, 1, 1]] = [[5, 1, 1], [2, 1, 1], [1, 1, 2]]
[0, 0, [1, 1, 1, 1]] leaving [[5, 1, 1], [2, 2, 1], [0, 4, 1]] = [[5, 1, 1], [2, 2, 1]]
Now each of those subproblems can be solved recursively. This may feel like we're on the way to constructing them all, but we aren't, because we memoize the recursive steps. It turns out that there are a lot of ways that the first two groups of 8 can wind up with the same 5 left overs. With memoization we don't need to repeatedly recalculate those solutions.
That said, we'll do better. Groups of 12 elements should not pose a problem. But we're not doing that much better. I wouldn't be surprised if it starts breaking down somewhere around groups of 30 or so elements with interesting sets of partitions. (I haven't coded it. It may be fine at 30 and break down at 50. I don't know where it will break down. But given that you're iterating over sets of partitions, at some fairly small point it will break down.)
All partitions can be found in 2 stages.
First: from P make new ordered partition of n, P_S={P_i1, P_i2, ..., P_ip}, summing identical i's.
P = {1, 1, 1, 1, 2, 2, 5}
P_S = (4, 4, 5)
Make partitions {C_i1, C_i2, ..., C_ip} of C with respect to P_S. Note, C_ix is multi-set like C. It is partitioning C into multi-sets by sizes of final partitions.
Second: for each {C_i1, C_i2, ..., C_ip} and for each ix, x={1,2,...,p} find number of partitions of C_ix into t (number of ix's in P) sets with ix elements. Call this number N(C_ix,ix,t).
Total number of partitions is:
sum by all {C_i1, C_i2, ..., C_ip} ( product N(C_ix,ix,t) ix={1,2,...,p} )
First part can be done recursively quite simple. Second is more complicated. Partition of multi-set M into n parts with k elements is same as finding all partially sorted list with elements from M. Partially order list is of type:
a_1_1, a_1_2, ..., a_1_k, a_2_1, a_2_2, ..., a_2_k, ....
Where a_i_x <= a_i_y if x < y and (a_x_1, a_x_2, ..., a_x_k) lexicographic <= (a_y_1, a_y_2, ..., a_y_k) if x < y. With these 2 conditions it is possible to create all partition from N(C_ix,ix,t) recursively.
For some cases N(C_ix,ix,t) is easy to calculate. Define |C_ix| as number of different elements in multi-set C_ix.
if t = 1 than 1
if |C_ix| = 1 than 1
if |C_ix| = 2 than (let m=minimal number of occurrences of elements in C_ix) floor(m/2) + 1
in general if |C_ix| = 2 than partition of m in numbers <= t.

Resources