Bug report ID 2123651 "min and max of imaginary and real numbers"



I had a look at the open bug report ID 2123651 "min and max of imaginary
and real numbers". To correct the behavior I have tried the following
changes:

1. In $compare
   Check for infinities, infinitesimal, indeterminate.
   Take the limit for this case. This simplifies -minf to minf
   or 7+inf to inf.

2. In $compare
   First, do the check lenient-extended-realp.
   We do not try to do the test meqp for complex expressions.

3. In simp-max
   In the final clause, do not remove a minf, when issue-warning is T.
   Do not simplify to inf, when issue-warning is T.

With these changes we get a noun form for expression like max(%i*inf,
minf).

We will get 5 changes in the testsuite (3 different results and 2
correct results for expected failures):

Running tests in rtest_allnummod: 
********************** Problem 127 ***************
Input:
is(compare(%i, %i) = =)


Result:
false

This differed from the expected result:
true

********************** Problem 128 ***************
Input:
is(compare(a < b, a < b) = =)


Result:
false

This differed from the expected result:
true

********************** Problem 132 ***************
Input:
is(compare(infinity, infinity) = =)


Result:
false

This differed from the expected result:
true

********************** Problem 135 ***************
Input:
is(compare(inf, - minf) = =)


Result:
true

... Which was correct, but was expected to be wrong due to a known bug
in
 Maxima.

********************** Problem 136 ***************
Input:
is(compare(inf, 7 + inf) = =)


Result:
true

... Which was correct, but was expected to be wrong due to a known bug
in
 Maxima.

This is the complete code with the changes:

(defun $compare (a b)
  (when (amongl '($ind $und $inf $minf $infinity $zeroa $zerob) a)
    (setq a ($limit a)))
  (when (amongl '($ind $und $inf $minf $infinity $zeroa $zerob) b)
    (setq b ($limit b)))
  (cond ((or (not (lenient-extended-realp a))
             (not (lenient-extended-realp b)))
         '$notcomparable)
        ((eq t (meqp a b)) "=")
        (t
         (let ((sgn (csign (specrepcheck (sub a b)))))
           (cond ((eq sgn '$neg) "<")
                 ((eq sgn '$nz) "<=")
                 ((eq sgn '$zero) "=")
                 ((eq sgn '$pz) ">=")
                 ((eq sgn '$pos) ">")
                 ((eq sgn '$pn) "#")
                 ((eq sgn '$pnz) '$unknown)
                 (t '$unknown))))))

(defun simp-max (l tmp z)
  (let ((acc nil) (sgn) (num-max nil) (issue-warning))
    (setq l (margs (specrepcheck l)))
    (dolist (li l)
      (if (op-equalp li '$max)
          (setq acc (append acc (mapcar #'(lambda (s) (simplifya s z))
(margs li))))
          (push (simplifya li z) acc)))
    
    ;; First, delete duplicate members of l.
    
    (setq l (sorted-remove-duplicates (sort acc '$orderlessp)))
    (setq acc nil)
    
    ;; Second, find the largest real number in l. Since (mnump '$%i) -->
false,
    ;; we don't have to worry that num-max is complex.
    
    (dolist (li l)
      (if (mnump li)
          (setq num-max (if (or (null num-max) (mgrp li num-max)) li
num-max))
          (push li acc)))
    (setq l acc)
    (setq acc (if (null num-max) num-max (list num-max)))
    
    ;; Third, accumulate the maximum in the list acc. For each x in l,
do:
    
    ;; (a) if x is > or >= every member of acc, set acc to (x),
    ;; (b) if x is < or <= to some member of acc, do nothing,
    ;; (c) if neither 'a' or 'b', push x into acc,
    ;; (d) if x cannot be compared to some member of acc, set
issue-warning to true.
    
    (dolist (x l)
      (catch 'done
        (dolist (ai acc)
          (setq sgn ($compare x ai))
          (cond ((member sgn '(">" ">=") :test #'equal)
                 (setq acc (delete ai acc :test #'eq)))
                ((eq sgn '$notcomparable) (setq issue-warning t))
                ((member sgn '("<" "=" "<=") :test #'equal)
                 (throw 'done t))))
             (push x acc)))
    
    ;; Fourth, when when trylevel is 2 or higher e and -e are members of
acc,
    ;; replace e by |e|.
    
    (cond ((eq t (mgrp ($get '$trylevel '$maxmin) 1))
           (setq sgn nil)
           (dolist (ai acc)
             (setq tmp (if (lenient-realp ai)
                           (member-if #'(lambda (s) (add-inversep ai s))
sgn)
                           nil))
             (if tmp 
                 (setf (car tmp) (take '(mabs) ai))
                 (push ai sgn)))
           (setq acc sgn)))
    
    ;; Fifth, when trylevel is 3 or higher and issue-warning is false,
try the
    ;; betweenp simplification.
    
    (cond ((and (not issue-warning) (eq t (mgrp ($get '$trylevel
'$maxmin) 2)))
           (setq l nil)
           (setq sgn (cdr acc))
           (dolist (ai acc)
             (if (not (betweenp ai sgn sgn)) (push ai l))
             (setq sgn `(,@(cdr sgn) ,ai)))
           (setq acc l)))

    ;; Finally, do a few clean ups:
    
    (setq acc (if (not issue-warning) (delete '$minf acc) acc))
    (cond ((null acc) '$minf)
          ((and (not issue-warning) (member '$inf acc :test #'eq))
'$inf)
          ((null (cdr acc)) (car acc))
          (t  `(($max simp) ,@(sort acc '$orderlessp))))))

Comments? Should I commit the code?

Dieter Kaiser