0
votes

I have a series of rules and a set of initial (assert) facts. Now, I want to add those facts, run the rules, and then apply another set of rules to check if the current existing facts after (run) contains correct facts and nothing else, without triggering the previous rules anymore and without destroying current facts. Then, I want to keep going applying new facts, running new rules, and test new inserted facts, etc.

How can I do that? My test (batch) file is something like:

(clear) ; just in case
(load constructs.clp) ; All loaded in the MAIN module.

(assert (blabla))
(assert (blabla2))
(run)

;; Code (rules/functions... I'm still wondering how to do it) to check
;; current facts

(assert (blabla3))
(assert (blabla4))
(run)

;; More tests.

(exit)

I have tried to create, for each deftemplate T a deftemplate T-copy with same slots and them apply a (assert (testing)) fact to make the copies first. Then I fire a set of rules with testing purposes and higher salience that "halts" the (run) execution when it's done, to avoid firing the previous rules (the rules I'm testing). The problem with that approach, apart from requiring too many steps, is that I don't know the salience of the original rules and so I cannot be sure that the testing rules will have more priority.

I'm aware of the defmodule constructs and the focus stack but I haven't understood them yet. If my guesses are correct, I think I could put all of my testing rules in a specific module and place the focus on that module to avoid execution of any MAIN rule. If something is wrong, I'll (halt) execution in one of the testing rules or just (exit) the batch script. If everything is correct, I pop the testing module to come back to MAIN, add more assert, (run) again, and them push the testing module again with new tests to see if everything is still correct.

But I'm not sure if my assumptions are right I'll like to see an example of how should I do the testing.

PD: In addition, my CLIPS version has no support for fact-set queries.

1

1 Answers

1
votes

Here's the general idea of separating the core group of rules from the rules doing the testing into separate modules and then using the focus command to execute the testing rules.

CLIPS> (defmodule MAIN (export ?ALL))
CLIPS> (deftemplate MAIN::point (slot x) (slot y))
CLIPS> 
(defrule MAIN::r1
   =>
   (assert (point (x 1) (y 2)))
   (assert (point (x 1) (y 5))))
CLIPS> (defmodule TESTING (import MAIN ?ALL))
CLIPS> 
(defrule TESTING::horizontal
   (point (x ?x1) (y ?y))
   (point (x ?x2&:(< ?x2 ?x1)) (y ?y))
   =>
   (printout t "Horizonal issue " ?y crlf))
CLIPS> (reset)
CLIPS> (agenda)
0      r1: *
For a total of 1 activation.
CLIPS> (run)
CLIPS> (facts)
f-0     (initial-fact)
f-1     (point (x 1) (y 2))
f-2     (point (x 1) (y 5))
For a total of 3 facts.
CLIPS> (focus TESTING)
TRUE
CLIPS> (agenda)
CLIPS> (run)
CLIPS> 
(defrule MAIN::r2
   =>
   (assert (point (x 3) (y 2))))
CLIPS> (run)
CLIPS> (facts)
f-0     (initial-fact)
f-1     (point (x 1) (y 2))
f-2     (point (x 1) (y 5))
f-3     (point (x 3) (y 2))
For a total of 4 facts.
CLIPS> (focus TESTING)
TRUE
CLIPS> (run)
Horizonal issue 2
CLIPS> 
(defrule TESTING::vertical
   (point (x ?x) (y ?y1))
   (point (x ?x) (y ?y2&:(< ?y2 ?y1)))
   =>
   (printout t "Vertical issue " ?x crlf))
CLIPS> (focus TESTING)
TRUE
CLIPS> (agenda)
0      vertical: f-2,f-1
For a total of 1 activation.
CLIPS> (run)
Vertical issue 1
CLIPS>