Consider such situation. I have such templates:
(deftemplate MAIN::simplecause
(multislot coraxinfo (type INTEGER) (default undefined))
(multislot changeinfo (type SYMBOL) (default undefined)))
(deftemplate MAIN::finalcause
(multislot coraxinfo (type INTEGER) (default undefined))
(multislot changeinfo (type SYMBOL) (default undefined)))
I know that in coraxinfo slot I will always have not more than 14 values (maybe less, but never more). I also now that in changeinfo multislot I will have not more than 13 values.
I am trying to write a rule which will find all possible matches between any facts I will have.
For instance:
(deffacts start
(simplecause (coraxinfo 1 2 3) (changeinfo a b c))
(simplecause (coraxinfo 7 8 2 3 9) (changeinfo d a b e))
(simplecause (coraxinfo 2 3 10 13) (changeinfo f g a b z))
(simplecause (coraxinfo 77 88 99 66) (changeinfo k m l s))
(simplecause (coraxinfo 88 99 11 22) (changeinfo v k m w))
(simplecause (coraxinfo 13 88 99) (changeinfo k m))
(simplecause (coraxinfo 666 777 888) (changeinfo abc def))
(simplecause (coraxinfo 666 111 222 888 333 444 555 777 999) (changeinfo abc 1a 2a 3a def 4a)))
I would need to get this (order of values in each multislot doesn't matter):
(finalcause (coraxinfo 2 3) (changeinfo a b))
(finalcause 88 99) (changeinfo k m))
(finalcause 666 777 888) (changeinfo abc def))
For now I have stopped on this function:
(defrule cause_generalization_initial1
?f1 <- (simplecause (coraxinfo $?coraxmatch1 $?coraxmatch2 $?coraxmatch3 $?coraxmatch4 $?coraxmatch5 $?coraxmatch6 $?coraxmatch7) (changeinfo $?pricematch1 $?pricematch2 $?pricematch3 $?pricematch4 $?pricematch5 $?pricematch6 $?pricematch7))
?f2 <- (simplecause (coraxinfo $?coraxmatch1 $?coraxmatch2 $?coraxmatch3 $?coraxmatch4 $?coraxmatch5 $?coraxmatch6 $?coraxmatch7) (changeinfo $?pricematch1 $?pricematch2 $?pricematch3 $?pricematch4 $?pricematch5 $?pricematch6 $?pricematch7))
(test (neq ?f1 ?f2))
(not (finalcause (coraxinfo $?coraxmatch1 $?coraxmatch2 $?coraxmatch3 $?coraxmatch4 $?coraxmatch5 $?coraxmatch6 $?coraxmatch7) (changeinfo $?pricematch1 $?pricematch2 $?pricematch3 $?pricematch4 $?pricematch5 $?pricematch6 $?pricematch7)))
=>
(assert (finalcause (coraxinfo $?coraxmatch1 $?coraxmatch2 $?coraxmatch3 $?coraxmatch4 $?coraxmatch5 $?coraxmatch6 $?coraxmatch7) (changeinfo $?pricematch1 $?pricematch2 $?pricematch3 $?pricematch4 $?pricematch5 $?pricematch6 $?pricematch7))))
It is a little bit clumsy, but as far as I remember $? means 'zero or more', so even if I will have less fields than I have specified in search patter it should work. I use up to 7 multislots in each of patterns since having 14 or 13 values as a maximum means that in worst case every second value in multislot will match to smth in other fact.
The issue that when I load the facts specified in deffacts CLIPS goes to a kind of infinite loop - it doesn't responds for a long time so I beleive I have made a mistake in my rule. Also this rule should kill the engine in case I will have couple of facts which are almost same with the difference only in one field. In such case it will produce terrible amount of matches between them. Any idea where I was wrong? I will really appreciate any suggestions.
UPDATE. If we are trying to take the approach of constructin (finalcause) facts by adding one value to coraxinfo and changeinfo slots at a time than I have currently stopped on these 2 rules:
Creates initial finalcause fact with one matching value in both multislots:
(defrule cause_generalization_initial
?f1 <- (simplecause (coraxinfo $? ?coraxmatch $?) (changeinfo $? ?changematch $?))
?f2 <- (simplecause (coraxinfo $? ?coraxmatch $?) (changeinfo $? ?changematch $?))
(test (neq ?f1 ?f2))
(not (finalcause (coraxinfo ?coraxmatch) (changeinfo ?changematch)))
=>
(assert (finalcause (coraxinfo ?coraxmatch) (changeinfo ?changematch)))
If we have any finalcause fact we try to check that all the multislot values in it are subset of everything before the ?coraxmatchafter value in both matching simplecause facts and assert an extended finalcause. I beleive this rule should be able to 'jump over the gaps' in matching simplecauses.
(defrule cause_generalization_advanced
?f1 <- (simplecause (coraxinfo $?coraxbefore1 ?coraxmatchafter $?) (changeinfo $?changebefore1 ?changematchafter $?))
?f2 <- (simplecause (coraxinfo $?coraxbefore2 ?coraxmatchafter $?) (changeinfo $?changebefore2 ?changematchafter $?))
(test (neq ?f1 ?f2))
(finalcause (coraxinfo $?finalcoraxbefore) (changeinfo $?finalchangebefore))
(test (and (subsetp $?finalcoraxbefore $?coraxbefore1) (subsetp $?finalcoraxbefore $?coraxbefore2)
(subsetp $?finalchangebefore $?changebefore1) (subsetp $?finalchangebefore $?changebefore2)))
=>
(assert (finalcause (coraxinfo $?finalcoraxbefore ?coraxmatchafter) (changeinfo $?finalchangebefore ?changematchafter))))
I use the rules with these deffacts (notice that deffacts is different from the one above):
(deffacts start
(simplecause (coraxinfo 1 2 3) (changeinfo a b c))
(simplecause (coraxinfo 7 8 2 3 9) (changeinfo d a b e))
(simplecause (coraxinfo 2 3 10 13) (changeinfo f g a b z))
(simplecause (coraxinfo 77 88 99 66) (changeinfo k m l s))
(simplecause (coraxinfo 88 99 11 22) (changeinfo v k m w))
(simplecause (coraxinfo 13 88 99) (changeinfo k m))
(simplecause (coraxinfo 666 777 888) (changeinfo abc def))
(simplecause (coraxinfo 666 111 222 777 333 444 555 888 999) (changeinfo abc 1a 2a 3a def 4a)))
The issue here is that I expected that it will be able to produce the finalcause for 3 matching fields but it produces only finalcause facts with 2 matching fields and I don't get why. Shouldn't it notice that these 3 facts are falling into the second rule?
(simplecause (coraxinfo 666 777 888) (changeinfo abc def))
(simplecause (coraxinfo 666 111 222 777 333 444 555 888 999) (changeinfo abc 1a 2a 3a def 4a))
(finalcause (coraxinfo 666 888) (changeinfo abc def))
Output of both rules is:
f-0 (initial-fact)
f-1 (simplecause (coraxinfo 1 2 3) (changeinfo a b c))
f-2 (simplecause (coraxinfo 7 8 2 3 9) (changeinfo d a b e))
f-3 (simplecause (coraxinfo 2 3 10 13) (changeinfo f g a b z))
f-4 (simplecause (coraxinfo 77 88 99 66) (changeinfo k m l s))
f-5 (simplecause (coraxinfo 88 99 11 22) (changeinfo v k m w))
f-6 (simplecause (coraxinfo 13 88 99) (changeinfo k m))
f-7 (simplecause (coraxinfo 666 777 888) (changeinfo abc def))
f-8 (simplecause (coraxinfo 666 111 222 777 333 444 555 888 999) (changeinfo abc 1a 2a 3a def 4a))
f-9 (finalcause (coraxinfo 666) (changeinfo abc))
f-10 (finalcause (coraxinfo 666 888) (changeinfo abc def))
f-11 (finalcause (coraxinfo 666 777) (changeinfo abc def))
f-12 (finalcause (coraxinfo 666) (changeinfo def))
f-13 (finalcause (coraxinfo 777) (changeinfo abc))
f-14 (finalcause (coraxinfo 777 888) (changeinfo abc def))
f-15 (finalcause (coraxinfo 777) (changeinfo def))
f-16 (finalcause (coraxinfo 888) (changeinfo abc))
f-17 (finalcause (coraxinfo 888) (changeinfo def))
f-18 (finalcause (coraxinfo 88) (changeinfo k))
f-19 (finalcause (coraxinfo 88 99) (changeinfo k m))
f-20 (finalcause (coraxinfo 88) (changeinfo m))
f-21 (finalcause (coraxinfo 99) (changeinfo k))
f-22 (finalcause (coraxinfo 99) (changeinfo m))
f-23 (finalcause (coraxinfo 2) (changeinfo a))
f-24 (finalcause (coraxinfo 2 3) (changeinfo a b))
f-25 (finalcause (coraxinfo 2) (changeinfo b))
f-26 (finalcause (coraxinfo 3) (changeinfo a))
f-27 (finalcause (coraxinfo 3) (changeinfo b))