Age rule is not getting executed properly - jess

I am trying to fire these two rules but i am getting the same output for both the rules.
This is the output i am getting for both.
(defrule old-male
?gender <- (gender m)
?age <- (age ?age&:(> ?age 35))
=>
(printout t "Person is male & older. This Person must go after older females!" crlf)
(retract ?gender)
(retract ?age)
(ask-start-again))
(defrule young-male
?gender <- (gender m)
?age <- (age ?age&:(< ?age 35))
=>
(printout t "Person is male & younger. This Person must go after younger females!" crlf)
(retract ?gender)
(retract ?age)
(ask-start-again))
(reset)
(run)
Please advice what i need to do to fix this.
And also is there a way to store the inputs that are given (gender, age and name) and compare them with another person.?
Thank you!
I have added the rule you advised and also another rule for the list.
(defrule print-solution
=>
(printout t "Name Age Gender" crlf)
(printout t "--------------------------------------" crlf))
I have no errors but the (print-all-persons)rule is not getting executed. Did I miss anything? Kindly advice.
This is the new output I am getting

You are using the same name in the binding to the entire fact (?age <- ...) and the first item of the ordered fact ((age ?age&:...). Just use another name for the latter.
(defrule old-male
?gender <- (gender m)
?age <- (age ?a&:(> ?a 35))
=>
...
For storing age and gender of several persons at the same time a template such as the following can be used. A name is added so that there is a distinction when two üersons of the same gender and age are inserted.
(deftemplate person (slot gender)
(slot age (type INTEGER))
(slot name))
Edit
Q1 from comment: A template (as the name implies) is just a "blueprint" for facts, and you can assert as many as you like.
Q2 from comment: If you add a rule like the following it'll print all Person facts at the end of the show. Note the low salience - if you omit it, the printout happens as soon as the fact is asserted.
(defrule print-all-persons
(declare (salience -1000))
(person (name ?name)(gender ?gender)(age ?age))
=>
(printout t ?name " is a " ?age "-year old "
(if (eq ?gender f) then "fe" else "") "male" crlf)
)

Related

Turning DB information into JSON with keys?

I have a database that returns data as a tree like this:
'((7 "vince" "vince1#test.com" "space" "no value" 1)
(8 "vince" "vince2#test.com" "place" "no value" 1)
(9 "Smith" "Smith#gmail.com" "now" "no value" 1))
The second column is first name and the third column is email.
My goal is to return JSON key value pairs but im struggling
Here is what I have tried:
Function to get name and email from one list item
(defun get-name-&-emails-db1 (lst)
(if (null lst)
nil
(let* ((name (second lst))
(email (third lst)))
(cl-json:encode-json-to-string `((:name . ,name)(:email . ,email))))))
Map over data set
(mapcar #'get-name-&-emails-db1 (return-data-tree))
This returns a list of individual json blocks. But I want it to be ONE json block with all records.
What am I missing?
(ideally, I want to know how to do this without any additional libraries)
Thanks
I tried to encode a list of alists, and this is how it goes:
USER> (cl-json:encode-json
(list '(("a" . "0") ("b" . "1")) '(("a" . "2") ("b" . "3"))))
[{"a":"0","b":"1"},{"a":"2","b":"3"}]
If this is what you want to have, then you need to organize your data in Lisp first, then encode the whole list as JSON instead of formatting each entry individually.
Use mapcar, get the second and third element of each entry, and then call cl-json:encode-json-to-string on the result:
(let ((data '((7 "vince" "vince1#test.com" "space" "no value" 1)
(8 "vince" "vince2#test.com" "place" "no value" 1)
(9 "Smith" "Smith#gmail.com" "now" "no value" 1))))
(cl-json:encode-json-to-string
(mapcar (lambda (e) `((:name . ,(second e))(:email . ,(third e))))
data)))
Here I don't use comma, backquote, alists or plists, but simply: I create a list of hash-tables. I'm quite sure how a list and a hash table are rendered in JSON, so let's rework our data a bit to come back in known territories.
(loop for row in '((7 "vince" "vince1#test.com" "space" "no value" 1)
(8 "vince" "vince2#test.com" "place" "no value" 1)
(9 "Smith" "Smith#gmail.com" "now" "no value" 1))
with result = (list) ;; the list of hash-tables to encode.
for ht = (make-hash-table) ;; intermediary hash-table.
do (setf (gethash "name" ht)
(second row)
(gethash "email" ht)
(third row))
(push ht result)
finally (return (cl-json:encode-json-to-string result)))
;; =>
"[{\"name\":\"Smith\",\"email\":\"Smith#gmail.com\"},{\"name\":\"vince\",\"email\":\"vince2#test.com\"},{\"name\":\"vince\",\"email\":\"vince1#test.com\"}]"
I like Serapeum's dict:
;; replaces (for ht = (make-hash-table)) and the setf
for ht = (dict :name (second row)
:email (third row))
Answers were given. Just a general way to deal with alist and json:
(ql:quickload :yason)
(defparameter *data* '((7 "vince" "vince1#test.com" "space" "no value" 1)
(8 "vince" "vince2#test.com" "place" "no value" 1)
(9 "Smith" "Smith#gmail.com" "now" "no value" 1)))
(defparameter *scheme* '(:id :name :email :meta :value :count))
(defun pairing (keys values)
(loop for a in keys
for b in values
collect (cons (string-downcase (format nil "~A" a)) b)))
(defun alist-json (x &keys keys)
(with-output-to-string (*standard-output*)
(yason:encode-alist (pairing keys x))))
(defun list-json (l)
(format nil "[~{~A~^, ~}]" l))
(defun values-list-keys-json (values-list keys)
(list-json (mapcar (lambda (x) (alist-json x :keys keys)) values-list)))
(values-list-keys-json *data* *scheme*)
#|
=> "[{\"id\":7,\"name\":\"vince\",\"email\":\"vince1#test.com\",\"meta\":\"space\",\"value\":\"no value\",\"count\":1},
{\"id\":8,\"name\":\"vince\",\"email\":\"vince2#test.com\",\"meta\":\"place\",\"value\":\"no value\",\"count\":1},
{\"id\":9,\"name\":\"Smith\",\"email\":\"Smith#gmail.com\",\"meta\":\"now\",\"value\":\"no value\",\"count\":1}]"
|#
(defun second-third (l)
(subseq l 1 3))
(values-list-keys-json (mapcar #'second-third *data*) (second-third *scheme*))
#|
=> "[{\"name\":\"vince\",\"email\":\"vince1#test.com\"}, {\"name\":\"vince\",\"email\":\"vince2#test.com\"}, {\"name\":\"Smith\",\"email\":\"Smith#gmail.com\"}]"
|#

How to debug this very simple Jess code?

(deftemplate bikelife
(slot name)
(slot type))
(deffacts bike
(bikelife (name Strida) (type low_lifestyle))
(bikelife (name Brompton) (type med_lifestyle))
(bikelife (name Molton) (type high_lifestyle))
(bikelife (name Specialized_AlleComp) (type low_sport))
(bikelife (name Specialized_Tarmac) (type medium_sport))
(bikelife (name Pinarello_DOGMA_F8) (type high_sport)))
(defrule rule-1
(budget ?x)
(test (< ?x 300))
(use_for lifestyle)
=>
(assert (recommend low_lifestyle)))
(defrule rule-2
(budget ?x)
(test (< ?x 300))
(use_for sport)
=>
(assert (recommend low_sport)))
(defrule rule-3
(budget ?x)
(test (and (> ?x 300) (< ?x <500)))
(use_for lifestyle)
=>
(assert (recommend med_lifestyle)))
(defrule rule-4
(budget ?x)
(test (and (> ?x 300) (< ?x <500)))
(use_for sport)
=>
(assert (recommend med_sport)))
(defrule rule-5
(budget ?x)
(test (> ?x 500))
(use_for lifestyle)
=>
(assert (recommend high_lifestyle)))
(defrule rule-6
(budget ?x)
(test (and (> ?x 300) (< ?x <500)))
(use_for sport)
=>
(assert (recommend med_sport)))
(defrule rule-7
(budget ?x)
(test (> ?x 500))
(use_for sport)
=>
(assert (recommend high_sport)))
(defrule recommend-rule
(recommend ?type)
(bikelife (name ?x) (type ?type))
=>
(printout t crlf "I recommend " ?x " for you." crlf crlf))
(defrule ask-1
=>
(printout t crlf "================================ ")
(printout t crlf " testing testing testing. ")
(printout t crlf "================================ " crlf crlf)
(printout t "* How much are you going to spend on bike? ")
(assert (budget (read)))
(printout t "* what purpose? ( lifestyle, sport )")
(assert (use_for (read))))
(reset)
(run)
This is my Jess code for recommending bikes. I don't see anything wrong in the code. I have tried hundreds of times and came to Stack Overflow to get some
help on it.
The code operates as I get budget value and evaluate it by 300, 500 and if the budget range matches I check the purpose of the bike the user is buying. After that using facts I want to send the recommendation message. How can I solve this problem?
This should more or less work except for the typos. I see a number of them, like “tyle” instead of “type”, “user_for” instead of “use_for”, and a stray “<“ before most instances of the number 500. At least the first of these three errors should be reported by Jess when you run this code.
Most of the documentation that exists is available on the Jess website, www.jessrules.com . There are a few YouTube videos if you search for them, and there’s the book “Jess in Action”; it is out of print but it’s not hard to find used copies.

Recursive call in Jess rule engine

I'm trying to implement the transitive closure in Jess.
With
(deftemplate P
(slot id)
(multislot d) ; reference to Ps
)
How can I collect the transitive slot calls : (p::P).d.d.d.d.... until no more d-ref can be taken ?
I thought about
(deffunction closure(?p)
?p1 <- (P (id ?p) (d $?p1d) ; Get the fact which name is given as parameter
?p2 <- (P (id ?id&:(member$ ?id ?p1d)))
(union$ ?p closure( ?p2 ) ) ; Meaning p.d.d.d.d.d.d.d.d.... Tree wise.
)
but it doesn't give anything interesting.
I also thought about using queries, but since the call will be made from a LHS, I've been discouraged from doing so.
Any help would be much appreciated.
Thanks,
Edouard

Reporting JESS's inference

I'm trying to report the inference steps in JESS. For example, I would like to know which rules/facts caused inference engine to fire a certain rule. In order words, I want to see the theorem proving capabilities of JESS.
Here is an example from Wikipedia:
(defrule A ""
(and (X croaks) (X eats flies))
=>
(assert (X is a frog))
)
(defrule B ""
(and (X chirps) (X sings))
=>
(assert (X is a canary))
)
(defrule C ""
(X is a frog)
=>
(assert (X is green))
)
(defrule D ""
(X is a canary)
=>
(assert (X is yellow))
)
If I have the following:
(assert (X croaks))
(assert (X eats flies))
Then when I enter (run) then I will have rule C fired. It seems like, it's fired because of
(X is a frog)
but actually because of
(and (X croaks) (X eats flies))
I am not sure if I'm clear, but I wonder if there is any way that I can show why a certain rules is fired with a comlete inference process.
You'll have to write some Java code, implementing jess.JessListener. You attach an object of this class to the Rete object, using Rete.addJessListener(jess.JessListener). The event you are interesting in is JessEvent.DEFRULE_FIRED, and it'll contain a reference to the activation object, and the rule is available from that.
See the Javadoc for JessListener for some Java code.
You can attach the listener from CLP code, prior to (run).

Call functions in RHS rule in Clips

Is there any way in Clips to create a rule in which the RHS is a Function call?
Yes:
CLIPS> (deffunction foo()
(printout t "The function was called." crlf))
CLIPS> (defrule calls-function
(trigger)
=>
(foo)
)
CLIPS> (reset)
CLIPS> (assert (trigger))
<Fact-1>
CLIPS> (run)
The function was called.
CLIPS>