; Basic rules

; Note that ? is used for rules that can be used where Int/Real are
; interchangable. This is because Int and Real are not comparable in our
; type system.

(define-rule arith-div-total-zero-real ((t ?)) (/_total t 0/1) 0/1)
(define-rule arith-div-total-zero-int ((t ?)) (/_total t 0) 0/1)

(define-cond-rule arith-int-div-total ((t Int) (s Int)) (not (= s 0)) (div t s) (div_total t s))
(define-rule arith-int-div-total-one ((t Int)) (div_total t 1) t)
(define-rule arith-int-div-total-zero ((t Int)) (div_total t 0) 0)

(define-cond-rule arith-int-div-total-neg ((t Int) (s Int)) (< s 0) (div_total t s) (- (div_total t (- s))))

(define-cond-rule arith-int-mod-total ((t Int) (s Int)) (not (= s 0)) (mod t s) (mod_total t s))
(define-rule arith-int-mod-total-one ((t Int)) (mod_total t 1) 0)
(define-rule arith-int-mod-total-zero ((t Int)) (mod_total t 0) t)

(define-cond-rule arith-int-mod-total-neg ((t Int) (s Int)) (< s 0) (mod_total t s) (mod_total t (- s)))

; Eliminations
(define-rule arith-elim-gt ((t ?) (s ?)) (> t s) (not (>= s t)))
(define-rule arith-elim-lt ((t ?) (s ?)) (< t s) (not (>= t s)))
(define-rule arith-elim-int-gt ((t Int) (s Int)) (> t s) (>= t (+ s 1)))
(define-rule arith-elim-int-lt ((t Int) (s Int)) (< t s) (>= s (+ t 1)))
(define-rule arith-elim-leq ((t ?) (s ?)) (<= t s) (>= s t))

(define-rule arith-leq-norm ((t Int) (s Int)) (<= t s) (not (>= t (+ s 1))))

(define-rule arith-geq-tighten ((t Int) (s Int)) (not (>= t s)) (>= s (+ t 1)))

(define-rule arith-geq-norm1-int ((t Int) (s Int)) (>= t s) (>= (- t s) 0))
(define-rule arith-geq-norm1-real ((t Real) (s Real)) (>= t s) (>= (- t s) 0/1))

(define-rule arith-eq-elim-real ((t Real) (s Real)) (= t s) (and (>= t s) (<= t s)))
(define-rule arith-eq-elim-int ((t Int) (s Int)) (= t s) (and (>= t s) (<= t s)))

(define-rule arith-to-int-elim ((x Int)) (to_int x) x)
(define-rule arith-to-int-elim-to-real ((x ?)) (to_int (to_real x)) (to_int x))
(define-rule arith-div-elim-to-real1 ((x ?) (y ?)) (/ (to_real x) y) (/ x y))
(define-rule arith-div-elim-to-real2 ((x ?) (y ?)) (/ x (to_real y)) (/ x y))

(define-cond-rule arith-mod-over-mod ((c Int) (ts Int :list) (r Int) (ss Int :list))
  (not (= c 0))
  (mod_total (+ ts (mod_total r c) ss) c)
  (mod_total (+ ts r ss) c))

(define-cond-rule arith-int-eq-conflict ((t Int) (c Real))
  (not (= (to_real (to_int c)) c))
  (= (to_real t) c)
  false)

(define-cond-rule arith-int-geq-tighten ((t Int) (c Real) (cc Int))
  (and (not (= (to_real (to_int c)) c)) (= cc (+ (to_int c) 1)))
  (>= (to_real t) c)
  (>= t cc))

(define-cond-rule arith-divisible-elim ((n Int) (t Int))
  (not (= n 0))
  (divisible n t)
  (= (mod_total t n) 0))

; absolute value comparisons

(define-rule arith-abs-eq ((x ?) (y ?))
  (= (abs x) (abs y))
  (or (= x y) (= x (- y))))

(define-rule arith-abs-int-gt ((x Int) (y Int))
  (> (abs x) (abs y))
  (ite (>= x 0)
    (ite (>= y 0)
      (> x y)
      (> x (- y)))
    (ite (>= y 0)
      (> (- x) y)
      (> (- x) (- y)))))

(define-rule arith-abs-real-gt ((x Real) (y Real))
  (> (abs x) (abs y))
  (ite (>= x 0/1)
    (ite (>= y 0/1)
      (> x y)
      (> x (- y)))
    (ite (>= y 0/1)
      (> (- x) y)
      (> (- x) (- y)))))

; ITE lifting

(define-rule arith-geq-ite-lift ((C Bool) (t ?) (s ?) (r ?))
  (>= (ite C t s) r)
  (ite C (>= t r) (>= s r)))

(define-rule arith-leq-ite-lift ((C Bool) (t ?) (s ?) (r ?))
  (<= (ite C t s) r)
  (ite C (<= t r) (<= s r)))

; min/max rules

(define-rule arith-min-lt1 ((t ?) (s ?))
  (<= (ite (< t s) t s) t)
  true)

(define-rule arith-min-lt2 ((t ?) (s ?))
  (<= (ite (< t s) t s) s)
  true)

; The rules for leq, gt are not applied if the arith static learner
; is applied only to rewritten terms.
;(define-rule arith-min-leq1 ((t ?) (s ?))
;  (<= (ite (<= t s) t s) t)
;  true)

;(define-rule arith-min-leq2 ((t ?) (s ?))
;  (<= (ite (<= t s) t s) s)
;  true)

;(define-rule arith-max-gt1 ((t ?) (s ?))
;  (>= (ite (> t s) t s) t)
;  true)

;(define-rule arith-max-gt2 ((t ?) (s ?))
;  (>= (ite (> t s) t s) s)
;  true)

(define-rule arith-max-geq1 ((t ?) (s ?))
  (>= (ite (>= t s) t s) t)
  true)

(define-rule arith-max-geq2 ((t ?) (s ?))
  (>= (ite (>= t s) t s) s)
  true)
