What is prolog query for finding possible values - prolog

This is my prolog program:
par(0,0).
par(0,1).
par(0,2).
par(1,0).
par(1,2).
par(1,1).
par(2,1).
par(2,0).
par(2,2).
gp(X,Y):- par(X,Z),par(Z,Y).
ggp(X,Y) :- par(X,Z), par(Z,W), par(W,Y).
What query must be used to obtain he possible set of tuples to satisfy the rules gp and ggp
I tried using gp (X,Y) but doesn't give me the tuples.
Also gp and ggp are not related. The tuples that satisfy ggp does not have to necessarily satisfy the rule gp

You only need to "pack" the X and Y together into a tuple, like:
tuple_gp((X,Y)) :-
gp(X,Y).
tuple_ggp((X,Y)) :-
ggp(X,Y).
This then can answer with:
?- tuple_gp(T).
T = (0, 0) ;
T = (0, 1) ;
T = (0, 2) ;
T = (0, 0) ;
T = (0, 2) ;
T = (0, 1) ;
T = (0, 1) ;
T = (0, 0) ;
T = (0, 2) ;
T = (1, 0) ;
T = (1, 1) ;
T = (1, 2) ;
T = (1, 1) ;
T = (1, 0) ;
T = (1, 2) ;
T = (1, 0) ;
T = (1, 2) ;
T = (1, 1) ;
T = (2, 0) ;
T = (2, 2) ;
T = (2, 1) ;
T = (2, 0) ;
T = (2, 1) ;
T = (2, 2) ;
T = (2, 1) ;
T = (2, 0) ;
T = (2, 2).
If you want to generate a list of all possible tuples, you can use findall/3:
?- findall((X,Y),gp(X,Y),L).
L = [ (0, 0), (0, 1), (0, 2), (0, 0), (0, 2), (0, 1), (0, 1), (0, 0), (..., ...)|...].
?- findall((X,Y),ggp(X,Y),L).
L = [ (0, 0), (0, 1), (0, 2), (0, 0), (0, 2), (0, 1), (0, 1), (0, 0), (..., ...)|...].
If you want only to obtain unique tuples, you can use setof/3:
?- setof((X,Y),X^Y^gp(X,Y),S).
S = [ (0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (..., ...)].

Related

How to read large Prolog files in ECLiPSe?

I generated a large file of paths via eclipse. Each line contains a clause for a list of 27 points.
$ wc -l snake_points.pl
240917 snake_points.pl
$ ls -lh snake_points.pl
-rw-rw-r-- 1 carl carl 72M Sep 6 02:39 snake_points.pl
$ head -n 1 snake_points.pl
snake_points([(2, 0, 0), (2, 0, 1), (2, 0, 2), (2, 1, 2), (2, 1, 1), (2, 1, 0), (2, 2, 0), (2, 2, 1), (2, 2, 2), (1, 2, 2), (0, 2, 2), (0, 1, 2), (0, 0, 2), (0, 0, 1), (0, 1, 1), (0, 1, 0), (0, 2, 0), (0, 2, 1), (1, 2, 1), (1, 2, 0), (1, 1, 0), (1, 1, 1), (1, 1, 2), (1, 0, 2), (1, 0, 1), (1, 0, 0), (0, 0, 0)]).
However, I am unable to load the file into memory (even with 8G of heap):
$ time eclipse -f snake_points.ecl -e 'halt.'
*** Overflow of the global/trail stack in spite of garbage collection!
You can use the "-g kBytes" (GLOBALSIZE) option to have a larger stack.
Peak sizes were: global stack 8388576 kbytes, trail stack 59904 kbytes
________________________________________________________
Executed in 128.05 secs fish external
usr time 122.92 secs 297.00 micros 122.92 secs
sys time 5.01 secs 37.00 micros 5.01 secs
Compare this to swipl:
$ time swipl -f snake_points.pl -g 'halt.'
________________________________________________________
Executed in 53.56 secs fish external
usr time 53.27 secs 272.00 micros 53.27 secs
sys time 0.28 secs 41.00 micros 0.28 secs
Neither are impressive, but I'd expect ECLiPSe to complete with a reasonable amount of memory.
Is this expected behavior? What can be done?
I understand the solution may be "use a database" or EXDR, but shouldn't this be able to be done efficiently?
The problem is that you are not only reading the data, you are trying to compile it as a single predicate with 240917 clauses, and the compiler is indeed not built for this kind of usage.
You can instead read and assert the clauses from the data file one-by-one, like this:
assert_from_file(File) :-
open(File, read, S),
repeat,
read(S, Term),
( Term == end_of_file ->
true
;
assert(Term),
fail
),
!, close(S).
This loads your data in finite time
?- assert_from_file("snake_points.pl").
Yes (19.38s cpu)
and you can then call the resulting predicate as expected
?- snake_points(X).
X = [(2, 0, 0), (2, 0, 1), (2, 0, 2), (2, 1, 2), (2, 1, 1), (2, 1, 0), (2, 2, 0), (2, 2, 1), (2, 2, 2), (1, 2, 2), (0, 2, 2), (0, 1, 2), (0, 0, 2), (0, 0, 1), (0, 1, 1), (0, 1, 0), (0, 2, 0), (0, ..., ...), (..., ...), ...]
Yes (0.04s cpu, solution 1, maybe more) ? ;
But whatever problem you are trying to solve, this doesn't look like the most promising approach...
Did you tried changing the points representation? Using ','/2 to represent tuples with more than two elements per tuple is a bad idea. Note that:
[eclipse 30]: write_canonical((1,2,3)).
','(1, ','(2, 3))
Yes (0.00s cpu)
Try instead e.g. p(1,2,3). This should lower memory requirements a bit and may make a difference.

group line segments into minimum set of polyline

Given a list of line segments I need to construct a list of polyline while keeping the number of polylines minimum.
The polylines must not visit the same edge more than once.
For example if I was given the 4 edges of a rectangle then one polyline would be sufficient.
If I was given the 6 edges of a rectangle with a cross in the middle then I would need two polyline to cover it.
This problem looks very similar to travelling sales man problem so I am not sure if a solution exists. I can live with a sub optimal solution in that case.
Edit:
Performance is more important than precision for us so ideally we would want to group the ones that almost join (1-2 pixels away from joining) each other into one polyline
Examples:
input for a square:
L(0, 0) - (0, 1), L(0, 1) - (1, 1), L(1, 1) - (1, 0), L(1, 0) - (0, 0)
Expected output: Polyline (0, 0), (0, 1), (1, 1), (1, 0), Close
input for a square with X:
L(0, 0) - (0, 1), L(0, 1) - (1, 1), L(1, 1) - (1, 0), L(1, 0) - (0, 0), L(0, 0) - (1, 1), L(1, 0) - (0, 1)
One possible output: Polyline1 (0, 0), (0, 1), (1, 1), (1, 0), (0, 0), (1, 1) Polyline2 (1, 0), (0, 1)
input for lines close to each other:
L(0, 0) - (1, 0), L(2, 0) - (3, 0)
Ideal output: Polyline (0, 0), (3, 0)

Why does this query not terminate?

I've written a generator which generates a string of digits given a description of them:
:- use_module(library(clpfd)).
some(_Int, 0) --> [].
some(Int, Count) --> {Count #> 0, Count1 #= Count - 1}, [Int], some(Int, Count1).
many([]) --> [].
many([some(X, N)|Rest]) --> some(X, N), many(Rest).
This works when run forward:
?- phrase(many([some(0, 3), some(1, 2)]), Some).
Some = [0, 0, 0, 1, 1] ;
false.
Well, it leaves a choicepoint, but at least it first gives the correct result. It loops forever when asked to generate a description for a given string of digits:
?- phrase(many([Some|Rest]), [0, 0, 0, 1, 1]).
OOPS
What am I doing wrong?
I'm going to give you a slightly "operational" perspective on what your problem is. Dijkstra forgive me.
The crux of the problem is that there is a way for you to do nothing in many//2 and then again in some//2. Your first clause of many//2 is happy to eat none of the input. But, in your second clause, you sort of assume that some//2 is going to eat some of your input--but it doesn't have to, and then you are recurring back into your first clause of many//2, which still doesn't have to eat any input. So you find yourself in a recursive call to many//2, back in the second clause of many//2 once again, with precisely the same input as when you started. This is your loop!
The solution is to ensure that some//2 definitely does some work: the first clause has to go:
some(Int, 1) --> [Int].
some(Int, Count) --> {Count #> 0, Count1 #= Count - 1}, [Int], some(Int, Count1).
This is not as aggressive as you'd probably like in folding together some/2 structures, but it does work and it terminates:
?- phrase(many([Some|Rest]), [0, 0, 0, 1, 1]).
Some = some(0, 1),
Rest = [some(0, 1), some(0, 1), some(1, 1), some(1, 1)] ;
Some = some(0, 1),
Rest = [some(0, 1), some(0, 1), some(1, 2)] ;
Some = some(0, 1),
Rest = [some(0, 2), some(1, 1), some(1, 1)] ;
Some = some(0, 1),
Rest = [some(0, 2), some(1, 2)] ;
Some = some(0, 2),
Rest = [some(0, 1), some(1, 1), some(1, 1)] ;
Some = some(0, 2),
Rest = [some(0, 1), some(1, 2)] ;
Some = some(0, 3),
Rest = [some(1, 1), some(1, 1)] ;
Some = some(0, 3),
Rest = [some(1, 2)] .

Sort by key then value which will then be grouped up...pyspark

So I'm trying to sort data in this format...
[((0, 4), 3), ((4, 0), 3), ((1, 6), 1), ((3, 2), 3), ((0, 5), 1)...
Ascending by key and then descending by value. I'm able to achieve this via...
test = test.sortBy(lambda x: (x[0], -x[1]))
which would give me based on shortened version above...
[((0, 4), 3), ((0, 5), 1), ((1, 6), 1), ((3, 2), 3), ((4, 0), 3)...
The problem I'm having is that after the sorting I no longer want the value but do need to retain the sort after grouping the data. So...
test = test.map(lambda x: (x[0][0],x[0][1]))
Gives me...
[(0, 4), (0, 5), (1, 6), (3, 2), (4, 0)...
Which is still in the order I need it but I need the elements to be grouped up by key. I then use this command...
test = test.groupByKey().map(lambda x: (x[0], list(x[1])))
But in the process I lose the sorting. Is there any way retain?
I managed to retain the order by changing the format of the tuple...
test = test.map(lambda x: (x[0][0],(x[0][1],x[1]))
test = test.groupByKey().map(lambda x: (x[0], sorted(list(x[1]), key=lambda x: (x[0],-x[1]))))
[(0, [(4, 3), (5, 1)] ...
which leaves me with the value (2nd element in the tuple) that I want to get rid of but took care of that too...
test = test.map(lambda x: (x[0], [e[0] for e in x[1]]))
Feels a bit hacky but not sure how else it could be done.

How to efficiently enumerate all points of sphere in n-dimensional grid

Say, we have an N-dimensional grid and some point X in it with coordinates (x1, x2, ..., xN).
For simplicity we can assume that the grid is unbounded.
Let there be a radius R and a sphere of this radius with center in X, that is the set of all points in grid such that their manhattan distance from X is equal to R.
I suspect that their will be 2*N*R such points.
My question is: how do I enumerate them in efficient and simple way? By "enumerate" I mean the algorithm, which, given N, X and R will produce the list of points which form this sphere (where point is the list of it's coordinates).
UPDATE: Initially I called the metric I used "Hamming distance" by mistake. My apologies to all who answered the question. Thanks to Steve Jessop for pointing this out.
Consider the minimal axis-aligned hypercube that bounds the hypersphere and write a procedure to enumerate the grid points inside the hypercube.
Then you only need a simple filter function that allows you to discard the points that are on the cube but not in the hypersphere.
This is a simple and efficient solution for small dimensions. For instance, for 2D, 20% of the points enumerated for the bounding square are discarded; for 6D, almost 90% of the hypercube points are discarded.
For higher dimensions, you will have to use a more complex approach: loop over every dimension (you may need to use a recursive function if the number of dimensions is variable). For every loop you will have to adjust the minimal and maximal values depending on the values of the already calculated grid components. Well, try doing it for 2D, enumerating the points of a circle and once you understand it, generalizing the procedure to higher dimensions would be pretty simple.
update: errh, wait a minute, you want to use the Manhattan distance. Calling the cross polytope "sphere" may be correct but I found it quite confusing! In any case you can use the same approach.
If you only want to enumerate the points on the hyper-surface of the cross polytope, well, the solution is also very similar, you have to loop over every dimension with appropriate limits. For instance:
for (i = 0; i <= n; i++)
for (j = 0; j + i <= n; j++)
...
for (l = 0; l + ...+ j + i <= n; l++) {
m = n - l - ... - j - i;
printf(pat, i, j, ..., l, m);
}
For every point generated that way, then you will have to consider all the variations resulting of negating any of the components to cover all the faces and then displace them with the vector X.
update
Perl implementation for the case where X = 0:
#!/usr/bin/perl
use strict;
use warnings;
sub enumerate {
my ($d, $r) = #_;
if ($d == 1) {
return ($r ? ([-$r], [$r]) : [0])
}
else {
my #r;
for my $i (0..$r) {
for my $s (enumerate($d - 1, $r - $i)) {
for my $j ($i ? (-$i, $i) : 0) {
push #r, [#$s, $j]
}
}
}
return #r;
}
}
#ARGV == 2 or die "Usage:\n $0 dimension radius\n\n";
my ($d, $r) = #ARGV;
my #r = enumerate($d, $r);
print "[", join(',', #$_), "]\n" for #r;
Input: radius R, dimension D
Generate all integer partitions of R with cardinality ≤ D
For each partition, permute it without repetition
For each permutation, twiddle all the signs
For example, code in python:
from itertools import *
# we have to write this function ourselves because python doesn't have it...
def partitions(n, maxSize):
if n==0:
yield []
else:
for p in partitions(n-1, maxSize):
if len(p)<maxSize:
yield [1] + p
if p and (len(p)<2 or p[1]>p[0]):
yield [ p[0]+1 ] + p[1:]
# MAIN CODE
def points(R, D):
for part in partitions(R,D): # e.g. 4->[3,1]
part = part + [0]*(D-len(part)) # e.g. [3,1]->[3,1,0] (padding)
for perm in set(permutations(part)): # e.g. [1,3,0], [1,0,3], ...
for point in product(*[ # e.g. [1,3,0], [-1,3,0], [1,-3,0], [-...
([-x,x] if x!=0 else [0]) for x in perm
]):
yield point
Demo for radius=4, dimension=3:
>>> result = list( points(4,3) )
>>> result
[(-1, -2, -1), (-1, -2, 1), (-1, 2, -1), (-1, 2, 1), (1, -2, -1), (1, -2, 1), (1, 2, -1), (1, 2, 1), (-2, -1, -1), (-2, -1, 1), (-2, 1, -1), (-2, 1, 1), (2, -1, -1), (2, -1, 1), (2, 1, -1), (2, 1, 1), (-1, -1, -2), (-1, -1, 2), (-1, 1, -2), (-1, 1, 2), (1, -1, -2), (1, -1, 2), (1, 1, -2), (1, 1, 2), (0, -2, -2), (0, -2, 2), (0, 2, -2), (0, 2, 2), (-2, 0, -2), (-2, 0, 2), (2, 0, -2), (2, 0, 2), (-2, -2, 0), (-2, 2, 0), (2, -2, 0), (2, 2, 0), (-1, 0, -3), (-1, 0, 3), (1, 0, -3), (1, 0, 3), (-3, -1, 0), (-3, 1, 0), (3, -1, 0), (3, 1, 0), (0, -1, -3), (0, -1, 3), (0, 1, -3), (0, 1, 3), (-1, -3, 0), (-1, 3, 0), (1, -3, 0), (1, 3, 0), (-3, 0, -1), (-3, 0, 1), (3, 0, -1), (3, 0, 1), (0, -3, -1), (0, -3, 1), (0, 3, -1), (0, 3, 1), (0, -4, 0), (0, 4, 0), (0, 0, -4), (0, 0, 4), (-4, 0, 0), (4, 0, 0)]
>>> len(result)
66
(Above I used set(permutations(...)) to get permutations without repetition, which is not efficient in general, but it might not matter here due to the nature of the points. And if efficiency mattered, you could write your own recursive function in your language of choice.)
This method is efficient because it does not scale with the hypervolume, but just scales with the hypersurface, which is what you're trying to enumerate (might not matter much except for very large radii: e.g. will save you roughly a factor of 100x speed if your radius is 100).
You can work your way recursively from the center, counting zero distance once and working on symmetries. This Python implementation works on the lower-dimension "stem" vector and realizes one 1-dimensional slice at a time. One might also do the reverse, but it would imply iterating on the partial hyperspheres. While mathematically the same, the efficiency of both approaches is heavily language-dependent.
If you know beforehand the cardinality of the target space, I would recommend to write an iterative implementation.
The following enumerates the points on a R=16 hyper-LEGO block in six dimensions in about 200 ms on my laptop. Of course, performance rapidly decreases with more dimensions or larger spheres.
def lapp(lst, el):
lst2 = list(lst)
lst2.append(el)
return lst2
def hypersphere(n, r, stem = [ ]):
mystem = lapp(stem, 0)
if 1 == n:
ret = [ mystem ]
for d in range(1, r+1):
ret.append(lapp(stem, d))
ret.append(lapp(stem, -d))
else:
ret = hypersphere(n-1, r, mystem)
for d in range(1, r+1):
mystem[-1] = d
ret.extend(hypersphere(n-1, r-d, mystem))
mystem[-1] = -d
ret.extend(hypersphere(n-1, r-d, mystem))
return ret
(This implementation assumes the hypersphere is centered in the origin. It would be easier to translate all points afterwards than carrying along the coordinates of the center).

Resources