1

I have a problem in which I have a list of elements and I have to cycle through all instances of a particular /2 predicate to find which one has he highest number of matching elements in its list. In terms of implementation I can't seem to figure out how I should be updating the highest match so far and then stopping when there are no more.

findAnswer(MyList, HighMatchNum,_):-
    answer(X,Y),
    myIntersection(MyList, Y, NUM), //handles a single instance check and returns how many elements match.
    NUM > HighMatchNum,
    findAnswer(MyList, NUM, answer(X,Y)).

//Knowledge base
 answer(sample1, [a,b,c,d]).
 answer(sample2, [d,c,e]).
false
  • 10,264
  • 13
  • 101
  • 209
user2211776
  • 239
  • 1
  • 2
  • 11

3 Answers3

2

To find the best, we have to search through the whole list, to its end. We will maintain the best so far and its score as additional arguments:

best_match(MyList,R-RN):-
  findall(X, (answer(A,L), X=A-L), ALL),
  ALL = [A-L|T],
  myIntersection(MyList, L, N),
  find_best(MyList,T,A,N,R,RN).

find_best(_,[],A,N,A,N).
find_best(MyList,[B-H|T],A,N,R,RN):-
  myIntersection(MyList, H, K),
  ( K>N -> find_best( MyList, T, B, K, R, RN)
    ;      find_best( MyList, T, A, N, R, RN ).

this produces the name and score of the best match.

Will Ness
  • 70,110
  • 9
  • 98
  • 181
2

there is library(aggregate):

findAnswer(MyList, HighMatchNum, K) :-
    aggregate_all(max(N, Key),
              (   answer(Key, List),
                  myIntersection(MyList, List, N)
              ),
              max(HighMatchNum, K)).

myIntersection(MyList, List, N) :-
    intersection(MyList, List, L),
    length(L, N).

% Knowledge base
answer(sample1, [a,b,c,d]).
answer(sample2, [d,c,e]).

yields

?- findAnswer([a], C, K).
C = 1,
K = sample1.

?- findAnswer([d,e], C, K).
C = 2,
K = sample2.
CapelliC
  • 59,646
  • 5
  • 47
  • 90
1

Simply assert it, I can not see how you can propagate the max value in your solution.

:- dynamic maxval/1
:- maxval(0).

findAnswer(MyList, HighMatchNum) :-
    answer(X,Y),
    myIntersection(MyList, Y, NUM), %handles a single instance check and returns how many   elements match.
    NUM > HighMatchNum,             %If this fails, try other answer
    retract(maxval(_), assert(maxval(X)),!, %else retract the previous value and assert the new one
    findAnswer(MyList, NUM).

Finally check the value of maxval/1 as maxval(X). This algorithm will always fail so you will get the solution in the user database, the problem is with your implementation, you may check your logic. However it will assert the proper answer. You must remember to always implement a base case for any recursive procedure.

jdavid_1385
  • 107
  • 6
  • it will *surely* fail, and the result will be asserted in the database. Also, `findAnswer` will always start from the start of all the `answer` facts. If you can use non-standard solutions, better use `nb_setval` in SWI, combined with `fail`, to achieve linear searching. – Will Ness Apr 28 '13 at 14:42
  • It will definitely fail, thanks. I would make it work simply by adding a helper predicate with two realizations, one would call findAnswer and on its failure the second will retrieve the value. – jdavid_1385 Apr 28 '13 at 14:53
  • yes, that's possible. This deals with aftermath of the search. I was referring though to the search itself. your `findAnswer` skips along the possible solutions which are shorter, but when it finds one that's longer than current maximum, it calls `findAnswer` again, and it will start from the first answer anew, not from the current longest answer. That's what I meant. :) Hmm, I'm also noticing right now that you must insert a cut before that last call to `findAnswer`. – Will Ness Apr 28 '13 at 15:04
  • The cut is not neccesary and even more it won't work since you have to initialize HighMatchNum to zero and given the first retrieved Y intersection with MyList is greater than zero, the algorithm will succeed and the next failure will make it stop. – jdavid_1385 Apr 28 '13 at 15:21
  • It works without the cut, but sure you are right. I didn't think about the code, I just half fixed what he gave so I didn't realize that the engine will backtrack to the entry point with 0 again for the first trial, and will keep asserting the solution, though is the same it will be asserted 100 times if there are such number of entries. Either you have plenty of experience with cut or you have a very good eye. Admitedly I traced it, since I don't use cuts so much, only when I really see the need, and I failed to see this. Sure I have to rethink about my implementations from now. Thank you. – jdavid_1385 Apr 28 '13 at 17:36
  • only if it's fun for you. :) most important thing to have fun. :) btw without the cut, if there are two equals, it finds the last one. and with cut it stays on the first. that was our intent there, right, with `NUM > HighMatchNum`? also, measured with `time/1` in SWI Prolog, it shows twice as much inferences without the cut, it keeps working, coming back. No need to re-work everything, just adding cut is half the improvement; using `nb_setval` is the other half. I think. :) Cheers, – Will Ness Apr 28 '13 at 18:03
  • Nice to have fun along with a depper insight of the paradigms we use with a little bit help of the views of more experienced entities in our Herbrand universe :). Just say that this program without cut is a piece of s**t. Thanks again, and have fun. – jdavid_1385 Apr 28 '13 at 18:40