Find all facts matching a condition in Defrule - clips

I have two type of facts: state1 and state2, both are arrays of numbers. I want to check if a fact with tag 'state' with current value of state2 variable exists. How can I do it?
For example, if now facts are:
State 1 2 3
State2 4 5 6
State 0 8 9,
And current state2 is 1 2 3, I want to get into RHS because first row 'State 1 2 3' matches current value of State2.
I tried following solution, but I never enter RHS.
;;; END FUNCTION, EXECUTES WHEN SOLUTION WAS FOUND
(defrule complete (declare (salience 1000))
(exists (state ?state2))
=> (printout t "Target state [1 2 3 8 0 4 7 6 5] reached" crlf) (halt)
);

CLIPS (6.31 6/12/19)
CLIPS>
(defrule complete
(exists (state $?state)
(state2 $?state))
=>
(printout t "Target state [1 2 3 8 0 4 7 6 5] reached" crlf))
CLIPS>
(assert
(state 1 2 3)
(state2 4 5 6)
(state 0 8 9)
(state2 1 2 3))
<Fact-4>
CLIPS> (agenda)
0 complete: *
For a total of 1 activation.
CLIPS> (run)
Target state [1 2 3 8 0 4 7 6 5] reached
CLIPS>

Related

Why does Clojure (1.8) create a HashMap if I manually create a map with > 8 keys, but an ArrayMap if I use zipmap to create map with > 8 keys?

I know that Clojure switches from PersistentArrayMap to PersistentHashMap when a map is greater than 8 in size (8 key-value pairs). This can be verified by:
(type {0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8})
=> clojure.lang.PersistentHashMap
But if I create the above map using zipmap:
(type (zipmap (range 9) (range 9)))
=> clojure.lang.PersistentArrayMap
I made sure that the construction is correct:
(= (zipmap (range 9) (range 9))
{0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8})
=> true
If I use (range 10), it starts using PersistentHashMap. So for zipmap, the size has to be 9 or greater before it starts using PersistentHashMap.
I found this very weird. Why is there a difference in datastructure depending on whether I create a map manually or with zipmap?
I'm using Clojure 1.8.
This is because zipmap creates the map incrementally using assoc. Because of a bug, assoc switches from ArrayMap to HashMap for size > 9, not for 9.
Look at this:
(type {0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7})
=> clojure.lang.PersistentArrayMap # size = 8
(type (assoc {0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7}
8 8))
=> clojure.lang.PersistentArrayMap # size = 9
(type (assoc {0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7}
8 8 9 9))
=> clojure.lang.PersistentHashMap # size = 10
The bug was fixed here: https://github.com/clojure/clojure/commit/ce9fbf61f113fdef1cbf8c1c0b4ea1a48831beef

How can I stablish a relation between two LHS in clips?

I'm trying to make a clips program in order to solve any Sokoban level but I have a huge problem:
In this example, I only have the initial state of the field and a rule which tries to move the player to the right if there is not a box or an obstacle (in the full program I also have rules which move the boxes). The problem comes when I have a state which matches with the LHS ?ff <- (R ?Ir ?Xr ?Yr $?a B ?Ib ?Xb ?Yb $?b S ?Is ?Xs ?Ys ?Es $?c W ?w D ?d L ?l F ?) and another one, created due to the movement of the boxes, which does not allow the rule (not (R $? B ? =(+ ?Xr 1) ?Yr $?) ) to be true even if the first estate makes it true.
(deffacts InitialState
;------static---------
(MAX_DEPTH 5)
;field
; X Y
(FIELD 8 5)
;obstacle
; X Y
(O 4 1)
(O 1 3)
(O 8 3)
(O 4 3)
(O 5 3)
(O 4 4)
(O 4 5)
;-----dynamic-----
(
;robot
; I X Y
R 1 2 4
;box
; I X Y
B 1 2 2
B 2 3 4
B 3 6 2
;storehouse
; I X Y E
S 1 7 1 0
S 2 5 4 0
S 3 5 5 0
;win
W 0 ;Posibilidad de cambiar la R por W asi paramos la ejec
; depth
D 0
;last move
;0:nothing 1:up 2:right 3:down 4:left
L 0
;father id
F 0
)
)
(defrule move_right_no_box
(MAX_DEPTH ?MD)
(FIELD ?Xf ?Yf)
?ff <- (R ?Ir ?Xr ?Yr $?a B ?Ib ?Xb ?Yb $?b S ?Is ?Xs ?Ys ?Es $?c W ?w D ?d L ?l F ?)
;comprueba que a la derecha no hay un obstacle
(not (O =(+ ?Xr 1) ?Yr) )
;comprueba que a la derecha no hay un box
(not (R $? B ? =(+ ?Xr 1) ?Yr $?) )
=>
(assert (R ?Ir (+ ?Xr 1) ?Yr $?a B ?Ib ?Xb ?Yb $?b S ?Is ?Xs ?Ys ?Es $?c W ?w D (+ ?d 1) L 2 F ?ff))
)
For example, I have a state which do not have a box or an obstacle in the right, but I have another state which does. I need a way to establish a relation between the rules:
?ff <- (R ?Ir ?Xr ?Yr $?a B ?Ib ?Xb ?Yb $?b S ?Is ?Xs ?Ys ?Es $?c W ?w D ?d L ?l F ?) and (not (R $? B ? =(+ ?Xr 1) ?Yr $?) ) in order to make sure that they are referring to the same state (and a different state, which is different from the one that I'm evaluating, is not interfering).
I other words, what I need is a way to make sure that both LHS are evaluating the same state.
Thanks!
PD1: I can't use something like an ID because it makes the execution of the program too slow.
Assert a fact containing information about the state that both rules match.
Okay, at the end I could not found a way to make sure that two LHS are evaluating the same state, so I solved the problem using the 'member' function: https://www.csie.ntu.edu.tw/~sylee/courses/clips/bpg/node12.2.3.html
I can create a LHS rule which always returns True and is composed of multifield variables and then using the member function check if part of the rule satisfies my condition.
Another option (even if I'm not sure this works due to I have not tested it) is to evaluate all the conditions in one LHS using this:
https://www.csie.ntu.edu.tw/~sylee/courses/clips/bpg/node5.4.1.4.html

Generate a random number, excluding a single number

I'm writing a Monty Hall simulator, and found the need to generate a number within a range, excluding a single number.
This seemed easy, so I naively wrote up:
(The g/... functions are part of my personal library. Their use should be fairly clear):
(defn random-int-excluding
"Generates a random number between min-n and max-n; excluding excluding-n.
min-n is inclusive, while max-n is exclusive."
[min-n max-n excluding-n rand-gen]
(let [rand-n (g/random-int min-n max-n rand-gen)
rand-n' (if (= rand-n excluding-n) (inc rand-n) rand-n)]
(g/wrap rand-n' min-n (inc max-n))))
This generates a random number within the range, and if it equals the excluded number, adds one; wrapping if necessary. Of course this ended up giving the number after the excluded number twice the chance of being picked since it would be picked either if it or the excluded number are chosen. Sample output frequencies for a range of 0 to 10 (max exclusive), excluding 2:
([0 0.099882]
[1 0.100355]
[3 0.200025]
[4 0.099912]
[5 0.099672]
[6 0.099976]
[7 0.099539]
[8 0.100222]
[9 0.100417])
Then I read this answer, which seemed much simpler, and based on it, wrote up:
(defn random-int-excluding
"Generates a random number between min-n and max-n; excluding excluding-n.
min-n is inclusive, while max-n is exclusive."
[min-n max-n excluding-n rand-gen]
(let [r1 (g/random-int min-n excluding-n rand-gen)
r2 (g/random-int (inc excluding-n) max-n rand-gen)]
(if (g/random-boolean rand-gen) r1 r2)))
Basically, it splits the range into 2 smaller ranges: from the min to the excluded number, and from excluded number + 1 to the max. It generates random number from these ranges, then randomly chooses one of them. Unfortunately though, as I noted under the answer, this gives skewed results unless both the partitions are of equal size. Sample output frequencies; same conditions as above:
([0 0.2499497]
[1 0.2500795]
[3 0.0715849]
[4 0.071297]
[5 0.0714366]
[6 0.0714362]
[7 0.0712715]
[8 0.0715285]
[9 0.0714161])
Note the numbers part of the smaller range before the excluded number are much more likely. To fix this, I'd have to skew it to pick numbers from the larger range more frequently, and really, I'm not proficient enough in maths in general to understand how to do that.
I looked at the accepted answer from the linked question, but to me, it seems like a version of my first attempt that accepts more than 1 number to exclude. I'd expect, against what the answerer claimed, that the numbers at the end of the exclusion range would be favored, since if a number is chosen that's within the excluded range, it just advances the number past the range.
Since this is going to be one of the most called functions in the simulation, I'd really like to avoid the "brute-force" method of looping while the generated number is excluded since the range will only have 3 numbers, so there's a 1/3 chance that it will need to try again each attempt.
Does anyone know of a simple algorithm to chose a random number from a continuous range, but exclude a single number?
To generate a number in the range [a, b] excluding c, simply generate a number in the range [a, b-1], and if the result is c then output b instead.
Just generate a lazy sequence and filter out items you don't want:
(let [ignore #{4 2}]
(frequencies
(take 2000
(remove ignore (repeatedly #(rand-int 5))))))
Advantage to the other approach of mapping to different new values: This function will also work with different discrete random number distributions.
If the size of the collection of acceptable answers is small, just put all values into a vector and use rand-nth:
http://clojuredocs.org/clojure.core/rand-nth
(def primes [ 2 3 5 7 11 13 17 19] )
(println (rand-nth primes))
(println (rand-nth primes))
(println (rand-nth primes))
~/clj > lein run
19
13
11
Update
If some of the values should include more than the others, just put them in the array of values more than once. The number of occurrances of each value determines its relative weight:
(def samples [ 1 2 2 3 3 3 4 4 4 4 ] )
(def weighted-samples
(repeatedly #(rand-nth samples)))
(println (take 22 weighted-samples))
;=> (3 4 2 4 3 2 2 1 4 4 3 3 3 2 3 4 4 4 2 4 4 4)
If we wanted any number from 1 to 5, but never 3, just do this:
(def samples [ 1 2 4 5 ] )
(def weighted-samples
(repeatedly #(rand-nth samples)))
(println (take 22 weighted-samples))
(1 5 5 5 5 2 2 4 2 5 4 4 5 2 4 4 4 2 1 2 4 1)
Just to show the implementation I wrote, here's what worked for me:
(defn random-int-excluding
"Generates a random number between min-n and max-n; excluding excluding-n.
min-n is inclusive, while max-n is exclusive."
[min-n max-n excluding-n rand-gen]
(let [rand-n (g/random-int min-n (dec max-n) rand-gen)]
(if (= rand-n excluding-n)
(dec max-n)
rand-n)))
Which gives a nice even distribution:
([0 0.111502]
[1 0.110738]
[3 0.111266]
[4 0.110976]
[5 0.111162]
[6 0.111266]
[7 0.111093]
[8 0.110815]
[9 0.111182])
Just to make Alan Malloy's answer explicit:
(defn rand-int-range-excluding [from to without]
(let [n (+ from (rand-int (dec (- to from))))]
(if (= n without)
(dec to)
n)))
(->> #(rand-int-range-excluding 5 10 8)
repeatedly
(take 100)
frequencies)
;{6 28, 9 22, 5 29, 7 21}
No votes required :).

functional forward checking implementation

I would like to implement the forward checking search algorithm in a functional way in scheme. Forward checking search is a depth first search that chooses a variable at each node of a graph, tries all the values in the domain of this variable and recursively calls itself until a variable domain is empty or a solution is found. In pseudo code the algorithm is
bool ForwardChecking ()
if no free variable then
return true
choose a free variable var
for all values in the domain of var
assign value to var
update the domains of the free variables
if no domain is empty or inconsistent then
if (ForwardChecking ()) then
return true
return false
In my particular problem I have a vector where some of the elements have seteq representing the possible values that element can take and other elements have an integer. For example a 6x6 vector is
#(1 (seteq 2 4 6) 5 (seteq 2 3 6) (seteq 2 3 4 6) (seteq 3 4)
(seteq 2 3 4) (seteq 2 4 6) (seteq 2 3 6) (seteq 2 3 6) 1 (seteq 3 4 5)
6 (seteq 1 2 5) (seteq 1 2 3) 4 (seteq 2 3 5) (seteq 1 3 5)
(seteq 2 3 5) (seteq 1 2 5) 4 (seteq 1 2 3) (seteq 2 3 5) 6
(seteq 2 4 5) 3 (seteq 1 2 6) (seteq 1 6) (seteq 4 6) (seteq 1 4)
(seteq 4)(seteq 1 4 6) (seteq 1 6) 5 (seteq 3 4 6) 2)
my goal is to figure out the integer that goes into the elements of the vector with seteq using forward checking.
My incomplete attempt at implementing the algorithm in scheme follows
(find-min-pos is a function that finds the positions of all elements of the vector with the smallest number of integers; vector-update is a function that sets one of those elements to one of the integers in its seteq)
(define (forward-checking vec)
; get list of position of elements of vec with smallest number of
; seteq elements
(define min-free-pos (find-min-pos vec))
(cond
; if no free variable return true
[(empty? min-free-pos) #t]
; pick a random element of min-free-pos
[else
(define free-elem-pos (list-ref min-free-pos (random (length min-free-pos))))
; find the vector element
(define free-elem (board-ref board free-elem-pos))
; loop through all values that free-elem contains
; this is a seteq
(for ([i (in-set free-elem)])
(define vec2 (vector-update vec free-elem-pos i))
; the following is incorrect
(if vec2
if forward-checking vec2)
)
#f]
))
How to complete it? Is there a different (maybe more functional) way of implementing it?

Range data type or generator in Emacs Lisp (elisp)?

What is elisp's equivalent for Python's range(start, end, [step])?
number-sequence is similar to python's range but its output is quite different.
For example:
(number-sequence 5)
=> (5)
(number-sequence 1 5)
=> (1 2 3 4 5)
(number-sequence 1 5 2)
=> (1 3 5)
I use this function to give me an output like that from python's range:
(defun py-range (start &optional end step)
(unless end
(setq end start
start 0))
(number-sequence start (1- end) step))
Now everything works as expected:
(py-range 5)
=> (0 1 2 3 4)
(py-range 1 5)
=> (1 2 3 4)
(py-range 1 5 2)
=> (1 3)
(number-sequence FROM &optional TO INC)

Resources