Unfair Coin
Simulating a coin with parameter p comparing up to d digits of the binary expansion of p to a sequence of bits drawn uniformly at random.
0.5::bit(T,0); 0.5::bit(T,1).
% base cases: return the current bit if it equals the truth value of 2*p>=1.0
step(T,D,P,1) :-
T =< D,
2*P >= 1.0,
bit(T,1).
step(T,D,P,0) :-
T =< D,
2*P < 1.0,
bit(T,0).
% recursive cases: else, continue with the fractional part of 2*p as new value of p
step(T,D,P,V) :-
T =< D,
2*P >= 1.0,
bit(T,0),
TT is T+1,
PP is float_fractional_part(2*P),
step(TT,D,PP,V).
step(T,D,P,V) :-
T =< D,
2*P < 1.0,
bit(T,1),
TT is T+1,
PP is float_fractional_part(2*P),
step(TT,D,PP,V).
coin(P,D,V) :-
step(1,D,P,V).
query(coin(0.12,D,_)) :- digits(D).
query(coin(0.7,D,_)) :- digits(D).
digits(20).
Here’s a version that takes the list of bits in the binary expansion as input:
0.5::bit(T,0); 0.5::bit(T,1).
% base case
step([X|_],T,X) :-
bit(T,X).
% recursive case
step([H|Tail],T,V) :-
bit(T,X),
X \= H,
TT is T+1,
step(Tail,TT,V).
coin(L,V) :-
step(L,1,V).
% 0.6 expanded is (1001)*
query(coin([1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1],_)).
query(coin([A,B,C,A,B,C,A,B,C],1)) :- between(0,1,A),between(0,1,B),between(0,1,C).
Markov Chain
% transition matrix
0.9::go(a,a,T); 0.05::go(a,b,T); 0.05::go(a,c,T).
0.7::go(b,a,T); 0.3::go(b,c,T).
0.8::go(c,a,T) ; 0.2::go(c,c,T).
% add initial distribution and define walk
1/3::in(a,0); 1/3::in(b,0); 1/3::in(c,0).
in(X,T) :- T > 0, TT is T-1, in(Y,TT), go(Y,X,TT).
query(in(_,3)).
evidence(in(a,5),false).
Students
An example of a soft constraint in a students and teachers setting, with an arbitrary input database added.
% uniform prior on students liking teachers
0.5::likes(S,T) :- student(S),teacher(T).
% if S takes T's course, S should like T
0.7::should_like(S,T) :- student_course(S,C),teacher_course(T,C).
% constraint on acceptable worlds: should_like implies like
bad_pair :- should_like(S,T), \+ likes(S,T).
evidence(bad_pair,false).
% posterior of likes?
query(likes(S,T)).
teacher(t1).
teacher(t2).
teacher(t3).
student(s1).
student(s2).
student(s3).
teacher_course(t1,c4).
teacher_course(t2,c1).
teacher_course(t2,c2).
teacher_course(t3,c3).
student_course(s1,c1).
student_course(s2,c1).
student_course(s2,c2).
student_course(s3,c2).
student_course(s3,c4).
Friends
A more complex soft constraint that depends on random variables, not just the input database as in the students example above.
% prior on friendship
0.5::friend(S1,S2) :- student(S1),student(S2).
% friendship is (probabilistically) transitive
0.6::should_be_friend(S1,S3) :- friend(S1,S2), friend(S2,S3).
% constraint on acceptable worlds: should_be_friends implies friends
bad_pair :- student(S1), student(S2), should_be_friend(S1,S2), \+ friend(S1,S2).
evidence(bad_pair,false).
query(friend(X,Y)) :- student(X),student(Y), X \= Y.
evidence(friend(s1,s3)).
evidence(friend(s3,s4)).
evidence(friend(s3,s2)).
student(s1).
student(s2).
student(s3).
student(s4).
Compare
We have two random n-bit sequences a and b and observe that a<b. What are the posterior probabilities of the individual bits?
% parameter n (number of bits)
n(3).
% bits of a
0.5::a(I,1); 0.5::a(I,0) :- n(N), between(1,N,I).
% bits of b
0.5::b(I,1); 0.5::b(I,0) :- n(N), between(1,N,I).
% start comparing at bit 1
compare(Res) :-
compare(1,Res).
% base cases
compare(I,equal) :-
n(I), a(I,A), b(I,A).
compare(I,smaller) :-
n(N), I =< N, a(I,A), b(I,B), A < B.
compare(I,larger) :-
n(N), I =< N, a(I,A), b(I,B), A > B.
% recursive case
compare(I,Res) :-
n(N), I < N, a(I,A), b(I,A), II is I+1, compare(II,Res).
query(a(_,1)).
query(b(_,1)).
evidence(compare(smaller)).
One Coin
Keep tossing a coin until it comes up heads.
0.5::coin(T,true); 0.5::coin(T,false).
b(0,false).
b(T,V) :- T>0, TT is T-1, b(TT,false), coin(T,V).
query(b(X,true)) :- between(1,5,X).
Dice
0.5::roll(ID,T,true); 0.5::roll(ID,T,false).
% start with all three false
dice(0,false,false,false).
% while all three are false or all three are true, continue
dice(N,A,B,C) :- N > 0, NN is N-1, dice(NN,X,X,X), roll(d1,N,A), roll(d2,N,B), roll(d3,N,C).
% and stop if not
dice_return(NN,A,B,C) :- NN >= 0, dice(NN,A,B,C), \+ allsame(A,B,C).
allsame(X,X,X).
query(dice_return(X,_,_,_)) :- between(1,3,X).