Bug report ID 2123651 "min and max of imaginary and real numbers"
Subject: Bug report ID 2123651 "min and max of imaginary and real numbers"
From: Dieter Kaiser
Date: Sun, 05 Sep 2010 20:41:51 +0200
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