0
votes

I'm having troubles understanding why doesn't this clips code get trapped in an infinite loop

(defrule rule0
=>
        (assert (my-fact))
)

(defrule rule1
        ?f <- (my-fact)
=>
        (retract ?f)
)

As far as I know, rule0 is executed asserting my-fact then rule1 is executed retracting it. Why doesn't rule0 execute again now?
Here are my thoughts:

  • Clips memorizes for each rule if it was executed using some basis facts and avoids re-executing this rule using the same basis facts.
  • There is some sort of optimizer that detected a loop and avoided it.
  • Clips memorizes the facts that were inserted and deleted, and avoids re-inserting these facts (highly doubt it, I'm almost sure this can't be the case).

Note: I abstracted this piece of code from another small program that uses templates instead of facts.

2

2 Answers

2
votes

Wikipedia has a good overview of how the Rete Algorithm works. One of the key concepts to understand is that rules do not seek the data that satisfy them, rather data seeks out the rules they satisfy. The Rete Algorithm assumes that most data remains the same after each rule firing, so having the rules seek out data would be inefficient since only a fraction of the data changes after each rule firing. Instead rules save the state of what has already been matched and when changes to data is made that effects that state, it is updated.

When rule rule0 is defined, it is activated because it has no conditions. When rule rule1 is defined, it is not activated because my-fact does not yet exist. When rule rule0 is executed, the fact my-fact is asserted, and then rule rule1 has its state updated and is activated. When rule rule1 is executed, my-fact is retracted and the state of rule rule1 is updated since it matches my-fact. Rule rule0 is not affected by this retraction because it doesn't have conditions which match my-fact.

1
votes

Your first explanation is the one to go with. The principle that a rule doesn't fire a second time for the same set of facts is called refraction. With the same set of facts I do not only mean the same value but also the same fact address.

Here, we have a special case. Because rule0 has no LHS, it wouldn't fire a second time, even if the fact base changes. No LHS means no pattern matching and therefore no further activation.

But you can make a rule fire again with the refresh command.

CLIPS> (run)
CLIPS> (refresh rule0)
CLIPS> (agenda)
0      rule0: *
For a total of 1 activation.

Normally, you are not able to insert a fact if the same fact is already in your factbase (if it was retracted you are free to add it again). You can change that with (set-fact-duplication):

CLIPS> (set-fact-duplication TRUE)

But I wouldn't recommend that.