calling random somehow ends the execution

32 views
Skip to first unread message

Xuan Wu

unread,
Apr 19, 2025, 6:34:17 PMApr 19
to CLIPSESG
Hi this is a weird issue but most likely I missed something obvious. I can get a infinitely growing energy using code below, which is expected and desired effect:

(deftemplate human
  (slot energy))

(defrule time_flies
  ?h <- (human (energy ?energy))
  =>
  (modify ?h (energy (+ ?energy 1))))

But if I change the 1 to (random -3 3), somehow the execution seems to end after one modification, with energy setting to a random value between -3 and 3. How could I get the energy keep changing like before?

Xuan Wu

unread,
Apr 19, 2025, 8:27:30 PMApr 19
to CLIPSESG
BTW the fact I used for debugging was:

(assert (human (energy 0)))

With 1, after "Halt execution" manually, matches returns below:

Matches for Pattern 1
f-1
Activations
f-1
(1 0 1)

After changing to (random 0 5) and ends by itself after (run), Activations is None:

CLIPS> (matches time_flies)
Matches for Pattern 1
f-1
Activations
 None
(1 0 0)

Xuan Wu

unread,
Apr 20, 2025, 9:48:02 PMApr 20
to CLIPSESG
If I replace modify with retract &assert as below:

(defrule time_flies
  ?h <- (human (energy ?energy))
  =>
  (retract ?h)
  (assert (human (energy (+ ?energy (random -3 3))))))

A new human is created infinitely with energy changing as expected and an increasing index. Maybe the combination of modify and random is the problem?

Then I tried using other function like simple /:

(defrule time_flies
  ?h <- (human (energy ?energy))
  =>
  (modify ?h (energy (+ ?energy (/ ?energy 2)))))

With fact: (assert (human (energy 1)))

It ends almost instantly with energy set to inf.0!

After slowing down the process to (/ ?energy 20000), it used several seconds to reach inf.0, and ends by itself. If change to retract&assert, it goes infinitely even after energy reaches inf.0.

This seems like another issue though, as the case with random function didn't involve inf.0.

Xuan Wu

unread,
Apr 20, 2025, 10:55:24 PMApr 20
to CLIPSESG
It turns out, if I use (random 1 3), modify behaves the same as retract&assert. My guess is, if the new value of energy is the same as before, when (random -3 3) returns 0, it doesn't assert any fact to trigger the rule and ends execution.

As stated in "12.9.3 Modifying Template Facts" in the reference manual:

If all slot changes specified in the modify command match the current values of the fact to be modified, no action is taken.

CLIPS Support

unread,
Apr 22, 2025, 10:32:52 PMApr 22
to CLIPSESG
Yes, that's what's happening. If you assert the exact same fact it won't do a retract and assert as it did in prior versions.

Xuan Wu

unread,
Apr 22, 2025, 11:14:07 PMApr 22
to CLIPSESG
Thanks for confirming. As developer needs to keep in mind to be sure that the new value is definitely different from the old value when using (modify), using retract&assert seems to be a way requiring less burden of mind with less chance of unexpected consequences.

CLIPS Support

unread,
Apr 23, 2025, 9:04:26 PMApr 23
to CLIPSESG
There were two long standing behaviors. 

1. Asserting an identical fact is a no-op.
2. Modify was initially implemented as a retract/assert.

Its functionality has changed to appear more like an actual modification than a complete retract/assert. Watched facts just display the changed slots. The fact-index does not change when you modify a fact. So there is an argument that a modify that doesn't change slots should now be a no-op.

But here's the use case that convinced me to change the behavior:

(defrule example
   (change (x ?x) (y ?y) (z ?z))
   ?d <- (data (x ?xd) (y ?yd) (z ?zd))
   (test (or (neq ?x ?xd) (neq ?y ?yd) (neq ?z ?zd)))
   =>
   (modify ?d (x ?x) (y ?y) (z ?z)))

can be rewritten as:

(defrule example
   (change (x ?x) (y ?y) (z ?z))
   ?d <- (data)
   =>
   (modify ?d (x ?x) (y ?y) (z ?z)))

Xuan Wu

unread,
Apr 23, 2025, 10:36:52 PMApr 23
to CLIPSESG
No-op when no change to slot does make sense to me. What caught me off guard was that a match doesn't trigger rule anymore. Case like below:

(deftemplate human
  (slot energy))

(defrule time_flies
  ?h <- (human (energy ?energy))
  =>
  (modify ?h (energy ?energy)))

with fact: (assert (human (energy 1)))
would end right away, as if there's no fact matching '?h <- (human (energy ?energy))' any more. While running matches shows below:

```
CLIPS> (matches time_flies)
Matches for Pattern 1
f-1
Activations
 None
(1 0 0)
```

Newbie like me may not figure out why there exists a match but no activation.

CLIPS Support

unread,
Apr 25, 2025, 1:03:18 PMApr 25
to CLIPSESG
 No, that should work as it always has, except for no looping when the fact is modified.

        CLIPS (6.4 2/9/21)
CLIPS>
(deftemplate human
  (slot energy))
CLIPS>
(defrule time_flies
  ?h <- (human (energy ?energy))
  =>
  (modify ?h (energy ?energy)))
CLIPS> (assert (human (energy 1)))
==> f-1     (human (energy 1))
<Fact-1>
CLIPS> (agenda)
0      time_flies: f-1
For a total of 1 activation.

CLIPS> (matches time_flies)
Matches for Pattern 1
f-1
Activations
f-1
(1 0 1)
CLIPS> (run)

CLIPS> (matches time_flies)
Matches for Pattern 1
f-1
Activations
 None
(1 0 0)
CLIPS> 

Reply all
Reply to author
Forward
0 new messages