is it possible to use the result of a defquery by a defrule? - jess

i'm moving along in jess. the problem that i'm using jess for is to allocate docks
to members based on a set of rules. the process starts when a dock is put in the
pool of available docks. the list of available docks is then compared to the
dock request list. i did this part using a defquery. for simplicity i have just
one available dock with 2 members requesting it. at this point i would like to
start to apply the rules to the result of the query.
i have successfully tested the defquery and the defrule - separately, but don't
understand how to have the rule act on the defquery result.
is it possible?
i have included the defrule and defquery below
duetto
(defglobal ?*curSlip* = nil ?*cand* = nil)
(deftemplate bid
(slot person)
(slot slipRequestedID)
(slot boatID))
(deftemplate slip
(slot slipID)
(slot slength)
(slot swidth)
(slot sdepth))
(deftemplate person
(slot name)
(slot bycseniority)
(slot boatID)
(slot currentSlip))
(deffacts members
(person (name John)(bycseniority 34)(boatID GEM)(currentSlip A8))
(person (name Joe)(bycseniority 50)(boatID MS#$)(currentSlip B9))
(person (name Frank)(bycseniority 120)(boatID DoryO)(currentSlip B8)))
(deffacts bids
(bid (person John) (slipRequestedID A13) (boatID GEM))
(bid (person Joe) (slipRequestedID A13) (boatID FarNiente))
(bid (person Frank) (slipRequestedID B9) (boatID DoryO)))
(deffacts freeSlips
(slip (slipID A13)))
(defrule mostSenior
(person (name ?name) (bycseniority ?senior))
(not (person (name ~?name) (bycseniority ?bycmem&:(< ?bycmem ?senior))))
=>
(bind ?*cand* ?name)
(printout t ?*cand* " is the most senior." crlf))
(defquery bidLookup
(declare (variables ?slipID))
(bid (person ?pers) (slipRequestedID ?slipID)))
(reset)
(bind ?collOfBids (run-query* bidLookup A13))
(while (?collOfBids next)
(printout t (?collOfBids getString pers) crlf)
)

You are leaving the rule-based approach after locating the most senior person. The fact(s) you need for assigning (or denying) a slot request to the most senior person are already in working-memory. Therefore, running a query doesn't yield any new information.
You could add conditions to the mostSenior rule, first establishing that the most senior person has made a bid (any bids) and, second, that the requested slip has a matching slip. If this rule fires, you have the first allocation (and may remove a bid and a slip).
You'll need to consider what happens when the most senior member isn't requesting anything: perhaps write another rule to remove him from WM. Also, a bid of the most senior member may not have a match, and you may have to remove that to make the "senior-has-no-bids" rule to fire.
Don't worry about duplicating conditions in different rules. The engine is built to deal efficiently with this.

Related

Common Lisp: Is there a version of `labels` with a type specifier?

Is there a Common Lisp construct that is to labels what defmethod is to defun? That is, I would like to use labels (or something similar) to define several local functions that would have the same name but differ in parameters they accept and let the compiler choose among them.
As an MWE, I would like to achieve the following functionality
(defmethod write-first-item-type ((lst list))
"Writes the type of the first item in lst."
(labels ((write-single ()
(format t "a single float"))
(write-double ()
(format t "a double float")))
(format t "The first item is: ~A.~%"
(cond ((eql (type-of (car lst)) 'single-float)
(write-single))
((eql (type-of (car lst)) 'double-float)
(write-double))
(t
(format t "unknown"))))))
with something like
(defmethod write-first-item-type ((lst list))
"Should write the type of the first item in lst but does not compile."
(label-method ((write-type ((item single-float))
(format t "a single float"))
(write-type ((ifem double-float))
(format t "a double float")))
(format t "The first item is: ~A.~%"
(write-type (car lst)))))
Admitably, my MWE is rather silly. My actual motivation is that while cleaning up my source code I would like to put bunches of little helper functions (created with defmethod) into the one big function that uses them. Feel free to comment on this motivation as well!
See here why the initial proposal for local generic bindings were removed from CLOS:
Issue GENERIC-FLET-POORLY-DESIGNED Writeup
I am not aware of a built-in functionality of that kind. However, such kind of feature is not hard to build from scratch, as long as other parts of OOP are not required (i.e., inheritance and other dispatching orders).
If you would never call (call-next-method) in you method-labels code (as you won't do in labels code, it is just a matter of defining a dispatch table and dispatch "methods" accordingly. To break it down, it should be a local macro that:
defines a local variable (gensym) as the dispatch table;
registers functions as closures together with its specialized lambda list into the dispatch table;
register a local "generic" function, that when called, find the function to call from the dispatch table according to the parameters supplied.
And to find the function, you may or may not need to:
sort the dispatch table (but if there is not eql specifier nor inheritance, this can be avoided)
write dedicated code to match against the specialized parameters for &optional, &key, and other options of the lambda list (or you can use destructuring-bind, but you'll need to transform the specialized lambda list into a lambda list) - there might be tools for that, but I am unaware of.
In the simplest case where the number of parameters in the lambda list is fixed, the dispatch can be as plain as a few (e)typecase.
The local/global methods are for you probably a matter of namespaces.
That you don't want to pollute the current namespace with this matter.
How about to create on-the-fly small namespace/packages and use therein the "global" methods of CLOS?
It would have nearly the same effect of having local functions which are "invisible" for other functions.
(defpackage my-sub
(:use :cl)
(:export #:write-type))
(in-package :my-sub)
(defgeneric write-type (x)
(:documentation "write type of x"))
(defmethod write-type ((x float))
(typecase x
(single-float "single float")
(double-float "double float")))
(defmethod write-type ((x string))
"string")
(defpackage my-main
(:use :cl
:my-sub))
(in-package :my-main)
(defmethod write-first-item-type ((lst list))
(format nil "first item is: ~A." (my-sub:write-type (car lst))))
(write-first-item-type '("a" b c))
;; "first item is: string."
(write-first-item-type '(1.0 2 3))
;; "first item is: single float."
(write-first-item-type '(1.0d0 2 3))
;; "first item is: double float."
defmethod anyway can only dispatch for classes - builtin or self-made.
But you want to dispatch for types.
So I put example for members of class float (single-float and double-float) - dispatch them manually useing typecase.
And of built-in class string.
Use packaging for namespace separation.
However just manual dispatch is better in this case.
(defmethod write-first-item-type ((lst list))
(labels ((write-type (x)
(typecase x
(single-float "single float")
(double-float "double float")
(string "string")
(t "unkown"))))
(format nil "The first item is: ~A." (write-type (car lst)))))

JessTab in Protege

I'm using Jess with Protege, I created a def template Person with the slots (name, age and adress), and I created another def template which extends the first one with the additional slot (sex), now I want to delete the first one and replace it by the new one, and I don't want to lose instances, I want the instances of the first one to be extended by the second, how can I do it ?
thank you
i tried first to modify the structure of the def template with the function "replace$", but it doesn't work, then I tried the function "modify" but it just modifies the value of a slot
(deftemplate Person (slot name(type string)) (slot age(type integer)) (slot adress(type string)))
(deftemplate Personne (slot name(type string)) (slot age(type integer)) (slot adress(type string)) (slot sexe (type string) ))
(assert( Person (name "Bryan") (age "25") (adress "New York")))
(assert( Person (name "Omar") (age "35") (adress "Algeria")))
(assert( Person (name "Sara") (age "30") (adress "Moroco")))
When I tried to use the function "replace$" into a rule, I had no syntaxique error, the syntax is correct, but when I do (run) it does not work, no rule is executed.
There’s no way to change the instances themselves during a single run of the program. But you could save them to a file, edit the file, and load them back in.

Compare value of a nested java bean

I am trying my hands with JESS wherein I want to write a rule as following.
When order amount is greater than 1000 and customer is preferred and customer name matches to order name then do something.
My Order.java has following properties
int amount, Customer cust
And Customer.java is a plain bean class holding following properties.
string name, string address
I am not able to find a way wherein I can get the value of Order.cust.name and compare with Customer.name in JESS.
Can anyone help me here please?
I tried using following but not working out for me.
(defrule HelloCustomer "When customer is preferred and amount is greater than 1001"
?person1 <- (Customer)
?cust <- (Customer {isPreferred == true})
?o <- (Order{amount > (+ 1000 1)})
?person2 <- (Order(customerA))
?person2Name <- (Customer{name == (Order{customerA.name})})
=>
(modify ?o (totalAmount 1000))
(printout t "Found two different " (call ?person2.customerA getName) crlf))
(printout t "Found two different*** " ?person1.name crlf))
You have many of the details right but the fundamentals are mostly wrong. First, note that each “Customer” and “Order” pattern matches a new object; this might match as many as five different objects. Secondly, you’ll need to bind variables to slot values so you can test them in other slots. Lastly, you’ll need to make use of the “OBJECT” slot to retrieve the Java object represented by each of this patterns. Roughly, I think you want something like
(defrule HelloCustomer
(Customer {isPreferred == true} (name ?name) (OBJECT ?customer))
(Order {amount > 1001} (name ?name) (OBJECT ?order)) ;; Repeating variable binds these together
=>
;; do something with ?customer and ?order
The Jess manual covers all of this, but you do have to read the whole thing. After all, you’re learning a whole new programming language.

How to compare java object in jess

I have a problem when I compare java object as attribute inside the java class
This is my clp file
(import Model.*)
(deftemplate PizzaBase
(declare (from-class PizzaBase)
(include-variables TRUE)))
(deftemplate PizzaTopping
(declare (from-class PizzaTopping)
(include-variables TRUE)))
(deftemplate Pizza
(declare (from-class Pizza)
(include-variables TRUE)))
(defrule make-pizza
?pizzaBase1 <-(PizzaBase{size == 9})
(Pizza(pizzaBase ?pizzaBase1))
=>
(add (new PizzaBase "New DeepPan" 10))
)
According from my rule, I want to create a new pizzaBase.When the pizzaBase object in Pizza equal pizzaBase1(size = 9), but JESS is not create a new fact for me.
From my thinking, I think JESS cannot compare the Java object that create from the class.Therefore, There isn't add any fact to JESS.
So,"How to solve this problem?",because I look on the manual on the JESS website but there aren't any title that according my problem.
Thank!
You may have overlooked section 5.3.2., Adding Java objects to working memory.
A Java object isn't the same as a fact, even when you derive a shadow (!) fact from a POJO, using from-class and include-variables. A fact contains a reference to the Java object you insert by calling (add ?aNewObject) in the reserved slot name OBJECT.
Change your rule like this:
(defrule make-pizza
(PizzaBase{size == 9}(OBJECT ?pizzaBase1))
(Pizza(pizzaBase ?pizzaBase1))
=>
(add (new PizzaBase "New DeepPan" 10))
)

Common Lisp: defstruct constructors and (declare (type blahblah blah))?

Let's say I have this:
(defstruct (derp
(:constructor
make-derp
(&key (dimension 4))))
(some-bits (make-array (list dimension dimension)
:element-type 'bit
:initial-element 0)))
I'd like to be able to (declare (type ...) blahblahblah) the 'dimension' parameter. Right now it accepts any value at all. Sure, make-array will error out on 0-or-less, but I also want to declare the type to be within a range, or whatever else I wish to use declare type for.
So anyway, I tried adding (declare (type (integer 1 32) dimension)) to various places in this defstruct, but it always yields a different error.
No luck on a casual Google search of these terms.
Can this be done somehow?
Why would you want to declare it? Why not just check the type?
(defstruct (derp
(:constructor
make-derp (&key (dimension 4))))
(some-bits (progn
(check-type dimension (integer 0 10))
(make-array (list dimension dimension)
:element-type 'bit
:initial-element 0))))
Generally above might not be robust enough. I'd then propose to write a MAKE-SOMETHING function, which does the checking upfront.
Note that you also can declare the type of the slot itself. Some CL will check that under some circumstances.