In particular I am trying to determine the best approach to solve the following type of problem:
The example I am interested in is the find-s algorithm in Mitchell's Machine Learning book were it is applied to 4 training examples.
The basic idea is for each training example, x, and hypothesis h, determine h' were it incorporates x by making it more general. I need to map h to h' for each x in the training set. The problem I am having is how to best approach this in a logical programming language. I am using minikanren which is roughly prolog embedded in scheme.
After computing each h', I need to then set! it to a global variable h, and then proceed to the next training example x. The code below is the main part of the program.
(define h '(0 0 0 0 0 0))
(define seto
(lambda (x)
(project (x)
(lambda (s) (set! h x) (succeed s)))))
(run* (q)
(fresh (x h0 h1)
(trainingo x)
(== h h0)
(find-so h0 x h1)
(seto h1)
(== h1 q)))
h is the global variable, seto mutates h with h1 which is the next computed hypothesis from h0 and x training example using the find-s algorithm (find-so).
In prolog it would be (I think) equivalent to assert('hypothesis'(H)) after each training example X (overwriting the the previous one) and calling retract('hypothesis'(H)) after all the training examples have been applied.
Again my question is whether this is the best approach (via side-effects) for solving these kind of problems?
Edit: I accepted @mat answer in conjunction with his comment. In summary I needed to treat the training examples as a list and use forward recursion on that list until I got to the empty list. Were I was getting stuck was in having the training examples as part of the backtracking along with finding the next hypothesis instead of having them in a list of which I can recur on until empty.
What you suggest may seem tempting: Simulate global updates with assertz/0
and retract/1
.
However, there are major drawbacks if you do it this way:
A declarative solution to simulate these state changes is to think in terms of relations between states.
For example, when you use H0
to compute the next hypothesis H1
, then you can express this as a relation between H0
and H1
, and possibly further parameters. Think about predicates like:
hypothesis_next(H0, H1)
algorithm_hypothesis_next(A, H0, H1)
parameters_hypothesis_next(Ps, H0, H1)
Note that such predicates can be read and—ideally—run in all directions!
In total, the entire solution will in your case be modeled as a sequence of hypotheses:
H0
→H1
→H2
→ … →H
For more information and pointers, see the closely related question:
How to avoid using assert and retractall in Prolog to implement global (or state) variables