I want to build an expert system in which in a case of emergency at a building with some floors (ground floor + three floors), the elevator should take the people into the ground. Idea is to save people firstly from the highest one (third floor), and after that from second floor, and at the end from first floor.
I have problem with salience of rules (I have separate rules for each floor). At the beginning the highest salience is for rule "MoveFloor3" - move elevator to third floor (because I want to save firstly people from the highest floor). When I save all people from third floor I want to change salience in this rule to 0 (or some number smaller than salience for second and first floor), because after that I want to save people from second and first floor.
Code for this rule is bellow, how to modify this code in order to change salience after the number of people on this floor becomes 0.
(defrule moveFloor3
(declare (salience 50))
?j<-(lastJob ?t&~moveFloor3)
?e<-(elevator ?peopleInElevator)
?f<-(floor3 ?peopleInFloor)
(capacityElevator ?capacityElevator)
=>
(bind ?newPeopleInElevator (+ ?peopleInElevator (min ?peopleInFloor (- ?capacityElevator ?peopleInElevator))))
(bind ?newPeopleInFloor (- ?peopleInFloor (min ?peopleInFloor (- ?capacityElevator ?peopleInElevator))))
(retract ?e ?f ?s ?j)
(assert (elevator ?newPeopleInElevator))
(assert (floor3 ?newPeopleInFloor))
(assert (lastJob moveFloor3))
(printout t "Elevator moved to third floor" crlf)
)
Here's an alternate solution that handles any number of floors with just two rules and does not require the use of salience:
CLIPS (6.31 6/12/19)
CLIPS>
(deftemplate floor
(slot #)
(slot people))
CLIPS>
(deftemplate elevator
(slot capacity)
(slot occupants))
CLIPS>
(deffacts initial
(elevator (capacity 8)
(occupants 0))
(floor (# ground) (people 0))
(floor (# 1) (people 4))
(floor (# 2) (people 8))
(floor (# 3) (people 13)))
CLIPS>
(defrule pick-up-people
;; The elevator is not full
?e <- (elevator (capacity ?c)
(occupants ?o&~?c))
;; There's a floor with people on it
?f <- (floor (# ?f1&~ground) (people ?p&~0))
;; There's not a higher floor with people
(not (floor (# ?f2&~ground&:(> ?f2 ?f1)) (people ~0)))
=>
;; The number of people that can enter the elevator is
;; the minimum of the remaining occupancy of the elevator
;; and the number of people on the floor
(bind ?added-people (min (- ?c ?o) ?p))
;; Print a message
(printout t "Elevator moves to floor " ?f1
" and picks up " ?added-people " "
(if (= ?added-people 1) then person else people)
crlf)
;; Update the number of people in the elevator and on the floor
(modify ?e (occupants (+ ?o ?added-people)))
(modify ?f (people (- ?p ?added-people))))
CLIPS>
(defrule drop-off-people
;; Determine the number of people on the ground floor
?f <- (floor (# ground) (people ?p))
;; There must be people in the elevator
?e <- (elevator (occupants ?o&~0)
(capacity ?c))
;; There are no remaining people on any of the floors
;; or the elevator is at full occupancy
(or (not (floor (# ~ground) (people ~0)))
(test (= ?c ?o)))
=>
;; Print a message
(printout t "Elevator moves to ground floor and drops off "
?o " " (if (= ?o 1) then person else people) crlf)
;; Update the number of people on the ground floor and
;; in the elevator
(modify ?f (people (+ ?o ?p)))
(modify ?e (occupants 0)))
CLIPS> (reset)
CLIPS> (run)
Elevator moves to floor 3 and picks up 8 people
Elevator moves to ground floor and drops off 8 people
Elevator moves to floor 3 and picks up 5 people
Elevator moves to floor 2 and picks up 3 people
Elevator moves to ground floor and drops off 8 people
Elevator moves to floor 2 and picks up 5 people
Elevator moves to floor 1 and picks up 3 people
Elevator moves to ground floor and drops off 8 people
Elevator moves to floor 1 and picks up 1 person
Elevator moves to ground floor and drops off 1 person
CLIPS>
Use a global variable for setting the salience, which can be changed in the RHS of the rule once it has fired. Also see Using variables in salience declaration in a rule definition
If someone has same problem - this was my solution and it is working!
**(defglobal ?*floor3* = 0)**
(defrule moveFloor3
**(declare (salience (+ ?*floor3* 40)))**
?j<-(lastJob ?t&~moveFloor3)
?e<-(elevator ?peopleInElevator)
?f<-(floor3 ?peopleInFloor)
(capacityElevator ?capacityElevator)
=>
(if (eq ?peopleInFloor 0)
then
**(bind ?*floor3* -40)**
else
(bind ?newPeopleInElevator (+ ?peopleInElevator (min ?peopleInFloor (- ?capacityElevator ?peopleInElevator))))
(bind ?newPeopleInFloor (- ?peopleInFloor (min ?peopleInFloor (- ?capacityElevator ?peopleInElevator))))
(retract ?e ?f ?j)
(assert (elevator ?newPeopleInElevator))
(assert (floor3 ?newPeopleInFloor))
(assert (lastJob moveFloor3))
(printout t "Elevator moved to third floor" crlf)
)
)
Related
How do I translate the loop part of this working Common Lisp (SBCL v.1.2.3) code into Clojure (v.1.6)? I am a bit frustrated after working on it for some hours/days without results. Somewhere I don't get this functional orientation I suppose ...
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Unconditional Entropy
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Probabilities
(setq list_occur_prob '()) ;; init
;; set probabilities for which we want to calculate the entropy
(setq list_occur_prob '(1/2 1/3 1/6)) ;;
;; Function to calculate the unconditional
;; entropy H = -sigma i=0,n (pi*log2(pi)
;; bits persymbol.
(setq entropy 0) ;; init
(setq entropy (loop for i in list_occur_prob
for y = (* (log_base2 i) i)
collect y
))
(setq entropy (* -1 (apply '+ entropy))) ;; change the sign
;; Print the unconditional entropy in bits per symbol.
(print entropy) ;; BTW, here the entropy is 1.4591479 bits per symbol.
Before we dive into the Clojure equivalent of the code, you should take some time to clean up the Common Lisp code. Using setqthe way you're doing it is considered bad style at best and can lead to undefined consequences at worst: setq is intended to assign values to variables, but your variables list_occur_proband entropy aren't defined (via defvar). In addition, this piece of code looks like you're assigning global variables (cf. defvar again), which are dynamic variables, which by convention should be marked with earmuffs, e.g. *entropy*.
However, for this small piece of code, you could just as well use local, non-dynamic variables, introduced via let like this (warning, I don't have any CL or Clojure environment handy):
(let ((list_occur_prob '(1/2 1/3 1/6)))
(loop for i in list_occur_prob
for y = (* (log_base 2 i) i)
collect y into acc
finally (return (* -1 (apply '+ acc)))))
There are ways to optimize the apply clause away into the loop:
(let ((list-occur-prob '(1/2 1/3 1/6)))
(- (loop for i in list-occur-prob
sum (* (log i 2) i))))
Now, Daniel Neal has shown you already a map/reduce based solution, here is one which is more closer to the original looping construct, using a recursive approach:
(defn ent-helper [probs acc]
(if (seq probs)
(recur (rest probs)
(conj acc (* (log_base 2 (first probs)) (first probs))))
acc))
(let [probs 1/2 1/3 1/6
acc (ent-helper probs [])]
(* -1 (apply + acc))
We're using conj instead of collect to gather the results into the accumulator. The call to ent-helper, which is essentially triggered for all values of probs via the recur recursion call, takes an (initially empty) second parameter in which the values build up so far are collected. If we've exhausted all probabilities, we simply return the collected values.
Again, summing up the values so far could be optimized into the loop, instead of mapping over the values.
They key operation you need is map which transforms a sequence using a function.
In the entropy example you gave, the following should work:
(def probabilities [1/2 1/3 1/6])
(defn log [base x]
(/ (Math/log x) (Math/log base)))
(defn entropy [probabilities]
(->> probabilities
(map #(* (log 2 %) %)) ; note - #(f %) is shorthand for (fn [x] (f x))
(reduce +)
(-)))
(entropy probabilities) ; => 1.459
When working with collections, the pipeline operator (->>) is often used
to clearly show a sequence of operations. I personally find it much easier to read than the nested bracket syntax, especially if there are lots of operations.
Here, we're first mapping the pi * log2(pi) function over the sequence,
and then summing it using (reduce +)
I would start with more functional Common Lisp code:
(- (reduce #'+
'(1/2 1/3 1/6)
:key (lambda (i)
(* (log i 2) i))))
You can write imperative code in Lisp, with lots of operations setting variable values, but it is not the best style.
Even a tight LOOP can look okay:
(- (loop for i in '(1/2 1/3 1/6)
sum (* (log i 2) i)))
I endorse the general flavor of schaueho's answer, but if you prefer you can get something closer to the "feel" of the looping approach with Clojure's for macro:
(apply - 0
(for [prob [1/2 1/3 1/6]]
(* (log prob 2) prob)))
I find this much easier to read than schaueho's version with manual recursion, and it also performs much better, in that it doesn't traverse the list twice, doesn't accumulate results into a temporary vector, and so on.
Note that (- (apply + xs)) is the same as (apply - 0 xs), although which one you find clearer is probably a matter of taste. Also, I'm assuming you already have a suitable log function defined elsewhere.
set-difference works as a filter function, but only for lists. What's about arrays and strings? Are there analogous functions for these types of data? If there are no such functions, what is the proper way to implement them?
For now I use this macro to process any sequence as a list (sometimes it's useful):
(defmacro treat-as-lists (vars &body body)
(let ((type (gensym)))
`(let ((,type (etypecase ,(car vars)
(string 'string)
(vector 'vector)
(list 'list)))
,#(mapcar (lambda (x) `(,x (coerce ,x 'list)))
vars))
(coerce (progn ,#body) ,type))))
My filter:
(defun filter (what where &key key (test #'eql))
(treat-as-lists (what where)
(set-difference where what :key key :test test)))
Examples:
CL-USER> (filter "cat" "can you take this cat away?")
"n you ke his wy?"
CL-USER> (filter #(0 1) #(1 5 0 1 9 8 3 0))
#(5 9 8 3)
Since writing functions that works on all sequences types often means writing separate versions for lists and vectors, it's worthwhile to use standard functions that operate on sequences where you can. In this case, we can use position and remove-if. I've reversed the order of your arguments, in order to make this sequence-difference more like set-difference where the second argument is subtracted from the first.
(defun sequence-difference (seq1 seq2 &key (start1 0) end1 (start2 0) end2
key (key1 key) (key2 key)
test test-not)
"Returns a new sequence of the same type of seq1 that contains the
elements of the subsequence of seq1 designated by start1 and end1, and
in the same order, except for those that appear in the subsequence of
seq2 designated by start2 and end2. Test and test-not are used in the
usual way to elements produced by applying key1 (which defaults to
key) to elements from seq1 and by applying key2 (which defaults to
key) to elements from seq2."
(flet ((in-seq2 (x)
(not (null (position x seq2
:start start2 :end end2
:key key2
:test test :test-not test-not)))))
(remove-if #'in-seq2
(subseq seq1 start1 end1)
:key key1)))
(sequence-difference "can you take this cat away?" #(#\c #\a #\t))
;=> "n you ke his wy?"
(sequence-difference "can you take this cat away?" #(#\c #\a #\t) :start1 3 :start2 1)
" you ke his c wy?"
Note that the standard also includes find, which works on arbitrary sequences, but find returns "an element of the sequence, or nil." This leads to ambiguity if nil is a member of the sequence. Position, on the other hand, returns either an index (which will be a number, and thus not nil) or null, so we can reliably determine whether an element is a in sequence.
There is one important difference here in that you're always getting a copy back here. The reason for that is subjective: Since sequence functions often take start and end index arguments, it's nice to include that functionality here. But, if we ask for (sequence-difference "foobar" "boa" :start1 2) then we want to remove the characters b, o, and a from the "foobar"'s subsequence "obar". What should we return though? "for" or "r"? That is, do we include the portion of seq1 that's outside the indices? In this solution, I've made the decision not to, and thus I'm doing (remove-if … (subseq seq1 …) …), and subseq always makes a copy. Set-difference, on the other hand, may return its list-1 or list-2 argument, if appropriate. This implementation generally won't return seq1 or seq2, except in some pathological cases (e.g., the empty list).
This Clojure code outputs 32 while I expect 100. Why is it so? What is a good way to make a loop with counter?
(def t 0)
(for [i (range 100)]
(def t (+ 1 t))
)
(println t)
for evaluates to a lazy sequence. Due to something called chunking, you are getting lucky here and for is being chunked into 32-element lazy partitions.
The code in your question is extremely non-idiomatic.
In your case you could just call (println 100)
If you want to loop over a sequence for some side-effects then you can use doseq
(doseq [i (range 100)]
(println i))
;; or
(dotimes [i 100]
(println i))
a few notes:
for in clojure is lazy, meaning it returns back a lazy seq. because lazy seqs in clojure are chunked, what you are seeing is the evaluation of the first chunk.
You generally dont want to have side-effects when working with for or map (because of their lazyness). In order to avoid that you should use doseq or at least doall.
You also dont want to def inside a function, that's not the proper way to do things in clojure. you should either use a more functional way, or (if appropriate) one of clojure's state constructs (such as atoms or agents)
here is a more idiomatic way to get what you want:
; a more functional way
(def t (reduce + (take 100 (repeat 1))))
(println t)
; a more "stateful" approach
(def t (atom 0))
(doseq [i (range 100)]
(swap! t inc))
(println #t)
I'm learning Clojure and I've just started on Project Euler and I've run into a problem I cannot figure out. Here is my code:
(defn largest_prime_factor
[x]
(if (prime? x) x)
(loop [running x divider 2]
(if (= 0 (mod running divider))
(let [d (/ running divider)]
(if (prime? d)
d
(recur d 2)))
(recur x (inc divider)))))
(largest_prime_factor 12) ;works
(largest_prime_factor 49) ;works
(largest_prime_factor 147) ;Endless loop!
I realise that this might not be the most efficient way to find the largest prime factor but what I'm trying to figure out is why it gets stuck in a loop. Obviously I'm using loop-recur the wrong way but what am I doing wrong?
A couple of things
(defn largest_prime_factor
[x]
(if (prime? x) x) ; #1
(loop [running x divider 2]
(if (= 0 (mod running divider))
(let [d (/ running divider)]
(if (prime? d)
d
(recur d 2)))
(recur x (inc divider))))) ; #2
The extra closing parenthesis makes this a self-contained if without an else clause. This has no bearing on the infinite loop, but would give the wrong answer (1) for a prime input (unless you start your divider at 1 instead, in which case you can omit this initial test).
This line should recur with running rather than x, otherwise you have not factored out the divisor and the prime? test will ever after be false. This is why you wind up in an infinite loop.
(if (prime? x) x)
I think you mean
(if (prime? x) x
(loop [...
I am stuck in a Clojure loop and need help to get out.
I first want to define a vector
(def lawl [1 2 3 4 5])
I do
(get lawl 0)
And get "1" in return. Now, I want a loop that get each number in the vector, so I do:
(loop [i 0]
(if (< i (count lawl))
(get lawl i)
(recur (inc i))))
In my mind this is supposed to set the value of i to nil, then if i is lower then the count of the lawl vector, it should get each lawl value and then increase the i variable with 1 and try again, getting the next value in the vector.
However, this does not work and I have spent some time trying to get it working and are totally stuck, would appreciate some help. I have also tried changing "if" to "when" with the same result, it doesn't provide any data the REPL just enters a new line and blink.
EDIT: Fixed the recur.
You need to consider what is "to get each lawl value" supposed to mean. Your get call does indeed "get" the appropriate value, but since you never do anything with it, it is simply discarded; Bozhidar's suggestion to add a println is a good one and will allow you to see that the loop does indeed access all the elements of lawl (just replace (get ...) with (println (get ...)), after fixing the (inc) => (inc i) thing Bozhidar mentioned also).
That said, if you simply want to do something with each number in turn, loop / recur is not a good way to go about it at all. Here are some others:
;;; do some side-effecty thing to each number in turn:
(dotimes [i (count lawl)]
(println (str i ": " (lawl i)))) ; you don't really need the get either
;; doseq is more general than dotimes, but doesn't give you equally immediate
;; acess to the index
(doseq [n lawl]
(println n))
;;; transform the lawl vector somehow and return the result:
; produce a seq of the elements of lawl transformed by some function
(map inc lawl)
; or if you want the result to be a vector too...
(vec (map inc lawl))
; produce a seq of the even members of lawl multiplied by 3
(for [n lawl
:when (even? n)]
(* n 3))
This is just the beginning. For a good tour around Clojure's standard library, see the Clojure -- Functional Programming for the JVM article by Mark Volkmann.
(recur (inc)) should be (recur (inc i))
Even so this code will just return 1 in the end, if you want a listing of the number you might add a print expression :-) Btw index based loops are not needed at all in scenarios such as this.
(loop [list [1 2 3 4 5] ]
(if (empty? list)
(println "done")
(do
(println (first list))
(recur (rest list)))))
OK, I'm about 10-1/2 years too late on this, but here goes:
The problem here is a pretty common misunderstanding of how the arguments to the if function are used. if takes three arguments - the condition/predicate, the code to be executed if the predicate is true, and the code to be executed if the predicate is false. In this case both of the true and false cases are supplied. Perhaps if we fix the indentation and add some appropriate comments we'll be able to see what's happening more easily:
(loop [i 0]
(if (< i (count lawl))
(get lawl i) ; then
(recur (inc i)))) ; else
So the problem is not that the code gets "stuck" in the loop - the problem is that the recur form is never executed. Here's how the execution flows:
The loop form is entered; i is set to 0.
The if form is entered.
The predicate form is executed and found to be true.
The code for the then branch of the if is executed, returning 1.
Execution then falls out the bottom of the loop form.
Right now I hear people screaming "Wait! WHAT?!?". Yep - in an if form you can only have a single form in the "then" and "else" branches. "But...THAT'S STUPID!" I hear you say. Well...not really. You just need to know how to work with it. There's a way to group multiple forms together in Clojure into a single form, and that's done by using do. If we want to group (get lawl i) and (recur... together we could write it as
(loop [i 0]
(if (< i (count lawl))
(do
(get lawl i) ; then
(recur (inc i))
)
)
)
As you can see, we have no "else" branch on this if form - instead, the (get... and (recur... forms are grouped together by the (do, so they execute one after the other. So after recurring its way through the lawl vector the above snippet returns nil, which is kind of ugly. So let's have it return something more informative:
(loop [i 0]
(if (< i (count lawl))
(do
(get lawl i) ; then
(recur (inc i)))
(str "All done i=" i) ; else
)
)
Now our else branch returns "All done i=5".