;;; Contributed by Ruben A. Gamboa

; Copyright (C) 2014, University of Wyoming
; All rights reserved.
; License: A 3-clause BSD license.  See the LICENSE file distributed with ACL2.


(in-package "ACL2")

;;; The absolute-value function has many useful properties, but ACL2
;;; doesn't know about them.  Instead, it likes to explode abs(x) into
;;; the two cases x<0 and x>=0, and that often leads to unnecessary
;;; case explosions.  In this book, we prove the more useful lemmas
;;; about abs.

(include-book "top")

;;; We start with |x*y| = |x| * |y|.  This is actually a dangerous
;;; lemma, sometimes, so we often disable it.

(defthm abs-*
  (implies (and (real/rationalp x) (real/rationalp y))
	   (equal (abs (* x y))
		  (* (abs x) (abs y)))))

;;; An obvious lemma that ACL2 doesn't know is that |-x| = |x|.

(defthm abs-uminus
  (equal (abs (- x))
	 (abs (fix x))))

;;; And |x| is always real, so long as x is real (which is should be
;;; from the guards).

(defthm realp-abs
  (implies (real/rationalp x)
	   (real/rationalp (abs x))))

;;; Similarly, abs is always numeric.

(defthm numberp-abs
  (implies (acl2-numberp x)
	   (acl2-numberp (abs x))))

;;; |x| = x when x is a non-negative real.

(defthm abs-x->-0
  (implies (and (real/rationalp x)
		(<= 0 x))
	   (equal (abs x) x)))

;;; If x is real and non-zero, then |x| is positive.

(defthm abs-x-=-0-iff-x=0
  (implies (and (real/rationalp x)
		(not (= 0 x)))
	   (< 0 (abs x))))

;;; And no matter what, |x|>=0.

(defthm not-abs-x-<-0
  (not (< (abs x) 0))
  :rule-classes (:rewrite :type-prescription))

;;; When you see a term |x| in an expression and you want to replace
;;; it with a new variable x1, keep in mind that x1>=0.

(defthm abs-x-generalize-weak
  (implies (real/rationalp x)
	   (and (<= 0 (abs x))
		(real/rationalp (abs x))))
  :rule-classes (:generalize :rewrite))

;;; Moreover, if you know x is non-zero, when you generalize |x| with
;;; x1, you can assume that x1>0.

(defthm abs-x-generalize-strong
  (implies (and (real/rationalp x)
		(not (equal x 0)))
	   (< 0 (abs x)))
  :rule-classes (:generalize :rewrite))

;;; |x+y| <= |x| + |y|.

(defthm abs-triangle
  (<= (abs (+ x y)) (+ (abs x) (abs y))))

(in-theory (disable abs))
