Can this type of problem be easily expressed in logic programming paradigm? - rule-engine

For simplicity, this is a toy version of the actual problem: given a set of integers, find the longest sequence of consecutive numbers from that set.
I looked at CLIPS and other expert systems, and they seem ill-suited to express this kind of problem. Specifically, I don't see a list like data structure, which seems to be necessary to implement a solution. I'm looking for an example of implementation using logic programming.

One way:
CLIPS (6.4 2/9/21)
CLIPS>
(deffacts start
(set 1 9 2 10 4 3 11 13 5 14))
CLIPS>
(defrule combine-1
?f <- (set $?b ?n $?e)
=>
(retract ?f)
(assert (combine ?n))
(assert (set ?b ?e)))
CLIPS>
(defrule combine-2
?f1 <- (combine $?b ?j1)
?f2 <- (combine ?j2&=(+ ?j1 1) $?e)
=>
(retract ?f1 ?f2)
(assert (combine ?b ?j1 ?j2 ?e)))
CLIPS>
(defrule longest
(declare (salience -10))
(combine $?c)
(not (combine $?o&:(> (length$ ?o) (length$ ?c))))
=>
(println "Longest is " ?c))
CLIPS> (reset)
CLIPS> (run)
Longest is (1 2 3 4 5)
CLIPS> (facts)
f-21 (set)
f-22 (combine 13 14)
f-26 (combine 1 2 3 4 5)
f-28 (combine 9 10 11)
For a total of 4 facts.
CLIPS>
Another way:
CLIPS> (clear)
CLIPS>
(deffacts start
(set 1 9 2 10 4 3 11 13 5 14))
CLIPS>
(defrule sort
?f <- (set $?s)
(test (neq ?s (sort > ?s)))
=>
(retract ?f)
(assert (set (sort > ?s))))
CLIPS>
(deffunction consecutive ($?s)
(loop-for-count (?i (- (length$ ?s) 1))
(if (<> (+ (nth$ ?i ?s) 1) (nth$ (+ ?i 1) ?s))
then (return FALSE)))
(return TRUE))
CLIPS>
(defrule longest
(set $? $?s&:(consecutive $?s) $?)
(not (set $? $?s2&~$?s&:(consecutive $?s2)&:(> (length$ ?s2) (length$ ?s)) $?))
=>
(println "Longest is " ?s))
CLIPS> (reset)
CLIPS> (run)
Longest is (1 2 3 4 5)
CLIPS> (facts)
f-2 (set 1 2 3 4 5 9 10 11 13 14)
For a total of 1 fact.
CLIPS>

Related

Creating a function using DrRacket that takes two lists and outputs it as a fraction

Write a function that takes two lists of numbers, numerators and denominators, and returns a list of fractions produced by dividing numerators by denominators. If one list is shorter than the other, assume that the corresponding numbers are all 1s. Don't worry about zeros in the denominators (it's ok if your function breaks when dividing by zero).
Input: (list 1 2 3) (list 1 3 5)
Output: (list 1/1 2/3 3/5)
You can solve it by recursion:
(define (r-map func l1 l2 (default-l1 1) (default-l2 1) (acc '()))
(cond ((and (null? l1) (null? l2)) (reverse acc))
((null? l1) (r-map func '() (cdr l2) default-l1 default-l2 (cons (func default-l1 (car l2)) acc)))
((null? l2) (r-map func (cdr l1) '() default-l1 default-l2 (cons (func (car l1) default-l2) acc)))
(else (r-map func (cdr l1) (cdr l2) default-l1 default-l2 (cons (func (car l1) (car l2)) acc)))))
The nice thing with this function is that you can change the default value for each list independently from each other.
Test it:
(define a '(1 2 3))
(define b '(4 5 6))
(define c '(10 20))
(define d '(40 50 60 70))
;; run all combinations of the four:
(let ((lists (list a b c d)))
(for*/list [(x lists)
(y lists)]
(list `(r-map ,x ,y ,default-l1 ,default-l2) '=> (r-map / x y))))
It returns:
Welcome to DrRacket, version 6.11 [3m].
Language: racket, with debugging; memory limit: 128 MB.
'(((r-map (1 2 3) (1 2 3) 1 1) => (1 1 1))
((r-map (1 2 3) (4 5 6) 1 1) => (1/4 2/5 1/2))
((r-map (1 2 3) (10 20) 1 1) => (1/10 1/10 3))
((r-map (1 2 3) (40 50 60 70) 1 1) => (1/40 1/25 1/20 1/70))
((r-map (4 5 6) (1 2 3) 1 1) => (4 2 1/2 2))
((r-map (4 5 6) (4 5 6) 1 1) => (1 1 1))
((r-map (4 5 6) (10 20) 1 1) => (2/5 1/4 6))
((r-map (4 5 6) (40 50 60 70) 1 1) => (1/10 1/10 1/10 1/70))
((r-map (10 20) (1 2 3) 1 1) => (10 10 1/3))
((r-map (10 20) (4 5 6) 1 1) => (2 1/2 4 1/6))
((r-map (10 20) (10 20) 1 1) => (1 1))
((r-map (10 20) (40 50 60 70) 1 1) => (1/4 2/5 1/60 1/70))
((r-map (40 50 60 70) (1 2 3) 1 1) => (40 25 20 70))
((r-map (40 50 60 70) (4 5 6) 1 1) => (10 10 10 70))
((r-map (40 50 60 70) (10 20) 1 1) => (4 2 1/2 60 70))
((r-map (40 50 60 70) (40 50 60 70) 1 1) => (1 1 1 1)))
Let's do this a bit more straightforwardly.
There are two simple cases:
Both lists are empty; the result is '()
Neither list is empty; cons the fraction of the cars onto the result of recursing.
Short-circuiting out the tricky cases:
(define (fractions ns ds)
(cond [(and (null? ns) (null? ds)) '()]
[(null? ns) 'only-denominators]
[(null? ds) 'only-numerators]
[else (cons (/ (car ns) (car ds)) (fractions (cdr ns) (cdr ds)))]))
Test:
> (fractions '() '())
'()
> (fractions '(1 2) '(4 5))
'(1/4 2/5)
> (fractions '(1 2 3) '(4 5))
'(1/4 2/5 . only-numerators)
> (fractions '(1 2) '(4 5 6))
'(1/4 2/5 . only-denominators)
If there are only numerators, the results are the same as those numerators, since x/1 is the same as x:
...
[(null? ds) ns]
...
And if there are only denominators, you divide 1 with each element.
This is easy with map:
...
[(null? ns) (map (lambda (d) (/ 1 d)) ds)]
...
In full:
(define (fractions ns ds)
(cond [(and (null? ns) (null? ds)) '()]
[(null? ns) (map (lambda (d) (/ 1 d)) ds)]
[(null? ds) ns]
[else (cons (/ (car ns) (car ds)) (fractions (cdr ns) (cdr ds)))]))
Test:
> (fractions '() '(4 5 6))
'(1/4 1/5 1/6)
> (fractions '(1 2 3) '())
'(1 2 3)
> (fractions '(1 2 3) '(4 5))
'(1/4 2/5 3)
> (fractions '(1 2) '(4 5 6))
'(1/4 2/5 1/6)

Maximum and minimum numbers in the list

I am using DrRacket.
How can I write a function for the difference between the maximum and minimum number in the list using accumulators and mutually recursive functions.
For instance, (list 10 2 3 -5 4 1 -6)) 9). The list has at least one element in the list.
Do I need two accumulators?
Version 1: An accumulator based solution that's mutually recursive. Since the input list is assumed to be non-empty, we start of with the first element being max and min. As we go through the list, we pick new max and mins by comparing the current element with the accumulators.
#lang racket
; [NEList-of Number] -> Number
(define (max-min-diff.v1 nelst)
(max-min-diff/t.v1 (rest nelst) (first nelst) (first nelst)))
; [List-of Number] -> Number
(define (max-min-diff/t.v1 l max min)
(cond [(empty? l) (- max min)]
[else (get-new-max-min (rest l) (first l) max min)]))
; [List-of Number] Number Number Number -> Number
(define (get-new-max-min rst fst max min)
(max-min-diff/t.v1 rst
(if (> fst max) fst max)
(if (< fst min) fst min)))
(max-min-diff.v1 '(0 33 2 32 4 8 3 3 5))
; => 33
(max-min-diff.v1'(1 3 9 4 7 2 2 5 11))
; => 10
Version 2: An accumulator based solution that's not mutually recursive. More abstract because we pass the comparators to a generic helper.
; [NEList-of Number] -> Number
(define (max-min-diff.v2 nelst)
(max-min-diff/t.v2 (rest nelst) (first nelst) (first nelst)))
; [List-of Number] -> Number
(define (max-min-diff/t.v2 l max min)
(cond [(empty? l) (- max min)]
[else (max-min-diff/t.v2 (rest l)
(f-if (first l) max >)
(f-if (first l) min <))]))
; X X [X X -> Boolean] -> X
(define (f-if n1 n2 func)
(if (func n1 n2) n1 n2))
(max-min-diff.v2 (list 0 33 2 32 4 8 3 3 5))
; => 33
(max-min-diff.v2 (list 1 3 9 4 7 2 2 5 11))
; => 10
Version 3: Small version. No explicit recursion.
(define (max-min-diff.v3 nelst)
(- (apply max nelst) (apply min nelst)))
(max-min-diff.v3 (list 0 33 2 32 4 8 3 3 5))
; => 33
(max-min-diff.v3 (list 1 3 9 4 7 2 2 5 11))
; => 10

how to can get values in facts in clips?

how to can get values in facts in clips?
CLIPS> (assert(rule1 (read)))
4
==> f-1 (rule1 1)
I want the fact 1 is stored in a variable and do calculations.
In this example, I want to return a value of ' 4 '.
CLIPS> (watch facts)
CLIPS> (assert (rule1 (read)))
4
==> f-1 (rule1 4)
<Fact-1>
CLIPS>
(defrule double
(rule1 ?v)
=>
(printout t "Twice the value is " (* 2 ?v) crlf))
CLIPS> (agenda)
0 double: f-1
For a total of 1 activation.
CLIPS> (run)
Twice the value is 8
CLIPS>

How to print a list as matrix in Common Lisp

I am working in Common Lisp, trying to make Windows game minesweeper.
I have a list (1 1 1 2 2 2 3 3 3) and want to print that like matrix
(1 1 1
2 2 2
3 3 3)
How to do that?
Edit
I am at the beginning of
(format t "Input width:")
(setf width (read))
(format t "Input height:")
(setf height (read))
(format t "How many mines:")
(setf brMina (read))
(defun matrica (i j)
(cond ((= 0 i) '())
(t (append (vrsta j) (matrica (1- i) j) ))))
(setf minefield (matrica width height))
(defun stampaj ()
(format t "~%~a" minefield ))
Another example, using the pretty-printer for fun:
(defun print-list-as-matrix
(list elements-per-row
&optional (cell-width (1+ (truncate (log (apply #'max list) 10)))))
(let ((*print-right-margin* (* elements-per-row (1+ cell-width)))
(*print-miser-width* nil)
(*print-pretty* t)
(format-string (format nil "~~<~~#{~~~ad~~^ ~~}~~#:>~%" cell-width)))
(format t format-string list)))
Works like this:
CL-USER> (print-list-as-matrix (loop for i from 1 to 9 collect i) 3)
1 2 3
4 5 6
7 8 9
NIL
CL-USER> (print-list-as-matrix (loop for i from 1 to 25 collect i) 5)
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
NIL
CL-USER> (print-list-as-matrix (loop for i from 1 to 16 collect i) 2)
1 2
3 4
5 6
7 8
9 10
11 12
13 14
15 16
Like this:
(defun print-list-as-grid (list rows cols)
(assert (= (length list) (* rows cols))
(loop for row from 0 below rows do
(loop for col from 0 below cols do
(princ (car list))
(princ #\space)
(setf list (cdr list)))
(princ #\newline)))
* (print-list-as-grid '(a b c d e f g h i) 3 3)
A B C
D E F
G H I
NIL

defining a starting point for dolist

Is it possible to tell dolist to start at (or even better after) a certain element in the given list? As I may not want to evaluate all the elements before.
If there is no way to do so, is there any other macro which might do the job?
Considering this example:
(defvar *liste* #(1 2 3 4 5 6))
(dolist (x *liste* :start-after: '4)
(FORMAT t "~a~%" x))
resulting in:
5
6
Which Lisp dialect are we talking about?
Assuming Common Lisp.
#(1 2 3 4 5 6) is not a list. It is a vector.
CL-USER > (let ((v #(1 2 3 4 5 6)))
(loop for i from 4 below (length v)
do (print (aref v i))))
5
6
NIL
With a list:
CL-USER 1 > (mapc #'print (nthcdr 4 '(1 2 3 4 5 6)))
5
6
(5 6)
What's wrong with NTHCDR?
http://www.lispworks.com/documentation/HyperSpec/Body/f_nthcdr.htm#nthcdr