🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.lang.prolog
Article #3600

Random Clause Selection (was: re:probabilstic or)

#3600
From: Thom Fruehwirth
Date: Mon, 22 Aug 1988 17:56
204 lines
5114 bytes

In <256@quintus.uucp> Richard O'Keefe sketched how to try clauses
in random order:
>
> p(~Args~):-
>	random_permutation([1,2,3,4,5,6,7],Perm),
>	member(Index,Perm),
>	p(Index,~Args~).

As Jamie Andrews in <628@etive.ed.ac.uk> pointed out, O'Keefe probably
intended to have a cut between random_permutation/2 and member/2.
Given that the call (R is random) binds R to a positive or negative
integer, then the possibility for success of (random>0) is about 1/2 .
Suppose we write a meta-interpreter for random clause selection:

prove(true).
prove((A,B)):-
	prove(A),
	prove(B).
prove(H):-
	clause_number(H,N),		% finds the number of clauses of
H
	randomize(N,I),
	rule(I,H,B),	% never use clause/2 here, use your own
predicate
	prove(B).
	
randomize(N,I):-
	generate_list(N,L),
	random_perm(L,P),
	!,
	member(I,P).

generate_list(0,[]).			
generate_list(N,[N|L]):- N>0, M is N-1, generate_list(M,L).
	
random_perm([],[]):-!.
random_perm([X],[X]):-!.
random_perm(X,Y):-
	random_split(A,B,X),
	random_perm(A,A1),
	random_perm(B,B1),
	merge(A1,B1,Y).

random_split([X],[],[X]):-!.
random_split([X|L1],L2,[X|L3]) :- random>0,!,
	random_split(L1,L2,L3).
random_split(L1,[X|L2],[X|L3]) :- 
	random_split(L1,L2,L3).
	
merge(X,[],X):-!.
merge([],X,X):-!.
merge([X|L1],L2,[X|L3]) :- merge(L1,L2,L3).
merge(L1,[X|L2],[X|L3]) :- merge(L1,L2,L3).

In this optimized version random_perm/2 is twice as slow as left-
recursive permutation, but more than twice as fast as naive, tail-
recursive permutation (on the average).

We now gonna transform randomize/2 into a more efficient version.
We move replace
	(random_perm(L,P),!,member(I,P)) by random_index(L,I)
by moving (!,member(I,P)) into random_perm/2:

random_index([],I):-!,	
	!,
	member(I,[]).
random_index([X],I):-!,	
	!,
	member(I,[X]).
random_index(L,I):-
	random_split(A,B,L),
	random_perm(A,A1),
	random_perm(B,B1),
	merge(A1,B1,P),
	!,
	member(I,P).

Partial evaluation gives:

random_index([],I):-!,fail.
random_index([X],X):-!.
random_index(L,I):-
	random_split(A,B,L),
	random_perm(A,A1),
	random_perm(B,B1),
	merge(A1,B1,Y),
	!,
	member(I,Y).

Moving the cut into merge/3 gives an optimized version of append/3:

append(L,[],L):-!.
append([],L,L):-!.
append([X|L1],L2,[X|L3]) :-!,append(L1,L2,L3).

It is easy to see that 
	(append(A1,B1,Y),member(I,Y)) <=> (member(I,A1),member(I,B1))
therefore (with the explicit failure of the first clause removed):
	
random_index([X],X).
random_index(L,I):-
	L=[X,Y|_],			% avoid problems with L=[] and
L=[X]
	random_split(A,B,L),
	random_perm(A,A1),
	random_perm(B,B1),
	(member(I,A1);
	member(I,B1)).
	
But this is

random_index([X],X).
random_index(L,I):-
	L=[X,Y|_],
	random_split(A,B,L),
	(random_perm(A,A1),
	member(I,A1);
	random_perm(B,B1),
	member(I,B1)).
	
and according to our initial replacement we result in:

random_index([X],X).
random_index(L,I):-
	L=[X,Y|_],
	random_split(A,B,L),
	(random_index(A,I);
	random_index(B,I)).

We can further move the first application of random_index/2 into
generate_list/2, this finally results in:

randomize(N,I):-
	generate_lists(N,A,B),
	(random_index(A,I);
	random_index(B,I)).

generate_lists(0,[],[]).
generate_lists(N,[N|L1],L2):- N>0,random>0,!,
	M is N-1,
	generate_lists(M,L1,L2).
generate_lists(N,L1,[N|L2]):- N>0,
	M is N-1,
	generate_lists(M,L1,L2).
	
----------------
Lee Naish pointed out, that even randomized clause selection is not
complete using the example (or the like):

	P:-true.
	p:-loop.
	
	loop:-loop.

This seems to indeicate that depth-bound computation is necessary.
But instead of having a depth bound meta-interpreter, we could have
one with a randomized depth bound:

prove(P,true).
prove(P,(A,B)):-
	prove(P,A),
	prove(P,B).
prove(P,H):-
	random>P,
	rule(H,B),
	prove(P,B).

Combining this with our random clause selection meta interpreter
means that some clauses may not be called, that not all indizes are
produced. After some transformations (ommitted here) we result in:

prove(P,true).
prove(P,(A,B)):-
	prove(P,A),
	prove(P,B).
prove(P,H):-
	clause_number(H,N),
	randomize(P,N,I),
	rule(I,H,B),
	prove(P,B).

randomize(P,N,I):-
	generate_lists(P,N,A,B),
	(random_index(A,I);
	random_index(B,I)).

generate_lists(P,0,[],[]).
generate_lists(P,N,L1,L2):- N>0,random>P,!,	% probably ignore N 
	M is N-1,			
	generate_lists(P,M,L1,L2).
generate_lists(P,N,[N|L1],L2):- N>0,random>0,!,
	M is N-1,
	generate_lists(P,M,L1,L2).
generate_lists(P,N,L1,[N|L2]):- N>0,
	M is N-1,
	generate_lists(P,M,L1,L2).
	

ughhh, I think thats enough...
thom fruehwirth

	  
Technical Details
Message-ID: <1171@tuhold>
Path: arc1-ca.pugleaf.net!utzoo!attcan!uunet!mcvax!tuvie!tuhold!thom

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!attcan!uunet!mcvax!tuvie!tuhold!thom
From: thom@tuhold (Thom Fruehwirth)
Newsgroups: comp.lang.prolog
Subject: Random Clause Selection (was: re:probabilstic or)
Keywords: meta interpreter, random, probabilistic, completeness, loops
Message-ID: <1171@tuhold>
Date: 22 Aug 88 17:56:10 GMT
Organization: Institut f. Angewandte Informatik, TU Vienna
Lines: 204