calling random somehow ends the execution

42 views
Skip to first unread message

Xuan Wu

unread,
Apr 19, 2025, 6:34:17 PM4/19/25
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 PM4/19/25
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 PM4/20/25
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 PM4/20/25
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 PM4/22/25
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 PM4/22/25
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 PM4/23/25
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 PM4/23/25
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 PM4/25/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