0

I am trying to modify a fact template from python using CLIPSPY. It behaves strangely as it does modify a slot for the first time, but then for next slot, it does not and even re-modify the previous modified slot value to something else itself!!

This is the python file.

# run.py
import clips

clips_env = clips.Environment()

def py_modify_s1(p):
    p.retract()
    p["s_1"] = clips.Symbol("ABC") 
    p.assertit()

def py_modify_s2(p):
    p.retract()
    p["s_2"] = clips.Symbol("DEF") 
    p.assertit()

clips_env.define_function(py_modify_s1)
clips_env.define_function(py_modify_s2)

clips_env.load("KB.clp")
clips_env.reset()
clips_env.run()

This is the clp file.

(deftemplate t
        (slot s_1 (type SYMBOL) (default none))
        (slot s_2 (type SYMBOL) (default none))
)

(defrule rule_0
        (initial-fact)
        =>
        (assert (t))
)

(defrule rule_1
        ?p<-(t  (s_1 none) (s_2 none))
        =>
        (py_modify_s1 ?p)
        (facts)
)

(defrule rule_2
        ?p <- (t (s_1 ?x&~none) (s_2 none))
        =>
        (py_modify_s2 ?p)
        (facts)
)

(defrule rule_3
        ?p <- (t (s_1 ?x&~none) (s_2 ?y&~none))
        =>
        (printout t "All set")
        (facts)
)

Running the same clip file in CLIPS shell (replacing py_modify with (modify ?p (s_1,ABC))) produces expected result. But running from clipspy I get:

f-0     (initial-fact)
f-2     (t (s_1 ABC) (s_2 none))
For a total of 2 facts.
f-0     (initial-fact)
f-2     (t (s_1 ▒▒▒3wU) (s_2 none))
For a total of 2 facts.

Notice how s_1 is containing some garbage value after firing of rule_2 and s_2 is not modified only. As a result, rule_3 never gets fired.

greenlantern
  • 374
  • 1
  • 3
  • 15
  • Updated the [old question](https://stackoverflow.com/questions/53967519/how-to-modify-a-fact-in-a-template-using-clipspy) with the latest findings. – noxdafox Jan 01 '19 at 22:48
  • It is not necessary to add the initial-fact to a rule with no other conditions; it is added automatically in versions of CLIPS prior to version 6.3. The initial-fact functionality was deprecated in the 6.3 release; it is still asserted by a reset, but rules without conditions no longer rely on it. In the 6.4 release, the initial-fact is no longer asserted, so rules that explicitly match this fact will no longer be activated. – Gary Riley Jan 03 '19 at 17:25

1 Answers1

0

It turns out facts cannot be modified once asserted via the C (and therefore Python) API. Only way to change a fact is retract the original one and assert a new one. Chapter 4.4.22 EnvPutFactSlot of the Advanced Programming Guide.

The only way possible seems to be retracting the old fact and asserting a new one with updated values.

def modify_fact(fact):
    """Modify a template fact."""
    fact.retract()

    new_fact = fact.template.new_fact()
    new_fact.update(dict(fact))  # copy over old fact slot values

    new_fact["s_1"] = clips.Symbol("v_2") 

    new_fact.assertit()

I raised this issue in a discussion on the CLIPS forum as well.

noxdafox
  • 14,439
  • 4
  • 33
  • 45