i am trying to use WARMR to find frequent relational patterns in my data; for this i am using ALEPH in SWI-Prolog. however, i am struggling to figure out how to do this and why my previous attempts did not work.
i want to make a toy example work before i move on to my full data. for this i took the toy "train" data from the aleph pack page:
http://www.swi-prolog.org/pack/list?p=aleph
the Aleph manual states about the ar search:
ar Implements a simplified form of the type of association rule search conducted by the WARMR system (see L. Dehaspe, 1998, PhD Thesis, Katholieke Universitaet Leuven). Here, Aleph simply finds all rules that cover at least a
pre-specified fraction of the positive examples. This fraction is specified by the parameter pos_fraction.
accordingly i have inserted
:- set(search,ar).
:- set(pos_fraction,0.01).
into the background file (and deleted :- set(i,2).)) and erased the .n file of negative examples. i have also commented out all the determinations and the modeh declaration logic being that we are searching for frequent patterns, not rules (i.e. in a supervised context head would be an "output" variable and clauses in the body -- "inputs" trying to explain the output), i.e. it is an unsupervised task.
now, the original trains dataset is trying to construct rules for "eastbound" trains. this is done by having predicates like car, shape, has_car(train, car) etc. originally all the background knowledge relating to these is located in the .b file and the five positive examples (e.g eastbound(east1).) in the .f file (+ five negative examples, e.g. eastbound(west1)., in the .n file). leaving files unchanged (save for the changes described above) and running induce. does not produce a sensible result (it would return ground terms like train(east1) as a "rule", for example). i have tried moving some of the background knowledge to the .f file but that did not produce anything sensible either.
how do i go about constructing the .f and .b files? what should to into the positive examples file if we are not really looking to explain any positive examples (which would surely constitute a supervised problem) but instead to find frequent patterns in the data (unsupervised problem)? am i missing something?
any help would be greatly appreciated.
First of all if you can use the original WARMR I think it is better. But I think you need to be an academic for free use. You can try asking for a license.
https://dtai.cs.kuleuven.be/ACE/
To get association rules, I put all the examples I want in the f file. The n file can have examples in it or I think be empty.
The only thing I change is to put :
:- set(search,ar).
:- set(pos_fraction,0.01).
In the .b file. Keep the determinations and mode declarations.
The set(i,2) limits the length of the query to having two additional literals (I think) so you might want this to be larger.
?-read_all(train).
induce.
You will then get an out of 'good clauses' which I think are the frequent queries.
[good clauses]
eastbound(A).
[pos cover = 5 neg cover = 0] [pos-neg] [5]
eastbound(A) :-
has_car(A,B).
[pos cover = 5 neg cover = 0] [pos-neg] [5]
eastbound(A) :-
has_car(A,B).
[pos cover = 5 neg cover = 0] [pos-neg] [5]
eastbound(A) :-
has_car(A,B).
[pos cover = 5 neg cover = 0] [pos-neg] [5]
eastbound(A) :-
has_car(A,B).
[pos cover = 5 neg cover = 0] [pos-neg] [5]
eastbound(A) :-
has_car(A,B), long(B).
[pos cover = 2 neg cover = 0] [pos-neg] [2]
eastbound(A) :-
has_car(A,B), open_car(B).
[pos cover = 5 neg cover = 0] [pos-neg] [5]
eastbound(A) :-
has_car(A,B), shape(B,rectangle).
[pos cover = 5 neg cover = 0] [pos-neg] [5]
eastbound(A) :-
has_car(A,B), wheels(B,2).
[pos cover = 5 neg cover = 0] [pos-neg] [5]
eastbound(A) :-
has_car(A,B), load(B,rectangle,3).
[pos cover = 1 neg cover = 0] [pos-neg] [1]
eastbound(A) :-
has_car(A,B), has_car(A,C).
[pos cover = 5 neg cover = 0] [pos-neg] [5]
eastbound(A) :-
has_car(A,B), has_car(A,C).
[pos cover = 5 neg cover = 0] [pos-neg] [5]
eastbound(A) :-
has_car(A,B), has_car(A,C).
[pos cover = 5 neg cover = 0] [pos-neg] [5]
eastbound(A) :-
has_car(A,B), short(B).
[pos cover = 5 neg cover = 0] [pos-neg] [5]
eastbound(A) :-
has_car(A,B), closed(B).
[pos cover = 5 neg cover = 0] [pos-neg] [5]
eastbound(A) :-
has_car(A,B), shape(B,rectangle).
[pos cover = 5 neg cover = 0] [pos-neg] [5]
eastbound(A) :-
has_car(A,B), wheels(B,2).
[pos cover = 5 neg cover = 0] [pos-neg] [5]
eastbound(A) :-
has_car(A,B), load(B,triangle,1).
[pos cover = 5 neg cover = 0] [pos-neg] [5]
eastbound(A) :-
has_car(A,B), has_car(A,C).
[pos cover = 5 neg cover = 0] [pos-neg] [5]
eastbound(A) :-
has_car(A,B), has_car(A,C).
[pos cover = 5 neg cover = 0] [pos-neg] [5]
eastbound(A) :-
has_car(A,B), long(B).
[pos cover = 2 neg cover = 0] [pos-neg] [2]
eastbound(A) :-
has_car(A,B), open_car(B).
[pos cover = 5 neg cover = 0] [pos-neg] [5]
eastbound(A) :-
has_car(A,B), shape(B,rectangle).
[pos cover = 5 neg cover = 0] [pos-neg] [5]
eastbound(A) :-
has_car(A,B), wheels(B,3).
[pos cover = 3 neg cover = 0] [pos-neg] [3]
eastbound(A) :-
has_car(A,B), load(B,hexagon,1).
[pos cover = 1 neg cover = 0] [pos-neg] [1]
eastbound(A) :-
has_car(A,B), has_car(A,C).
[pos cover = 5 neg cover = 0] [pos-neg] [5]
eastbound(A) :-
has_car(A,B), short(B).
[pos cover = 5 neg cover = 0] [pos-neg] [5]
eastbound(A) :-
has_car(A,B), open_car(B).
[pos cover = 5 neg cover = 0] [pos-neg] [5]
eastbound(A) :-
has_car(A,B), shape(B,rectangle).
[pos cover = 5 neg cover = 0] [pos-neg] [5]
eastbound(A) :-
has_car(A,B), wheels(B,2).
[pos cover = 5 neg cover = 0] [pos-neg] [5]
eastbound(A) :-
has_car(A,B), load(B,circle,1).
[pos cover = 3 neg cover = 0] [pos-neg] [3]
eastbound(A) :-
has_car(A,B), open_car(B), shape(B,rectangle).
[pos cover = 4 neg cover = 0] [pos-neg] [4]
etc etc
The rules are of the form eastbound(A):-blah blah. But it is only counting the eastbound examples. So think of this as example_covered(A):-blah blah
Related
Help, please, find the lower peaks of the list. For example, given an array [1,5,4,6,3] the answer would be [1,4,3]
lower_peaks([X,Y|T],[X|L]):-X<Y,lp2([Y|T],L).
lower_peaks([X,Y|T],L):-lp2([X,Y|T],L).
lp2([X,Y],[Y]):-Y<X.
lp2([_,_],[]).
lp2([X,Y,Z|T],[Y|L]):-Y<X,Y<Z,lp2([Y,Z|T],L).
lp2([X,Y,Z|T],L):-lp2([Y,Z|T],L).
The problem is multiple answers:
?- lower_peaks([1,5,4,6,3],V).
V = [1, 4, 3] ;
V = [1, 4] ;
V = [1, 3] ;
V = [1] ;
V = [4, 3] ;
V = [4] ;
V = [3] ;
V = [] ;
false.
Complete code:
lower_peaks(L,R) :-
lower_peaks_start(L,R).
lower_peaks([_],[]).
lower_peaks([],[]).
lower_peaks_start([X,Y|T],[X|L]) :-
X<Y,
lower_peaks_middle([Y|T],L).
lower_peaks_start([X,Y|T],L) :-
\+ (X<Y),
lower_peaks_middle([Y|T],L).
lower_peaks_middle([X,Y,Z|T],[Y|L]) :-
Y<X, Y<Z,
lower_peaks_middle([Y,Z|T],L).
lower_peaks_middle([X,Y,Z|T],L) :-
\+ (Y<X, Y<Z),
lower_peaks_middle([Y,Z|T],L).
lower_peaks_middle([X,Y],L) :-
lower_peaks_end([X,Y],L).
lower_peaks_end([X,Y],[Y]) :-
Y<X.
lower_peaks_end([X,Y],[]) :-
\+ (Y<X).
Example run:
?- lower_peaks([1,5,4,6,3],V).
V = [1, 4, 3] ;
false.
There were several problems with the code.
The code had guards, e.g. X<Y for the one predicate, but either a cut (!) or better a not guard \+ (X<Y) for the matching predicate was needed.
The code transitioned from the start of the list to the middle, e.g. lower_peaks then to lp2 but did not transition for the end.
The code needed base cases for a list of one or no items.
The code needed a way to transition from the start of list to the end of list if there was no middle.
I'm trying to get Aleph to work and induce a simple theory: grandparent(X,Z):- father(X, Y), father(Y, Z). However i get back an atom (e.g. grandparent(john,johnJuniorJunior)). Hope somebody can help. Note that Aleph for SWI uses a single file as input.
Cheers/JC
My program:
:- use_module(library(aleph)).
:- aleph.
:- modeh(*,grandparent(+person,-person)).
:- modeb(*,father(+person,-person)).
:-begin_bg.
person(john).
person(johnJunior).
person(johnJuniorJunior).
person(jack).
person(jackJunior).
person(jackJuniorJunior).
father(johnJunior, john).
father(johnJuniorJunior, johnJunior).
father(jackJunior, jack).
father(jackJuniorJunior, jackJunior).
:-determination(grandparent/2,father/2).
:-end_bg.
:-begin_in_pos.
grandparent(john, johnJuniorJunior).
grandparent(jack, jackJuniorJunior).
:-end_in_pos.
:-begin_in_neg.
grandparent(jack, john).
:-end_in_neg.
:-aleph_read_all.
My output:
[theory]
[Rule 1] [Pos cover = 1 Neg cover = 0]
grandparent(john,johnJuniorJunior).
[Rule 2] [Pos cover = 1 Neg cover = 0]
grandparent(jack,jackJuniorJunior).
[time taken] [0.0]
[total clauses constructed] [2]
true.
Changing
:- modeh(*,grandparent(+person,-person)).
:- modeb(*,father(+person,-person)).
To
:- modeh(*,grandparent(+person,+person)).
:- modeb(*,father(-person,-person)).
Solved my issue. Thanks Fabrizio!
I'm working with ALEPH reasoning engine in SWI-Prolog. I want to save the rules that ALEPH infers and shows them in SWI-Prolog console, but I have no idea how can I do it!
The sample result is depicted in the picture below,
[Rule 134] [Pos cover = 1 Neg cover = 0]
likes(u9,soccer).
[Rule 135] [Pos cover = 3 Neg cover = 0]
friends(A,u2) :- age(A,adult).
[Rule 136] [Pos cover = 2 Neg cover = 0]
friends(A,u5) :- age(A,adult).
[Rule 137] [Pos cover = 1 Neg cover = 0]
trusts(u1,u5).
[Rule 138] [Pos cover = 1 Neg cover = 0]
trusts(u5,u7).
these rules are shown after calling the induction procedure with this commands:
- read_all(aleph_files).
- induce.
Now I'm wondering how I can store these rules into a txt file automatically.
I found it. It is only needed to say:
write_rules(FileName).
How can I generate all the possible combinations of the elements of a list?
For example, given the list [1,2,3], I want to design a predicate with the form comb([1,2,3], L). which should return the following answer for L:
[1]
[2]
[3]
[1,2]
[2,1]
[1,3]
[3,1]
[2,3]
[3,2]
[1,2,3]
[1,3,2]
[2,1,3]
[2,3,1]
[3,1,2]
[3,2,1]
What you are asking for involves both combinations (selecting a subset) and permutations (rearranging the order) of a list.
Your example output implies that the empty list is not considered a valid solution, so we will exclude it in the implementation that follows. Reconsider if this was an oversight. Also this implementation produces the solutions in a different order than your example output.
comb(InList,Out) :-
splitSet(InList,_,SubList),
SubList = [_|_], /* disallow empty list */
permute(SubList,Out).
splitSet([ ],[ ],[ ]).
splitSet([H|T],[H|L],R) :-
splitSet(T,L,R).
splitSet([H|T],L,[H|R]) :-
splitSet(T,L,R).
permute([ ],[ ]) :- !.
permute(L,[X|R]) :-
omit(X,L,M),
permute(M,R).
omit(H,[H|T],T).
omit(X,[H|L],[H|R]) :-
omit(X,L,R).
Tested with Amzi! Prolog:
?- comb([1,2,3],L).
L = [3] ;
L = [2] ;
L = [2, 3] ;
L = [3, 2] ;
L = [1] ;
L = [1, 3] ;
L = [3, 1] ;
L = [1, 2] ;
L = [2, 1] ;
L = [1, 2, 3] ;
L = [1, 3, 2] ;
L = [2, 1, 3] ;
L = [2, 3, 1] ;
L = [3, 1, 2] ;
L = [3, 2, 1] ;
no
Stay pure by defining comb/2 based on same_length/2, prefix/2, foldl/4 and
select/3:
comb(As,Bs) :-
same_length(As,Full),
Bs = [_|_],
prefix(Bs,Full),
foldl(select,Bs,As,_).
Here's the sample query given by the OP:
?- comb([1,2,3],Xs).
Xs = [1]
; Xs = [2]
; Xs = [3]
; Xs = [1,2]
; Xs = [1,3]
; Xs = [2,1]
; Xs = [2,3]
; Xs = [3,1]
; Xs = [3,2]
; Xs = [1,2,3]
; Xs = [1,3,2]
; Xs = [2,1,3]
; Xs = [2,3,1]
; Xs = [3,1,2]
; Xs = [3,2,1]
; false.
Ok! But what if the list given as the first argument contains duplicates?
?- comb([1,1,2],Xs).
Xs = [1]
; Xs = [1] % (redundant)
; Xs = [2]
; Xs = [1,1]
; Xs = [1,2]
; Xs = [1,1] % (redundant)
; Xs = [1,2] % (redundant)
; Xs = [2,1]
; Xs = [2,1] % (redundant)
; Xs = [1,1,2]
; Xs = [1,2,1]
; Xs = [1,1,2] % (redundant)
; Xs = [1,2,1] % (redundant)
; Xs = [2,1,1]
; Xs = [2,1,1] % (redundant)
; false.
Not quite! Can we get rid of above redundant answers? Yes, simply use selectd/3!
comb(As,Bs) :-
same_length(As,Full),
Bs = [_|_],
prefix(Bs,Full),
foldl(selectd,Bs,As,_).
So let's re-run above query again with the improved implementation of comb/2!
?- comb([1,1,2],Xs).
Xs = [1]
; Xs = [2]
; Xs = [1,1]
; Xs = [1,2]
; Xs = [2,1]
; Xs = [1,1,2]
; Xs = [1,2,1]
; Xs = [2,1,1]
; false.
there is a predefined predicate called permutation ...
1 ?- permutation([1,2,3],L).
L = [1, 2, 3] ;
L = [2, 1, 3] ;
L = [2, 3, 1] ;
L = [1, 3, 2] ;
L = [3, 1, 2] ;
L = [3, 2, 1] .
2 ?- listing(permutation).
lists:permutation([], [], []).
lists:permutation([C|A], D, [_|B]) :-
permutation(A, E, B),
select(C, D, E).
lists:permutation(A, B) :-
permutation(A, B, B).
true.
hope this helps ..
Hint: This is easy to do if you have written a predicate inselt(X,Y,Z), which holds if any insertion of Y into X gives Z:
inselt([E|X], Y, [E|Z]) :- inselt(X,Y,Z).
inselt(X, Y, [Y|X]).
Then comb/3 can be coded recursively using inselt/3.
This is for GNU-Prolog
I'm having trouble getting a certain predicate to work. Its functionality is that it matches a list of integers
that have a domain of 1 to N with no duplicates and length N. Basically what I want to do is have this as inputs and outputs:
| ?- row_valid(X, 3).
X = [1, 2, 3] ? ;
X = [1, 3, 2] ? ;
X = [2, 1, 3] ? ;
X = [2, 3, 1] ? ;
X = [3, 1, 2] ? ;
X = [3, 2, 1] ? ;
no
| ?- row_valid(X, 2).
X = [1, 2] ? ;
X = [2, 1] ? ;
no
| ?- row_valid(X, 1).
X = [1] ? ;
no
But right now, this is what is happening:
| ?- row_valid(X, 3).
X = [] ? ;
no
This is probably happening because of the row_valid([], _). predicate I have in the code. However, I can verify that the predicate matches correctly since:
| ?- row_valid([1,2,3], 3).
true ?
yes
Here are the predicates defined. Do you have any suggestions on how I could get this to work the way I want? Thanks for your time.
% row_valid/2: matches if list of integers has domain of 1 to N and is not duplicated
% 1 - list of integers
% 2 - N
row_valid([], _).
row_valid(Row, N) :-
length(Row, N), % length
no_duplicates_within_domain(Row, 1, N),
row_valid(RestRow, N).
% no_duplicates/1: matches if list doesn't have repeat elements
% 1 - list
no_duplicates([]). % for empty list always true
no_duplicates([Element | RestElements]) :-
\+ member(Element, RestElements), % this element cannot be repeated in the list
no_duplicates(RestElements).
% within_domain/3 : matches if list integers are within a domain
% 1 - list
% 2 - min
% 3 - max
within_domain(Integers, Min, Max) :-
max_list(Integers, Max),
min_list(Integers, Min).
% no_duplicates_within_domain/3: matches if list integers are within a domain and isn't repeated
% 1 - list
% 2 - min
% 3 - max
no_duplicates_within_domain(Integers, Min, Max) :-
no_duplicates(Integers),
within_domain(Integers, Min, Max).
How about the following?
row_valid(Xs,N) :-
length(Xs,N),
fd_domain(Xs,1,N),
fd_all_different(Xs),
fd_labeling(Xs).
Running it with GNU Prolog 1.4.4:
?- row_valid(Xs,N).
N = 0
Xs = [] ? ;
N = 1
Xs = [1] ? ;
N = 2
Xs = [1,2] ? ;
N = 2
Xs = [2,1] ? ;
N = 3
Xs = [1,2,3] ? ;
N = 3
Xs = [1,3,2] ? ;
N = 3
Xs = [2,1,3] ? ;
N = 3
Xs = [2,3,1] ? ;
N = 3
Xs = [3,1,2] ? ;
N = 3
Xs = [3,2,1] ? ;
N = 4
Xs = [1,2,3,4] ? % ...and so on...
Here is a simple piece of code that does this in SWI-Prolog. I don't know if GNU-Prolog provides between/3 and permutation/2, so maybe it doesn't directly answer your question, but maybe it can still help you further.
row_valid(List, N) :-
findall(X, between(1, N, X), Xs),
permutation(Xs, List).
Usage examples:
?- row_valid(List, 0).
List = [].
?- row_valid(List, 1).
List = [1] ;
false.
?- row_valid(List, 2).
List = [1, 2] ;
List = [2, 1] ;
false.
?- row_valid(List, 3).
List = [1, 2, 3] ;
List = [2, 1, 3] ;
List = [2, 3, 1] ;
List = [1, 3, 2] ;
List = [3, 1, 2] ;
List = [3, 2, 1] ;
false.