问题
I have a rule similar to the following:
(deftemplate person
(slot name ( type INTEGER))
(slot surname ( type INTEGER))
)
(defrule surname_cant_be_a_name
?p1<-(person (name ?n1))
?p2<-(person (surname ?n2&:(= ?n1 ?n2)))
=>
(retract ?p2)
)
Functionally, this works. But I run this on a huge fact-set, and the complexity gets through the roof fairly quickly.
Because the rule is looking for two person objects, there's a nested for-loop kinda situation slowing the execution down. This setup goes through every possible person pairing and only after having a pair the rule filters out based on my setup "&:(= ?n1 ?n2))"
I feel like there must be a smarter way to do this. Ideally, I want p1 to iterate through all person objects, but only match with p2 objects that conform to my rule.
To make my point clearer, I'm looking for something like the following which will avoid double looping:
(defrule surname_cant_be_a_name
?p1<-(person (name ?n1))
?p2<-(person (surname %%JUST_MATCH_n1%% ))
=>
(retract ?p2)
)
Is this possible to achieve something like that? Any recommendation to optimize this rule is appreciated.
Thanks
P.S. Sorry for the ridiculous example, but it highlights my situation very well.
回答1:
If you're comparing variables for equality, it's much more efficient to use the same variable in both places than to use two separate variables and call the = or eq function to compare for equality. Across patterns, hash tables are used to quickly locate facts sharing the same variables, something which isn't done when you're using a function call to perform an equality comparison. For a large number of facts, this can improve performance by orders of magnitude:
CLIPS (6.31 6/12/19)
CLIPS> (clear)
CLIPS>
(deftemplate person
(slot name (type INTEGER))
(slot surname (type INTEGER)))
CLIPS>
(defrule surname_cant_be_a_name
?p1<- (person (name ?n1))
?p2<- (person (surname ?n2&:(= ?n1 ?n2)))
=>
(retract ?p2))
CLIPS> (timer (loop-for-count (?i 10000) (assert (person (name ?i) (surname (+ ?i 1))))))
12.3485549999987
CLIPS> (clear)
CLIPS>
(deftemplate person
(slot name (type INTEGER))
(slot surname (type INTEGER)))
CLIPS>
(defrule surname_cant_be_a_name
?p1 <- (person (name ?n1))
?p2 <- (person (surname ?n1))
=>
(retract ?p2))
CLIPS> (timer (loop-for-count (?i 10000) (assert (person (name ?i) (surname (+ ?i 1))))))
0.0177029999995284
CLIPS> (/ 12.3485549999987 0.0177029999995284)
697.540247434201
CLIPS>
来源:https://stackoverflow.com/questions/58647480/how-to-optimize-pattern-matching-between-different-templated-facts-in-clips