1

I am doing an assignment for my class on ProofPad which is a web-based IDE for ACL2.

I have already been given two functions:

 ;;; BEGIN boilerplate code -- ignore :-)

(in-package "ACL2")

(include-book "testing" :dir :teachpacks)
(include-book "doublecheck" :dir :teachpacks)
(include-book "arithmetic-5/top" :dir :system)

;;; END boilerplate code

(defun tree-max (tree)
   (if (consp tree)
       (if (consp (third tree))
           (if (consp (fourth tree))
               (max-<< (first tree)
                    (max-<< (tree-max (third tree)) 
                            (tree-max (fourth tree))))
               (max-<< (first tree)
                       (tree-max (third tree))))
           (if (consp (fourth tree))
               (max-<< (first tree)
                       (tree-max (fourth tree)))
               (first tree)))
       'MIN-SYMBOL))
;;; This function finds the minimum key in a tree

(defun tree-min (tree)
   (if (consp tree)
       (if (consp (third tree))
           (if (consp (fourth tree))
               (min-<< (first tree)
                       (min-<< (tree-min (third tree)) 
                               (tree-min (fourth tree))))
               (min-<< (first tree)
                       (tree-min (third tree))))
           (if (consp (fourth tree))
               (min-<< (first tree)
                       (tree-min (fourth tree)))
               (first tree)))
       'MAX-SYMBOL)
   )

The conditions are these:

;;; This function checks whether the tree is a valid search tree
;;; The conditions are that:
;;;   1.   The tree is NIL, OR
;;;   2.1. The tree is a list with 4 elements (key value left right), AND
;;;   2.2. The key is a valid symbol, AND
;;;   2.3. The value is a rational number, AND
;;;   2.4. The left tree is NIL, OR the max of the left tree is << the key, AND
;;;   2.5. The right tree is NIL, OR the key is << the min of the right, AND
;;;   2.6. The left tree is a valid search tree, AND
;;;   2.7. The right tree is a valid search tree

This is what I have so far:

;;; TODO-5: Implement this function using the strategy above.

(defun search-treep (tree)
   (if (consp tree) ;;if list or tree is non-0
      (if (= (LEN '(tree)) 4)
      (if (symbolp (first tree)) ;;if the first item in list or "key" is a symbol
         (if(rationalp (second tree)) ;;if the second item for value is a number
            (if(AND ;;if both
            (OR (= (third tree) nil) (tree-max (third tree))) ;;The left tree is NIL, OR the max of                          
            (OR (= (fourth tree) nil) (tree-min(fourth tree)))) ;;The right tree is NIL, OR the key 
               (if (search-treep (third tree)) ;he left tree is a valid search tree
                 (if (search-treep (fourth tree)) t ;The right tree is a valid search tree
                 nil)
               nil)
            nil)
        nil)
     nil)
     nil)     
  nil))

I was expecting:

(check-expect (search-treep '(x 1 nil (z 3 (y 2 nil nil) nil))) t) - this one to be true
(check-expect (search-treep '(y 1 (z 3 (x 2 nil nil) nil) nil)) nil) - this one  to be nil

However both are Nil

Gwang-Jin Kim
  • 9,303
  • 17
  • 30

2 Answers2

0

This is not so easy to solve because it is ACL2 - and I don't have it installed in my computer. However, I see it is based on Common Lisp. So I will solve it with Common Lisp. If you know the ACL2-specific functions or expressions, feel free to replace them.

;; tree-reduce or tree-fold is a generalization 
;; for max or min or other functions over this kind of trees

(defun tree-reduce (node-fn leaf-fn tree)
  (cond ((null tree) nil)
        ((= (length tree) 4)
          (destructuring-bind (key value left right) tree
            (cond ((null left) (funcall node-fn value (tree-reduce node-fn leaf-fn right)))
                  ((null right) (funcall node-fn value (tree-reduce node-fn leaf-fn left)))
                  (t (funcall node-fn
                              (tree-reduce node-fn leaf-fn left)
                              (tree-reduce node-fn leaf-fn right))))))
        (t (funcall leaf-fn tree))))

;; since an empty tree returns `nil` we want the operators be
;; nil-resistant or nil-ignoring.
;; it returns `nil` if both a and b are nil.
(defun nil-ignore (op a b)
  (cond ((null a) b)
        ((null b) a)
        (t (funcall op a b))))

;; define nil-ignoring operators
(defun max-nil (a b)
  (nil-ignore #'max a b))

(defun min-nil (a b)
  (nil-ignore #'min a b))

;; now, we can define nil-ignoring max and min functions for the tree
(defun tree-max (tree)
  (tree-reduce #'max-nil
               #'identity 
               tree))

(defun tree-min (tree)
  (tree-reduce #'min-nil
               #'identity 
               tree))

Now, we can validate the tree:

;; because of the case of the empty tree, we want a 
;; nil-ignoring < operator
;; it evaluates quasi to true, if a or b are nil, however nil if both
;; are nil. Otherwise it evaluates (< a b)
(defun <-nil (a b)
  (nil-ignore #'< a b))

(defun valid-tree-p (tree)
  (or (null tree)
      (and (= (length tree) 4)
           (destructuring-bind (key value left right) tree
             (and (symbolp key)
                  (not (null key))       ; key should not be NIL
                  (rationalp value)
                  (valid-tree-p left)
                  (valid-tree-p right)
                  (<-nil (tree-max left) value)
                  (<-nil value (tree-min right)))))))

Test by:

(valid-tree-p '(x 1 nil (z 3 (y 2 nil nil) nil)))   ;;=> T
(valid-tree-p '(y 1 (z 3 (x 2 nil nil) nil) nil))   ;;=> NIL
(valid-tree-p '(x 1 nil (z 3 (y nil nil nil) nil))) ;;=> NIL
(valid-tree-p '(x 1 nil (z 3 (nil 2 nil nil) nil))) ;;=> NIL
(valid-tree-p '(x 1 nil (z 3 (y 2 nil) nil)))       ;;=> NIL
(valid-tree-p '(x 1 nil (z 3 (y 1 nil nil) nil)))   ;;=> NIL
(valid-tree-p '(x 2 nil (z 3 (y 4 nil nil) nil)))   ;;=> NIL
(valid-tree-p '(x 2 nil (z 4 (y 3 nil nil) nil)))   ;;=> T
Gwang-Jin Kim
  • 9,303
  • 17
  • 30
0

I would try to write search-tree-p using only and/or by expressing each condition as written in the specification. A way to check for NIL is to use the endp predicate.

I think it is possible to check the min/max requirements by using two auxiliary functions, but I don't have anything installed for ACL2 to check what I'm writing. This is based on the available online documentation.

(defun search-tree-p (tree)
  (or 
   ;; 1
   (endp tree)
   ;; 2.1
   (and (= (len tree) 4)
        ;; 2.2
        (symbolp (car tree))
        ;; 2.3
        (rationalp (cadr tree))
        ;; 2.6/2.4
        (search-tree-p/below (car tree) (caddr tree))
        ;; 2.7/2.5
        (search-tree-p/above (car tree) (cadddr tree)))))

(defun search-tree-p/below (max tree)
  (and (or (endp tree) (symbol< (car tree) max))
       (search-tree-p tree)))

(defun search-tree-p/above (min tree)
  (and (or (endp tree) (symbol< min (car tree)))
       (search-tree-p tree)))
coredump
  • 37,664
  • 5
  • 43
  • 77