Related
I do not find a Prolog cut in Dijsktras "if fi", since he says "otherwise an arbitrary guarded list with a true guard will be selected for execution.". So his construct, does not choose the first match, as a Prolog cut would do:
if Cond1 -> Action11, .., Action1n1
[] Cond2 -> Action21, .., Action2n2
...
[] Condm -> Actionm1, .., Actionmn2
if
Is there maybe a Prolog cut in the "do od" construct, which loops as long as at least one condition of a guarded list is true? Or maybe some other approach to realize it in Prolog, I assume a loop can be translated to a recursive call. So how would we do this sorting of q1,q2,q3,q4 in Prolog:
do q1 > q2 -> q1,q2 := q2,q1
[] q2 > q3 -> q2,q3 := q3,q2
[] q3 > q4 -> q3,q4 := q4,q3
od
How many non-deterministic execution paths aka Prolog solutions will the Prolog program have for input 7,11,5,3 that all provide the same answer?
I think you can do something like this:
do([Q1,Q2,Q3,Q4], [swap(Q1,Q2)|P], S) :-
Q1 > Q2,
do([Q2,Q1,Q3,Q4], P, S).
do([Q1,Q2,Q3,Q4], [swap(Q2,Q3)|P], S) :-
Q2 > Q3,
do([Q1,Q3,Q2,Q4], P, S).
do([Q1,Q2,Q3,Q4], [swap(Q3,Q4)|P], S) :-
Q3 > Q4,
do([Q1,Q2,Q4,Q3], P, S).
do([Q1,Q2,Q3,Q4], [], [Q1,Q2,Q3,Q4]) :- % termination state
Q1 =< Q2,
Q2 =< Q3,
Q3 =< Q4.
Execution:
?- do([7,11,5,3],P,S).
P = [swap(11, 5), swap(7, 5), swap(11, 3), swap(7, 3), swap(5, 3)],
S = [3, 5, 7, 11] ;
P = [swap(11, 5), swap(11, 3), swap(7, 5), swap(7, 3), swap(5, 3)],
S = [3, 5, 7, 11] ;
P = [swap(11, 5), swap(11, 3), swap(5, 3), swap(7, 3), swap(7, 5)],
S = [3, 5, 7, 11] ;
P = [swap(5, 3), swap(11, 3), swap(7, 3), swap(11, 5), swap(7, 5)],
S = [3, 5, 7, 11] ;
P = [swap(5, 3), swap(11, 3), swap(11, 5), swap(7, 3), swap(7, 5)],
S = [3, 5, 7, 11] ;
false.
If we assume no guard calculation can diverge, I think the following expresses the same computation as the sort example from the question:
dgsort([A,B,C,D],R):-
( A > B -> X1 = [1] ; X1 = [] ),
( B > C -> X2 = [2|X1] ; X2 = X1 ),
( C > D -> X3 = [3|X2] ; X3 = X2 ),
( X3 = [] -> R = [A,B,C,D]
; random_member( X, X3),
( X =:= 1 -> dgsort([B,A,C,D],R)
; X =:= 2 -> dgsort([A,C,B,D],R)
; X =:= 3 -> dgsort([A,B,D,C],R) )).
comments: "an arbitrary guarded list with a true guard will be selected for execution" and all the others dropped, i.e. the chosen one is committed to, I always thought. Thus if I had to implement it I'd spawn all the branches's guards, check on them at some timeout intervals, and as soon as one or more are successful I'd pick one of them randomly, kill all the rest, and proceeded with the winner. i.e. committing to it. that is my understanding anyway. (or maybe the timeout should be random as well?)
I also thought the do-od construct chose the true guard by the same mechanism. i.e. "at least one" and we don't care which. If we assume all the guards calculations terminate, we can just execute all of them, pick the winner randomly, then proceed with its actions. Which is what the code above is doing.
To find out the number of execution paths we need to change random_member to just member, run the predicate through findall and measure the length of the resulting list:
dgsortn([A,B,C,D],R):-
( A > B -> X1 = [1] ; X1 = [] ),
( B > C -> X2 = [2|X1] ; X2 = X1 ),
( C > D -> X3 = [3|X2] ; X3 = X2 ),
( X3 = [] -> R = [A,B,C,D]
; member( X, X3),
( X =:= 1 -> dgsortn([B,A,C,D],R)
; X =:= 2 -> dgsortn([A,C,B,D],R)
; X =:= 3 -> dgsortn([A,B,D,C],R) )).
Running it succeeds 5 times:
9 ?- dgsortn( [7,11,5,3], R).
R = [3, 5, 7, 11] ;
R = [3, 5, 7, 11] ;
R = [3, 5, 7, 11] ;
R = [3, 5, 7, 11] ;
R = [3, 5, 7, 11].
We could also add a counter to see the number of steps taken to produce each solution.
I directly takled the counting problem and came up with this solution. It has the defect that the negation as failure will re-evaluate the conditions.
sortloop([Q1,Q2,Q3,Q4], R) :- Q1 > Q2, sortloop([Q2,Q1,Q3,Q4], R).
sortloop([Q1,Q2,Q3,Q4], R) :- Q2 > Q3, sortloop([Q1,Q3,Q2,Q4], R).
sortloop([Q1,Q2,Q3,Q4], R) :- Q3 > Q4, sortloop([Q1,Q2,Q4,Q3], R).
sortloop([Q1,Q2,Q3,Q4], [Q1,Q2,Q3,Q4]) :- \+ Q1 > Q2, \+ Q2 > Q3, \+ Q3 > Q4.
But it shows there are 5 execution paths:
?- sortloop([7,11,5,3], R).
R = [3, 5, 7, 11] ;
R = [3, 5, 7, 11] ;
R = [3, 5, 7, 11] ;
R = [3, 5, 7, 11] ;
R = [3, 5, 7, 11] ;
false.
But can we improve that the conditions are only evaluated once? What came to my mind was the soft cut (*->)/2 since the action lists do not abort:
sortloop2([Q1,Q2,Q3,Q4], R) :-
((Q1 > Q2, sortloop2([Q2,Q1,Q3,Q4], R);
Q2 > Q3, sortloop2([Q1,Q3,Q2,Q4], R);
Q3 > Q4, sortloop2([Q1,Q2,Q4,Q3], R)) *-> true; R=[Q1,Q2,Q3,Q4]).
The soft cut solution gives the same result:
?- sortloop2([7,11,5,3], R).
R = [3, 5, 7, 11] ;
R = [3, 5, 7, 11] ;
R = [3, 5, 7, 11] ;
R = [3, 5, 7, 11] ;
R = [3, 5, 7, 11] ;
false.
But none of the solutions uses a Prolog cut that would replace the arrow between condition and action list in the Dijkstra guards. Situation is a little bit more complicated.
Edit 12.02.2021:
In case somebody is currious how the 5 paths look like as a DAG:
Is it possible to have the numbers 1-9 be placed such that it fills a constrain set out.
I have:
foo(bl1,A,B,C,Total1) :- A+B+C =:= Total1.
foo(bl2,A,B,D,Total2) :- A+B+D =:= Total2.
run_foo(A,B,C,D) :-
foo(bl1,A,B,C,13),
foo(bl2,A,B,D,11),
A/=B,
A/=C,
A/=D,
B=/C,
B=/D,
C=/D.
And then run with something like:
run_foo(A,6,C,D).
So that it returns the values of A, C and D. This should return A=4 ,C=3, D=2.
You can use a constraints solver:
?- B #= 6, Vs = [A,B,C,D],
Vs ins 1..9, A+B+C #= 13, A+B+D #= 11, all_distinct(Vs), label(Vs).
B = 6, Vs = [2,6,5,3], A = 2, C = 5, D = 3
; B = 6, Vs = [3,6,4,2], A = 3, C = 4, D = 2
; B = 6, Vs = [4,6,3,1], A = 4, C = 3, D = 1.
Or:
?- B = 6, Vs = [A,B,C,D],
maplist(between(1,9), Vs), A+B+C =:= 13, A+B+D =:= 11, \+ (select(V, Vs, Vs0), member(V, Vs0)).
B = 6, Vs = [2,6,5,3], A = 2, C = 5, D = 3
; B = 6, Vs = [3,6,4,2], A = 3, C = 4, D = 2
; B = 6, Vs = [4,6,3,1], A = 4, C = 3, D = 1
; false.
Can someone explain this behavior:
a = b = c = 1, 2, 3
a # => [1, 2, 3]
b # => 1
c # => 1
In the assignment a = b = c = 1, 2, 3, the variables a, b, and c should be assigned [1, 2, 3]. Any idea?
Can someone explain why is this happening
#shivam already answered the question, but adding some parentheses might clarify things even more.
a = b = c = 1, 2, 3
is interpreted as:
a = [(b = (c = 1)), 2, 3]
The expression is evaluated in this order:
c = 1
b = ( )
a = [( ), 2, 3]
the variables a, b, and c should be assigned [1, 2, 3]
To get the expected result, you could write:
a = b = c = [1, 2, 3]
which is interpreted as:
a = (b = (c = [1, 2, 3]))
and evaluated in this order:
c = [1, 2, 3]
b = ( )
a = ( )
You are being confused
a=b=c=1,2,3
is actually:
a = (b = c = 1), 2, 3
that leaves
c = 1 # => 1
b = c # => 1
a = 1,2,3 # => [1, 2, 3]
To do what you are talking about you should do as follow:
a,b,c = 1,2,3
p a #=> 1
p b #=> 2
p c #=> 3
Let x denote a vector of p values (i.e. a data point in p dimensional space).
I have two sets: set A of n elements A = {xi, .., xn} and a set B of m elements B = {xj, .., xm}, where |A| > 1 and |B| > 1. Given an integer k > 0, let dist(x, k, A) a function which returns the mean Euclidean distance from x to its k nearest points in A; and dist(x, k, B) the mean Euclidean distance from x to its k nearest points in B.
I have the following algorithm:
Repeat
{
A' = { x in A, such that dist(x, k, A) > dist(x, k, B) }
B' = { x in B, such that dist(x, k, A) < dist(x, k, B) }
A = { x in A such that x not in A' } U B'
B = { x in B such that x not in B' } U A'
}
Until CONDITION == True
Termination: CONDITION is True when no more elements move from A to B or from B to A (that is A' and B' becomes empty), or when |A| or |B| becomes less than or equals to 1.
1) Is it possible to prove that this algorithm terminates ?
2) And if so, is it also possible to have an upper bound for the number of iterations required to terminate ?
Note: the k nearest points to x in a set S, means: the k points (others than x) in S, having the smallest Euclidean distance to x.
It looks like this algorithm can loop forever, oscillating between two or more states. I determined this experimentally using the following Python program:
def mean(seq):
if len(seq) == 0:
raise IndexError("didn't expect empty sequence for mean")
return sum(seq) / float(len(seq))
def dist(a,b):
return abs(a-b)
def mean_dist(x, k, a):
neighbors = {p for p in a if p != x}
neighbors = sorted(neighbors, key=lambda p: dist(p,x))
return mean([dist(x, p) for p in neighbors[:k]])
def frob(a,b,k, verbose = False):
def show(msg):
if verbose:
print msg
seen_pairs = set()
iterations = 0
while True:
iterations += 1
show("Iteration #{}".format(iterations))
a_star = {x for x in a if mean_dist(x, k, a) > mean_dist(x,k,b)}
b_star = {x for x in b if mean_dist(x, k, a) < mean_dist(x,k,b)}
a_temp = {x for x in a if x not in a_star} | b_star
b_temp = {x for x in b if x not in b_star} | a_star
show("\tA`: {}".format(list(a_star)))
show("\tB`: {}".format(list(b_star)))
show("\tA becomes {}".format(list(a_temp)))
show("\tB becomes {}".format(list(b_temp)))
if a_temp == a and b_temp == b:
return a, b
key = (tuple(sorted(a_temp)), tuple(sorted(b_temp)))
if key in seen_pairs:
raise Exception("Infinite loop for values {} and {}".format(list(a_temp),list(b_temp)))
seen_pairs.add(key)
a = a_temp
b = b_temp
import random
#creates a set of random integers, with the given number of elements.
def randSet(size):
a = set()
while len(a) < size:
a.add(random.randint(0, 10))
return a
size = 2
k = 1
#p equals one because I don't feel like doing vector math today
while True:
a = randSet(size)
b = randSet(size)
try:
frob(a,b, k)
except IndexError as e:
continue
except Exception as e:
print "infinite loop detected for initial inputs {} and {}".format(list(a), list(b))
#run the algorithm again, but showing our work this time
try:
frob(a,b,k, True)
except:
pass
break
Result:
infinite loop detected for initial inputs [10, 4] and [1, 5]
Iteration #1
A`: [10, 4]
B`: [1, 5]
A becomes [1, 5]
B becomes [10, 4]
Iteration #2
A`: [1, 5]
B`: [10, 4]
A becomes [10, 4]
B becomes [1, 5]
Iteration #3
A`: [10, 4]
B`: [1, 5]
A becomes [1, 5]
B becomes [10, 4]
In this case, the loop never terminates because A and B continually switch entirely. While experimenting with larger set sizes, I found a case where only some elements switch:
infinite loop detected for initial inputs [8, 1, 0] and [9, 4, 5]
Iteration #1
A`: [8]
B`: [9]
A becomes [0, 1, 9]
B becomes [8, 4, 5]
Iteration #2
A`: [9]
B`: [8]
A becomes [0, 1, 8]
B becomes [9, 4, 5]
Iteration #3
A`: [8]
B`: [9]
A becomes [0, 1, 9]
B becomes [8, 4, 5]
Here, elements 8 and 9 move back and forth while the other elements stay in place.
When given groups of numbers, how can I find the minimal set of groups to cover all the numbers? The constraint is that the chosen groups should not overlap.
For example, given three groups of numbers (1,2), (2,3), and (3,4), we can select (1,2) and (3,4) as (2,3) is redundant.
With (1,2),(2,3),(3,4),(1,4), we have two solutions (1,2),(3,4) or (1,4),(2,3).
With (1,2,3),(1,2,4), and (3,4), there is a redundancy, but there is no solution.
The algorithm that I came up with (for G = (1,2),(2,3),(3,4),(1,4) example) is
collect all the numbers from the groups x = (1,2,3,4)
for g in G:
x = remove g in x # x = (3,4)
find G' = (a set of (g' in (G - g))) that makes (G' + g = x) # G' = ((3,4))
if find (G' + g) return (G',g) # return ((1,2)(3,4))
I know my algorithm has a lot of holes in it in terms of performance, and I assume this might be a well known problem. Any hints to this problem?
I found a working code in python from this site : http://www.cs.mcgill.ca/~aassaf9/python/algorithm_x.html
X = {1, 2, 3, 4, 5, 6, 7}
Y = {
'A': [1, 4, 7],
'B': [1, 4],
'C': [4, 5, 7],
'D': [3, 5, 6],
'E': [2, 3, 6, 7],
'F': [2, 7]}
def solve(X, Y, solution=[]):
if not X:
yield list(solution)
else:
c = min(X, key=lambda c: len(X[c]))
for r in list(X[c]):
solution.append(r)
cols = select(X, Y, r)
for s in solve(X, Y, solution):
yield s
deselect(X, Y, r, cols)
solution.pop()
def select(X, Y, r):
cols = []
for j in Y[r]:
for i in X[j]:
for k in Y[i]:
if k != j:
X[k].remove(i)
cols.append(X.pop(j))
return cols
def deselect(X, Y, r, cols):
for j in reversed(Y[r]):
X[j] = cols.pop()
for i in X[j]:
for k in Y[i]:
if k != j:
X[k].add(i)
X = {j: set(filter(lambda i: j in Y[i], Y)) for j in X}
a = solve(X, Y)
for i in a: print i