2014-05-13 4 views
1

J'essaie de faire quelque chose comme «généralisation des faits» dans CLIPS (je ne sais pas quel terme le décrit le mieux) et je ne suis pas sûr comment le faire de la meilleure façon.Généralisation d'un ensemble de faits dans CLIPS (en essayant de trouver des valeurs de fentes correspondantes dans des fentes multislot)

Considérons une telle situation. J'ai un ensemble de faits qui sont décrits par les modèles ci-dessous:

(deftemplate MAIN::simplecause 
    (slot coraxidcause (type INTEGER) (default 0)) 
    (slot changeidcause (type SYMBOL) (default PF1)) 
    (multislot coraxinfo (type SYMBOL) (default undefined)) 
    (multislot changeinfo (type SYMBOL) (default undefined))) 

(deftemplate MAIN::finalcause 
    (multislot coraxinfo (type SYMBOL) (default undefined)) 
    (multislot changeinfo (type SYMBOL) (default undefined)) 
    (slot casecount (type INTEGER) (default 0))) 

Coraxidcause et la combinaison de changeidcause est une sorte de clé - combinaison de ces 2 champs est unique. changeinfo et coraxinfo ont des valeurs symboliques dans les slots (je n'ai toujours pas plus de 10 valeurs dans chacun de ces slots)

J'ai donc quelques faits simples. Ce que je veux faire est de trouver quelles valeurs sont les mêmes dans changeinfo et coraxinfo et de les affirmer. Par exemple, si je ces faits simplecause:

(simplecause (coraxidcause id1) (changeidcause id1) (coraxinfo 1 2 3) (changeinfo a b c)) 

(simplecause (coraxidcause id2) (changeidcause id2) (coraxinfo 2 3 6 7) (changeinfo e a b d f)) 

(simplecause (coraxidcause id3) (changeidcause id3) (coraxinfo 9 11 2 3 0) (changeinfo g a b)) 

(simplecause (coraxidcause id4) (changeidcause id4) (coraxinfo 77) (changeinfo z)) 

Je veux affirmer ce fait:

(finalcause (coraxinfo 2 3) (changeinfo a b)) 

Pour l'instant, je l'ai écrit cette règle:

(defrule MAIN::cause_generalization_initial 
    (simplecause (coraxidcause ?coraxid1) (changeidcause ?factid1) (coraxinfo $? $?coraxdetails $?) (changeinfo $? $?changedetails $?)) 
    (simplecause (coraxidcause ?coraxid2) (changeidcause ?factid2) (coraxinfo $? $?coraxdetails $?) (changeinfo $? $?changedetails $?)) 
    (or (test (<> ?coraxid1 ?coraxid2)) 
           (neq ?factid1 ?factid2)) 
       (not (finalcause (coraxinfo $?coraxdetails) (changeinfo $?changeddetails))) 
    => 
    (assert (finalcause (coraxinfo ?coraxdetails) (changeinfo ?changedetails) (casecount 0)))) 

Le problème est que si nous revenons à ces 4 faits mentionnés plus tôt, il affirme ceci:

(finalcause (coraxinfo 2) (changeinfo a)) 
(finalcause (coraxinfo 3) (changeinfo a)) 
(finalcause (coraxinfo 2 3) (changeinfo b)) 

etc.

Je ne ai pas besoin tous ces 'correspondances partielles', je dois juste la partie entièrement mise en correspondance - (finalcause (coraxinfo 2 3) (changeinfo a b)), et je ne suis pas sûr de savoir comment cela. De plus, une des choses vraiment terribles se produire quand j'ai quelque chose comme ceci:

(simplecause (coraxidcause id5) (changeidcause id5) (coraxinfo 0 1 2 3) (changeidcause a b c)) 

(simplecause (coraxidcause id6) (changeidcause id6) (coraxinfo 6 1 2 3) (changeidcause a b c)) 

En ce moment, le moteur CLIPS va dans smth comme une boucle infinie, LHS répertorie toutes les correspondances possibles:

(finalcause (coraxinfo 1) (changeidcause a)) 
(finalcause (coraxinfo 1) (changeidcause a b)) 

etc.

Cela prend des années (et fait toujours la chose dont je n'ai pas besoin, comme je l'ai mentionné auparavant). Je suis un débutant dans CLIPS donc je suppose que quelque chose me manque, il devrait y avoir un moyen de faire ce dont j'ai besoin. J'apprécierai n'importe quelle aide ou suggestions sur comment faire ceci. Toutes les idées seront vraiment utiles.

On dirait que je n'ai pas clarifié exactement ce que je veux.Je dois trouver tous les possibles appariements accross tous les faits, par exemple, si j'ai ces faits:

(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) (changeinfo abc def))) 

je aurais besoin d'obtenir ce que la sortie:

(finalcause (coraxinfo 2 3) (changeinfo a b)) 
(finalcause 88 99) (changeinfo k m)) 

Répondre

1

Vous pouvez faire cela avec une seule règle, mais il est un peu noueux:

CLIPS> 
(deftemplate simplecause 
    (multislot coraxinfo) 
    (multislot changeinfo)) 
CLIPS>  
(deftemplate finalcause 
    (multislot coraxinfo) 
    (multislot changeinfo)) 
CLIPS> 
(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))) 
CLIPS> 
(defrule cause_generalization_initial 
    ;; There's a simplecause with two subsequences 
    (simplecause (coraxinfo $? $?coraxdetails $?) (changeinfo $? $?changedetails $?)) 
    ;; And every simplecause contains that same subsequence 
    (forall (simplecause (coraxinfo $?all1) (changeinfo $?all2)) 
      (test (and (subsetp $?coraxdetails $?all1) (subsetp $?changedetails $?all2)))) 
    ;; And there's not a longer subsequence where every simplecause contains that subsequence 
    (not (and (simplecause (coraxinfo $? $?coraxdetails2 $?) (changeinfo $? $?changedetails2 $?)) 
      (test (or (and (>= (length $?coraxdetails2) (length $?coraxdetails)) 
          (> (length $?changedetails2) (length $?changedetails))) 
         (and (> (length $?coraxdetails2) (length $?coraxdetails)) 
          (>= (length $?changedetails2) (length $?changedetails))))) 
      (forall (simplecause (coraxinfo $?all1) (changeinfo $?all2)) 
        (test (and (subsetp $?coraxdetails2 $?all1) (subsetp $?changedetails2 $?all2)))))) 
    ;; And a fact for the subsequences has not been generated (since 
    ;; the rule will have an activation for each simple cause) 
    (not (finalcause (coraxinfo $?coraxdetails) (changeinfo $?changedetails))) 
    => 
    (assert (finalcause (coraxinfo $?coraxdetails) (changeinfo $?changedetails)))) 
CLIPS> (reset) 
CLIPS> (agenda) 
0  cause_generalization_initial: f-3,*,*,* 
0  cause_generalization_initial: f-2,*,*,* 
0  cause_generalization_initial: f-1,*,*,* 
For a total of 3 activations. 
CLIPS> (watch rules) 
CLIPS> (run) 
FIRE 1 cause_generalization_initial: f-3,*,*,* 
CLIPS> (facts) 
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  (finalcause (coraxinfo 2 3) (changeinfo a b)) 
For a total of 5 facts. 
CLIPS> 

il est un peu plus facile à comprendre si le travail est réparti entre plusieurs règles:

CLIPS> (unwatch all) 
CLIPS> 
(deftemplate simplecause 
    (multislot coraxinfo) 
    (multislot changeinfo)) 
CLIPS>  
(deftemplate finalcause 
    (multislot coraxinfo) 
    (multislot changeinfo)) 
CLIPS> 
(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))) 
CLIPS> 
(defrule cause_generalization_initial 
    (simplecause (coraxinfo $? $?coraxdetails $?) (changeinfo $? $?changedetails $?)) 
    (forall (simplecause (coraxinfo $?all1) (changeinfo $?all2)) 
      (test (and (subsetp $?coraxdetails $?all1) (subsetp $?changedetails $?all2)))) 
    => 
    (assert (finalcause (coraxinfo $?coraxdetails) (changeinfo $?changedetails)))) 
CLIPS> 
(defrule cause_generalization_better 
    ?f <- (finalcause (coraxinfo $?coraxdetails1) (changeinfo $?changedetails1)) 
    (finalcause (coraxinfo $?coraxdetails2) (changeinfo $?changedetails2)) 
    (test (or (< (length $?coraxdetails1) (length $?coraxdetails2)) 
      (< (length $?changedetails1) (length $?changedetails2)))) 
    => 
    (retract ?f)) 
CLIPS> (reset) 
CLIPS> (run) 
CLIPS> (facts) 
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-24 (finalcause (coraxinfo 2 3) (changeinfo a b)) 
For a total of 5 facts. 
CLIPS> 

La partie clé des deux méthodes est l'élément conditionnel forall qui vérifie que chaque phrase simple contient la sous-séquence considérée.

Une approche modifiée en fonction de votre commentaire:

CLIPS> (clear) 
CLIPS>  
(deftemplate simplecause 
    (multislot coraxinfo) 
    (multislot changeinfo)) 
CLIPS>  
(deftemplate finalcause 
    (multislot coraxinfo) 
    (multislot changeinfo)) 
CLIPS> 
(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) (changeinfo abc def))) 
CLIPS>  
(defrule cause_generalization_initial 
    ?f1 <- (simplecause (coraxinfo $? ?v11 ?v12 $?) (changeinfo $? ?v21 ?v22 $?)) 
    ?f2 <- (simplecause (coraxinfo $? ?v11 ?v12 $?) (changeinfo $? ?v21 ?v22 $?)) 
    (test (neq ?f1 ?f2)) 
    (not (finalcause (coraxinfo ?v11 ?v12) (changeinfo ?v21 ?v22))) 
    => 
    (assert (finalcause (coraxinfo ?v11 ?v12) (changeinfo ?v21 ?v22)))) 
CLIPS> (reset) 
CLIPS> (watch rules) 
CLIPS> (run) 
FIRE 1 cause_generalization_initial: f-6,f-5,* 
FIRE 2 cause_generalization_initial: f-3,f-2,* 
CLIPS> (facts) 
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) (changeinfo abc def)) 
f-8  (finalcause (coraxinfo 88 99) (changeinfo k m)) 
f-9  (finalcause (coraxinfo 2 3) (changeinfo a b)) 
For a total of 10 facts. 
CLIPS> 
+0

Salut Harry. Merci pour votre réponse. Désolé, on dirait que je n'ai pas clarifié tous les points de la question initiale et que je vous ai confondu. Je l'ai mis à jour (veuillez voir la fin de la question originale). Longue histoire courte, j'ai besoin de trouver tous les matchs possibles à travers tous les faits, je ne m'attends pas à trouver ce qui est pareil pour TOUS les faits dans la liste –

+0

Merci, Harry, on dirait que c'est tout. Juste une question de plus. Ai-je raison de dire que si je ne sais pas combien de slots subséquents dans multislot devraient correspondre (actuellement dans la règle que vous avez fournie, supposons qu'il y en a 2, mais peut-être qu'il y en aura 4 ou 5 ou juste 1) $? match11, $? match12 au lieu de? v11? v12 et? v21? v22? Ou je vais devoir écrire une règle distincte pour chacun de ces cas avec différentes quantités de champs correspondants? –

+0

Ok, on dirait que ça marche, maintenant le seul problème est de nettoyer tout le désordre qu'il crée. Vous ne savez pas comment le faire au mieux, essayez ceci: (defrule cause_generalization_better ? F1 <- (finalcause (coraxinfo $? Match1) (changeinfo $? Match2)) ? F2 <- (derniere raison (coraxinfo $? Matchbig1) (changeinfo $ ? matchbig2)) (test (et (sous-ensemble $? match1 $? matchbig1) (sous-ensemble $? match2 $? matchbig2) (neq? f1? f2))) => (retract? f1)) –

0

Ok, avec l'aide de Gary est ici le résultat final:

(deftemplate simplecause 
    (multislot coraxinfo) 
    (multislot changeinfo)) 

(deftemplate finalcause 
    (multislot coraxinfo) 
    (multislot changeinfo)) 

(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) (changeinfo abc def))) 

(defrule cause_generalization_initial 
    ?f1 <- (simplecause (coraxinfo $? $?match1 $?) (changeinfo $? $?match2 $?)) 
    ?f2 <- (simplecause (coraxinfo $? $?match1 $?) (changeinfo $? $?match2 $?)) 
    (test (neq ?f1 ?f2)) 
    (not (finalcause (coraxinfo $?match1) (changeinfo $?match2))) 
    => 
    (assert (finalcause (coraxinfo $?match1) (changeinfo $?match2)))) 

(reset) 

(run) 

;retract simplecause facts and prevent them from adding 'partial matched final causes' 
(do-for-all-facts ((?f simplecause)) TRUE (retract ?f)) 

;retracts partially matched facts so that we have only best matches 
(defrule cause_generalization_better 
    ?f1 <- (finalcause (coraxinfo $?match1) (changeinfo $?match2)) 
    ?f2 <- (finalcause (coraxinfo $?matchbig1) (changeinfo $?matchbig2)) 
    (test (and (subsetp $?match1 $?matchbig1) (subsetp $?match2 $?matchbig2) (neq ?f1 ?f2))) 
    => 
    (retract ?f1)) 


;in some cases we can see facts like (finalcause (coraxinfo 13) (changeinfo)) 
;this happens when there is match by coraxinfo but no match by changeinfo or vice versa 
;we retract such facts too 

(defrule cause_generalization_remove_empty_coraxinfo 
    ?f1 <- (finalcause (coraxinfo)) 
    => 
    (retract ?f1)) 

(defrule cause_generalization_remove_empty_changeinfo 
    ?f1 <- (finalcause (changeinfo)) 
    => 
    (retract ?f1)) 

(run) 
Questions connexes