I’m using CLIPS for a university project, it’s a question driven expert system, and I need to ask randomly a few initial questions, so I wrote this group of rules, and (set-strategy random):
(defrule ask-age
(not (age ?))
=>
(bind ?answer (question “What’s your age?”))
(assert (age ?answer)))
(defrule ask-gender
(not (age ?))
=>
(bind ?answer (question “What’s your gender?”))
(assert (gender ?answer)))
(defrule ask-main-symptom
(not (main-symptom ? TRUE))
=>
(bind ?answer (question “What’s the main symptom?”))
(assert (main-symptom ?answer TRUE)))
Based upon the knowledge about the main symptom, another group of rules gets activated, and I need to change the conflict resolution strategy.
Is it correct to put (set-strategy complexity) in ask-main-symptom rule, after (assert (main-symptom ?answer TRUE))? There is a better way?
(defrule ask-main-symptom
(not (main-symptom ? TRUE))
=>
(bind ?answer (question “What’s the main symptom?”))
(assert (main-symptom ?answer TRUE))
(set-strategy complexity))
There's nothing wrong with it per se, but other than using the random strategy to check for potentially conflicting rules and lex/mea for running programs originally written in OPS5, I've never come across a situation where I used a strategy other than depth let alone using two different strategies during execution. If changing the strategy is one of the project requirements, then I'd do it from a rule, but rather than doing it from the ask-main-symptom rule which will fire randomly in relation to the other question rules, create a lower salience rule that changes the strategy after all the question rules have had an opportunity to execute.
Related
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.
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.
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.
I am learning Scheme, coming from a background of Haskell, and I've run into a pretty surprising issue - scheme doesn't seem to have custom data types??? (ie. objects, structs, etc.). I know some implementations have their own custom macros implementing structs, but R6RS itself doesn't seem to provide any such feature.
Given this, I have two questions:
Is this correct? Am I missing a feature that allows creation of custom data types?
If not, how do scheme programmers structure a program?
For example, any function trying to return multiple items of data needs some way of encapsulating the data. Is the best practice to use a hash map?
(define (read-user-input)
(display "1. Add todo\n2. Delete todo\n3. Modify todo\n")
(let ((cmd-num (read)))
(if (equal? cmd-num "1") '(("command-number" . cmd-num) ("todo-text" . (read-todo)))
(if (equal? cmd-num "2") '(("command-number" . cmd-num) ("todo-id" . (read-todo-id)))
'(("command-number" . cmd-num) ("todo-id" . (read-todo-id)))))))
In order to answer your question, I think it might help to give you a slightly bigger-picture comment.
Scheme has often been described as not so much a single language as a family of languages. This is particularly true of R5RS, which is still what many people mean when they say "Scheme."
Nearly every one of the languages in the Scheme family has structures. I'm personally most familiar with Racket, where you can define structures with
struct or define-struct.
"But", you might say, "I want to write my program so that it runs in all versions of Scheme." Several very smart people have succeeded in doing this: Dorai Sitaram and Oleg Kiselyov both come to mind. However, my observation about their work is that generally, maintaining compatibility with many versions of scheme without sacrificing performance usually requires a high level of macro expertise and a good deal of Serious Thinking.
It's true that several of the SRFIs describe structure facilities. My own personal advice to you is to pick a Scheme implementation and allow yourself to feel good about using whatever structure facilities it provides. In some ways, this is not unlike Haskell; there are features that are specific to ghc, and generally, I claim that most Haskell programmers are happy to use these features without worrying that they don't work in all versions of Haskell.
Absolutely not. Scheme has several SRFIs for custom types, aka. record types, and with R7RS Red edition it will be SRFI-136, but since you mention R6RS it has records defined in the standard too.
Example using R6RS:
#!r6rs
(import (rnrs))
(define-record-type (point make-point point?)
(fields (immutable x point-x)
(immutable y point-y)))
(define test (make-point 3 7))
(point-x test) ; ==> 3
(point-y test) ; ==> 7
Early Scheme (and lisp) didn't have record types and you usually made constructors and accessors:
Example:
(define (make-point x y)
...)
(define (point-x p)
...)
(define (point-y p)
...)
This is the same contract the record types actually create. How it is implemented is really not important. Here are some ideas:
(define make-point cons)
(define point-x car)
(define point-y cdr)
This works most of the time, but is not really very safe. Perhaps this is better:
(define tag (list 'point))
(define idx-tag 0)
(define idx-x 1)
(define idx-y 2)
(define (point? p)
(and (vector? p)
(positive? (vector-length p))
(eq? tag (vector-ref p idx-tag))))
(define (make-point x y)
(vector tag x y))
;; just an abstraction. Might not be exported
(define (point-acc p idx)
(if (point? p)
(vector-ref p idx)
(raise "not a point")))
(define (point-x p)
(point-acc p idx-x))
(define (point-y p)
(point-acc p idx-y))
Now if you look the the reference implementation for record types you'll find they use vectors so the vector version and R6RSs isn't that different.
Lookup? You can use a vector, list or a case:
Example:
;; list is good for a few elements
(define ops `((+ . ,+) (- . ,-)))
(let ((found (assq '+ ops)))
(if found
((cdr found) 1 2)
(raise "not found")))
; ==> 3
;; case (switch)
((case '+
((+) +)
((-) -)
(else (raise "not found"))) 1 2) ; ==> 3
Of course you have hash tables in SRFI-125 so for a large number of elements its probably vice. Know that it probably uses vector to store the elements :-)
I've been trying to do something like this in python:
(set-option :smt.arith.solver 1)
(declare-const x Int)
(declare-const y Int)
(assert (>= 10 x))
(assert (>= x (+ y 7)))
(maximize (+ x y))
(check-sat)
I've been able to do it for a solver (solver.set('smt.arith.solver', 1)), but cannot do it with the Optimize class. Is it possible to write something like the above in python?
Also, does the solver that has been set to difference logic throw an error if it gets a regular integer linear program?
The standard way of stating the logic is to provide the SMT-LIB name of the logic when you create the solver instance, using the SolverFor() factory (see https://z3prover.github.io/api/html/z3.html )
It is not necessary to set a logic to get Z3 working, so it might be worth getting to a working version of your problem without worrying about the logic.
I am starting to learn CLIPS at the moment and asked myself when is it better to use symbols and when strings?
On first sight it seems to me, that symbols are favorable because they are easier to compare than strings.
(eq test test)
is faster than
(= (str-compare "test" "test") 0)
Is there a downside to it too?
The advantage of symbols compared to strings is that you have to enter two fewer characters (the quotation marks). The disadvantage of symbols compared to strings is that some delimiters aren't allowed (notably the space characters). The str-compare function is primarily provided for alphabetic sorting. For equality testing, you can use eq:
CLIPS> (eq "test" "test")
TRUE
CLIPS> (eq "test" "nottest")
FALSE
CLIPS>
I am a newbie in scheme, and I am in the process of writing a function that checks pairwise disjointess of rules (for the time being is incomplete), I used symbols and lists in order to represent the rues of the grammar. Uppercase symbol is a non-terminal in the grammar, and lowercase is a terminal. I am trying to check if a rule passes the pairwise disjointness test.
I will basically check if a rule has only one unique terminal in it. if it is the case, that rule passes the pairwise disjointness test. In scheme, I am thinking to realize that by representing the terminal symbol in lower case. An example of that rule would be:
'(A <= (a b c))
I will then check the case of a rule that contains an or. like:
'(A <= (a (OR (a b) (a c))))
Finally, I will check recursively for non terminals. A rule for that case would be
'(A <= (B b c))
However, What is keeping me stuck is how to use those symbols as data in order to be processed and recurse upon it. I thought about converting the symbols to strings, but that did not in case of having a list like that for example '(a b c) How can I do it?
Here is what I reached so far:
#lang racket
(define grammar
'(A <= (a A b))
)
(define (pairwise-disjoint lst)
(print(symbol->string (car lst)))
(print( cddr lst))
)
Pairwise Disjoint
As far as I know, the only way to check if a set is pairwise disjoint is to enumerate every possible pair and check for matches. Note that this does not follow the racket syntax, but the meaning should still be pretty clear.
(define (contains-match? x lst)
(cond ((null? x) #f) ; Nothing to do
((null? lst) #f) ; Finished walking full list
((eq? x (car lst)) #t) ; Found a match, no need to go further
(else
(contains-match? x (cdr lst))))) ; recursive call to keep walking
(define (pairwise-disjoint? lst)
(if (null? lst) #f
(let ((x (car lst)) ; let inner vars just for readability
(tail (cdr lst)))
(not
;; for each element, check against all later elements in the list
(or (contains-match? x tail)
(contains-match? (car tail) (cdr tail)))))))
It's not clear to me what else you're trying to do, but this is the going to be the general method. Depending on your data, you may need to use a different (or even custom-made) check for equality, but this works as is for normal symbols:
]=> (pairwise-disjoint? '(a b c d e))
;Value: #t
]=> (pairwise-disjoint? '(a b c d e a))
;Value: #f
Symbols & Data
This section is based on what I perceive to be a pretty fundamental misunderstanding of scheme basics by OP, and some speculation about what their actual goal is. Please clarify the question if this next bit doesn't help you!
However, What is keeping me stuck is how to use those symbols as data...
In scheme, you can associate a symbol with whatever you want. In fact, the define keyword really just tells the interpreter "Whenever I say contains-match? (which is a symbol) I'm actually referring to this big set of instructions over there, so remember that." The interpreter remembers this by storing the symbol and the thing it refers to in a big table so that it can be found later.
Whenever the interpreter runs into a symbol, it will look in its table to see if it knows what it actually means and substitute the real value, in this case a function.
]=> pairwise-disjoint?
;Value 2: #[compound-procedure 2 pairwise-disjoint?]
We tell the interpreter to keep the symbol in place rather than substituting by using the quote operator, ' or (quote ...):
]=> 'pairwise-disjoint?
;Value: pairwise-disjoint?
All that said, using define for your purposes is probably a really poor decision for all of the same reasons that global variables are generally bad.
To hold the definitions of all your particular symbols important to the grammar, you're probably looking for something like a hash table where each symbol you know about is a key and its particulars are the associated value.
And, if you want to pass around symbols, you really need to understand the quote and quasiquote.
Once you have your definitions somewhere that you can find them, the only work that's left to you is writing something like I did above that is maybe a little more tailored to your particular situation.
Data Types
If you have Terminals and Non-Terminals, why not make data-types for each? In #lang racket the way to introduce new data type is with struct.
;; A Terminal is just has a name.
(struct Terminal (name))
;; A Non-terminal has a name and a list of terms
;; The list of terms may contain Terminals, Non-Terminals, or both.
(struct Non-terminal (name terms))
Processing Non-terminals
Now we can find the Terminals in a Non-Terminal's list of terms using the predicate Terminal? which is provided automatically when we define the Terminal as a struct.
(define (find-terminals non-terminal)
(filter Terminal? (Non-terminal-terms non-terminal)))
Pairwise Disjoint Terminals
Once we have filtered the list of terms we can determine properties:
;; List(Terminal) -> Boolean
define (pairwise-disjoint? terminals)
(define (roundtrip terms)
(set->list (list->set terms)))
(= (length (roundtrip terminals)
(length terminals))))
The round trip list->set->list isn't necessarily optimized for speed, of course and profiling actual working implementations may justify refactoring, but at least it's been black-boxed.
Notes
Defining data types with struct provides all sorts of options for validating data as the type is instantiated. If you look at the Racket code base, you will see struct used frequently in the more recent portions.
Since grammar has a list within a list, I think you'll have to either test via list? before calling symbol->string (since, as you discovered, symbol->string won't work on a list), or else you could do something like this:
(map symbol->string (flatten grammar))
> '("A" "<=" "a" "A" "b")
Edit: For what you're doing, i guess the flatten route might not be that helpful. so ya, test via list? each time when parsing and handle accordingly.