|
From: tomasriker <tom...@us...> - 2026-06-02 06:59:54
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Maxima CAS".
The branch, master has been updated
via 46cd19a89f63d02d858cc965f5527c56f456c412 (commit)
from 7fc142f5436bcfa02107388d8d25c6119ec482c5 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 46cd19a89f63d02d858cc965f5527c56f456c412
Author: David Scherfgen <d.s...@go...>
Date: Tue Jun 2 08:58:34 2026 +0200
Prevent some inconsistent type declarations and restore/add kind inferences
This commit partially resolves bug #4749 by tightening Maxima's property
declaration engine and restoring foundational numeric inferences that had been
commented out in compar.lisp since 2009.
Summary of changes:
* Restored standard numeric tower inferences: integer -> rational,
and par(rational, irrational) -> real.
* Added missing lateral inferences: irrational -> noninteger and
imaginary -> noninteger (Maxima seems to treat zero as non-imaginary).
* Modified DECLAREKIND to explicitly block mathematically invalid
cross-declarations (e.g., real and imaginary, rational and imaginary),
while relying on the inference engine to handle subset exclusions.
* Removed redundant property checks in DECL-REALP and across compar.lisp, as the
restored inferences now handle transitive types natively. This greatly reduces
the number of potentially expensive KINDP checks.
* Cleaned up kind declarations for mathematical constants to rely on the
inferencing engine.
* Added exhaustive tests for errors on inconsistent declarations and
inferencing.
Note that complex and real aren't treated as mutually exclusive (yet). This
might require further discussion and deeper code changes.
diff --git a/src/compar.lisp b/src/compar.lisp
index fc3221589..0be22b6cc 100644
--- a/src/compar.lisp
+++ b/src/compar.lisp
@@ -2165,8 +2165,6 @@ TDNEG TDZERO TDPN) to store it, and also sets SIGN."
((mnump x) nil)
((and (symbolp x)
(or (kindp x '$integer)
- (kindp x '$even)
- (kindp x '$odd)
(check-integer-facts x))))
(t (let ((x-op (and (consp x) (consp (car x)) (caar x))) ($prederror nil))
(cond ((null x-op) nil)
@@ -2209,9 +2207,7 @@ TDNEG TDZERO TDPN) to store it, and also sets SIGN."
;; Case equal(x,expr): Test expr to be an integer.
(cond ((symbolp (caddr fact))
(cond ((and (eq mode 'integer)
- (or (kindp (caddr fact) '$integer)
- (kindp (caddr fact) '$odd)
- (kindp (caddr fact) '$even)))
+ (kindp (caddr fact) '$integer))
(return t))
((eq mode 'evod)
(cond ((kindp (caddr fact) '$odd)
@@ -2231,9 +2227,7 @@ TDNEG TDZERO TDPN) to store it, and also sets SIGN."
;; Case equal(expr,x): Test expr to be an integer.
(cond ((symbolp (caddr fact))
(cond ((and (eq mode 'integer)
- (or (kindp (cadr fact) '$integer)
- (kindp (cadr fact) '$odd)
- (kindp (cadr fact) '$even)))
+ (kindp (cadr fact) '$integer))
(return t))
((eq mode 'evod)
(cond ((kindp (cadr fact) '$odd)
@@ -2250,7 +2244,7 @@ TDNEG TDZERO TDPN) to store it, and also sets SIGN."
(t (return nil)))))))))))
(defun nonintegerp (e)
- (cond ((and (symbolp e) (or (kindp e '$noninteger) (check-noninteger-facts e) (kindp e '$irrational)))) ;declared noninteger
+ (cond ((and (symbolp e) (or (kindp e '$noninteger) (check-noninteger-facts e)))) ;declared noninteger
((mnump e)
(if (integerp e) nil t)) ;all floats are noninteger and integers are not nonintegers
(($ratp e)
@@ -2601,14 +2595,27 @@ TDNEG TDZERO TDPN) to store it, and also sets SIGN."
(let (prop2)
(cond ((truep (list 'kind var prop)) t)
((or (falsep (list 'kind var prop))
- (and (setq prop2 (assoc prop '(($integer . $noninteger)
+ (and (setq prop2 (assoc prop
+ ;; Note that the following list of inconsistent type
+ ;; declaration pairs intentionally omits cases that are
+ ;; handled by the inferencing engine in the above FALSEP
+ ;; call, e.g., ($even . $odd).
+ ;; Similarly, the pair ($imaginary . $real) also covers
+ ;; $rational, $irrational, $integer, $even and $odd on
+ ;; the right hand side via inferencing in the below
+ ;; TRUEP call.
+ '(($integer . $noninteger)
($noninteger . $integer)
+ ($even . $noninteger)
+ ($odd . $noninteger)
+ ($rational . $imaginary) ; Maxima doesn't seem to think of zero
+ ($irrational . $imaginary) ; as an imaginary number,
+ ($real . $imaginary) ; therefore these pairs are all
+ ($imaginary . $real) ; inconsistent.
($increasing . $decreasing)
($decreasing . $increasing)
($symmetric . $antisymmetric)
($antisymmetric . $symmetric)
- ($rational . $irrational)
- ($irrational . $rational)
($oddfun . $evenfun)
($evenfun . $oddfun)) :test #'eq))
(truep (list 'kind var (cdr prop2)))))
@@ -2782,35 +2789,34 @@ TDNEG TDZERO TDPN) to store it, and also sets SIGN."
(eval-when (:load-toplevel :execute)
(mapc #'true*
- '(;; even and odd are integer
+ '(;; Even and odd numbers partition the integers.
(par ($even $odd) $integer)
-; Cutting out inferences for integer, rational, real, complex (DK 10/2009).
-; (kind $integer $rational)
-; (par ($rational $irrational) $real)
-; (par ($real $imaginary) $complex)
+ ;; Integers are rationals.
+ (kind $integer $rational)
+
+ ;; Irrationals are nonintegers.
+ (kind $irrational $noninteger)
+
+ ;; Rationals and irrationals partition the reals.
+ (par ($rational $irrational) $real)
- ;; imaginary is complex
+ ;; Imaginary numbers are complex and nonintegers
+ ;; (Maxima doesn't seem to think of zero as an imaginary number).
(kind $imaginary $complex)
+ (kind $imaginary $noninteger)
+
+ ;; Declarations for constants
+ (kind $%i $imaginary)
+ (kind $%e $irrational)
+ (kind $%pi $irrational)
+ (kind $%gamma $noninteger) ; when proven irrational,
+ (kind $%gamma $real) ; replace with a single $irrational
+ (kind $%phi $irrational)
+ (kind $%catalan $noninteger) ; when proven irrational,
+ (kind $%catalan $real) ; replace with a single $irrational
- ;; Declarations for constants
- (kind $%i $noninteger)
- (kind $%i $imaginary)
- (kind $%e $noninteger)
- (kind $%e $real)
- (kind $%pi $noninteger)
- (kind $%pi $real)
- (kind $%gamma $noninteger)
- (kind $%gamma $real)
- (kind $%phi $noninteger)
- (kind $%phi $real)
- (kind $%pi $irrational)
- (kind $%e $irrational)
- (kind $%phi $irrational)
- (kind $%catalan $noninteger)
- (kind $%catalan $real)
-
- ;; Declarations for functions
+ ;; Declarations for functions
(kind %log $increasing)
(kind %asin $increasing) (kind %asin $oddfun)
(kind %atan $increasing) (kind %atan $oddfun)
diff --git a/src/simp.lisp b/src/simp.lisp
index 950ff5b1a..a24af4507 100644
--- a/src/simp.lisp
+++ b/src/simp.lisp
@@ -2777,17 +2777,12 @@
;; TRUE, if the symbol e is declared to be $complex or $imaginary.
(defun decl-complexp (e)
- (and (symbolp e)
- (kindp e '$complex)))
+ (kindp e '$complex))
;; TRUE, if the symbol e is declared to be $real, $rational, $irrational
;; or $integer
(defun decl-realp (e)
- (and (symbolp e)
- (or (kindp e '$real)
- (kindp e '$rational)
- (kindp e '$irrational)
- (kindp e '$integer))))
+ (kindp e '$real))
;; WARNING: Exercise extreme caution when modifying this function!
;;
diff --git a/tests/rtest16.mac b/tests/rtest16.mac
index 0d9c766d3..c54f5ddcc 100644
--- a/tests/rtest16.mac
+++ b/tests/rtest16.mac
@@ -3293,6 +3293,99 @@ factor(a^2*g+a*g-a^2, second(factor(g^3-1)));
kill(x);
done$
+/*
+Bug #4749: "Declaring a symbol both real and complex or real and imaginary"
+Test all(?) pairs of inconsistent declarations and make sure they cause errors.
+*/
+
+sublist
+(
+ [
+ ['integer, 'noninteger],
+ ['even, 'noninteger],
+ ['odd, 'noninteger],
+ ['rational, 'irrational],
+ ['integer, 'irrational],
+ ['even, 'irrational],
+ ['odd, 'irrational],
+ ['real, 'imaginary],
+ ['rational, 'imaginary],
+ ['irrational, 'imaginary],
+ ['integer, 'imaginary],
+ ['even, 'imaginary],
+ ['odd, 'imaginary],
+ ['even, 'odd],
+ ['increasing, 'decreasing],
+ ['symmetric, 'antisymmetric],
+ ['evenfun, 'oddfun],
+ ['scalar, 'nonscalar]
+ ],
+ lambda
+ (
+ [pair],
+ block
+ (
+ [[a, b] : pair],
+ /* first a, then b */
+ kill(x),
+ apply('declare, ['x, a]),
+ if errcatch(apply('declare, ['x, b])) # [] then return(true),
+ /* first b, then a */
+ kill(y),
+ apply('declare, ['y, b]),
+ if errcatch(apply('declare, ['y, a])) # [] then return(true),
+ false
+ )
+ )
+);
+[];
+
+kill(x, y);
+done;
+
+/*
+Test inferencing, e.g. irrational -> noninteger
+A list entry ['rational, ['rational, 'real, -'irrational, -'imaginary]] means
+that for a symbol x declared rational,
+featurep(x, rational) and featurep(x, real) should return true, and
+featurep(x, irrational) and featurep(x, imaginary) should return false.
+*/
+
+sublist
+(
+ [
+ ['even, ['even, 'integer, 'rational, 'real, -'odd, -'noninteger, -'imaginary]],
+ ['odd, ['odd, 'integer, 'rational, 'real, -'even, -'noninteger, -'imaginary]],
+ ['integer, ['integer, 'rational, 'real, -'noninteger, -'imaginary]],
+ ['rational, ['rational, 'real, -'irrational, -'imaginary]],
+ ['irrational, ['irrational, 'real, 'noninteger, -'rational, -'integer, -'even, -'odd, -'imaginary]],
+ ['imaginary, ['imaginary, 'complex, 'noninteger, -'real, -'rational, -'irrational, -'integer, -'even, -'odd]]
+ ],
+ lambda
+ (
+ [entry],
+ block
+ (
+ [[source, targets] : entry, failed : false, expected, res],
+ kill(x),
+ apply('declare, ['x, source]),
+ for target in targets do
+ (
+ if atom(target) then expected : true
+ else [target, expected] : [-target, false],
+ if apply('featurep, ['x, target]) # expected then failed : true
+ ),
+ failed
+ )
+ )
+);
+[];
+
+kill(x);
+done;
+
+
+
+/* Leave this at the end of the file! */
contexts;
[initial, global]$
-
-----------------------------------------------------------------------
Summary of changes:
src/compar.lisp | 78 ++++++++++++++++++++++++---------------------
src/simp.lisp | 9 ++----
tests/rtest16.mac | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 138 insertions(+), 44 deletions(-)
hooks/post-receive
--
Maxima CAS
|