1 ;;; Define a length function similar to the one in maple, at least on polynomials
2 ;;; Symbols have length equal to the number of characters, etc. Composite objects have
3 ;;; length given by the sum of lengths of atoms plus length of structures as discovered with
4 ;;; dismantle. Example:
6 ;; > dismantle(3*xxx^2):
7 ;; SUM(3) header of polynomial length 3
8 ;; PROD(3) header of monomial length 3
9 ;; NAME(4): xxx symbol length 3
10 ;; INTPOS(2): 2 power 2 length 1
11 ;; INTPOS(2): 3 coeff 3 length 1 total 3+3+3+1+1=11
15 ;; One sees that monomials x^ay^b... are represented by a structure PROD of
16 ;; length 2n+1 (n the number of terms, each gets 2 slots pointing to variable and power,
17 ;; even when the power is 1) but if we have just a variable no prod is generated.
18 ;; As soon as the monomial has a coefficient or if there is a sum of terms, they are
19 ;; represented by a structure SUM of length 2n+1 (n the number of terms, each one occupies 2
20 ;; slots for pointers to monomial and coefficient, even 1 if the coeff is 1). Thus
21 ;; length(x+y)=9 while length(x^2+y^2)=17, difference due to 2 PROD of length 2.3=6 plus the lengths
22 ;; of the exponents 1+1=2. Moreover x+y is represented by SUM (length 5) plus 2 variables
23 ;; and coeffs equal to 1 (length 4). This is very different from the maxima representation.
29 ;; The cases where mapatom returns T
30 ; For a rational the header adds 2, length(3/5)=5
31 ; In maxima 32/76 is represented as ((RAT SIMP) 8 19), simplified, so remove 13
32 ; Note one gets the length of the simplified rational, as in maple
33 ; For a float the header adds 3, length(5.67)=7
34 ; For a subscripted variable, the header adds 3, length(x[12])=8
35 ; In maxima x[12] is represented as (($X SIMP ARRAY) 12) so remove 15
36 ; If x[12] is assigned, one gets the length of the assignment
38 (defun charsets_atomlength (x)
39 (cond ((integerp x
) (length (write-to-string x
)))
40 (($ratnump x
) (- (length (write-to-string x
)) 11))
41 ((floatp x
) (+ 3 (length (write-to-string x
))))
42 (($subvarp x
) (- (length (write-to-string x
)) 12))
43 ((symbolp x
) (1- (length (symbol-name x
)))) ; to remove the leading $
44 (t (merror "Mapatom must send the argument on 1 here."))))
46 (defun charsets_maxatomp (x)
48 (if (or (charsets_coeffp x
) (charsets_variap x
)) t nil
))
51 (defun charsets_coeffp (x)
52 "Maxima atoms which can be coefficients"
53 (cond ((atom x
) (if (or (integerp x
)(floatp x
)) t nil
))
54 ((and (listp (car x
)) ($ratnump x
)) t
)
57 (defun charsets_variap (x)
58 "Maxima atoms which can be variables"
60 ((and (listp (car x
)) ($subvarp x
)) t
)
64 (defun charsets_atomlength1 (x insum
)
65 ;; An atom (symbol coeff or exponent) causes no problem at the higher level (start)
66 ;; or in a power term. But a bare symbol in a sum or a prod needs to add 1 for the
67 ;; coeff (=1) resp. the exponent (=1), a bare number in a sum needs to add 1 as coeff.
68 ;; Examples: x*y -> prod (x^1,y^1), x+y -> sum (1*x,1*y),
69 ;; 2*x*y -> sum (2*prod (x^1,y^1)), 3+2*x -> sum(1*3,2*x)
70 ;; This has to ba called only on sums and products
71 (cond (insum (1+ (charsets_atomlength x
))) ; add 1 for bare numbers and symbols
72 (t (if (or (symbolp x
)($subvarp x
)) ; add 1 only for bare symbols in products
73 (1+ (charsets_atomlength x
)) (charsets_atomlength x
)))))
78 ;; The case where mapatom returns false
79 ;; In maxima (in maple this is automatically done)
80 ;; the polynomial must first be expanded to distribute eventual coefficients, e.g.
81 ;; (2*x^3*y^5+3*y*z^2)/5 after applying expand is represented as:
83 ;; ((MTIMES SIMP) ((RAT SIMP) 2 5) ((MEXPT SIMP) $X 3) ((MEXPT SIMP) $Y 5))
84 ;; ((MTIMES SIMP) ((RAT SIMP) 3 5) $Y ((MEXPT SIMP) $Z 2)))
85 ;; Note that contrary to maple, in the second monomial, Y is not ((MEXPT SIMP) $Y 1)
88 (defun $charsets_polylength
(x)
89 (let ((y ($expand x
)))
90 ;; We treat here the exceptional cases at start: isolated atoms, isolated exponent x^m,
91 ;; isolated product like 2*x -> sum (2*x) of length 5 and not sum(2*prod(x^1)) of length 9
93 (cond ((atom y
) (charsets_atomlength y
)) ; isolated integer, float or symbol
94 ((and (listp (car y
)) ($ratnump y
)) (charsets_atomlength y
)) ; idem, rational
95 ((and (listp (car y
)) ($subvarp y
)) (charsets_atomlength y
)) ; idem, subscripted variable
96 ((and (listp (car y
)) (eq (caar y
) 'MTIMES
) (eql (length (cdr y
)) 2)
97 (charsets_coeffp (second y
)) (charsets_variap (third y
)))
98 (+ 3 (charsets_atomlength (second y
)) (charsets_atomlength (third y
))))
99 ((and (listp (car y
)) (eq (caar y
) 'MEXPT
))
100 (+ 3 (reduce #'+ (mapcar #'charsets_atomlength
(cdr y
))))) ; isolated x^m
101 ;; Now we know we have a sum or a prod or a list of terms
102 (t (let ((insum nil
)) (charsets_polyrecur y insum
))))))
104 ;; Monomials at the top level with a coefficient require an extra sum header. We call them
105 ;; impure. One then needs to add 3 to length and reduce by 1 the number of terms
107 (defun charsets_impuremonomialp (x)
108 ; we suppose (and (listp (car x)) (eq (caar x) 'MTIMES) true
109 (if (charsets_coeffp (cadr x
)) t nil
))
112 (defun charsets_partial-length (h-length n-terms x insum
)
113 (+ h-length
1 (* 2 n-terms
) (reduce #'+ (charsets_polyrecur (cdr x
) insum
))))
115 (defun charsets_polyrecur (x insum
)
116 ;; MEXPT terms don't produce a new header when inside a prod
117 (if (charsets_maxatomp x
) (charsets_atomlength1 x insum
)
118 (cond ((and (listp (car x
)) (eq (caar x
) 'MPLUS
)) ; sum
120 (charsets_partial-length 0 (length (cdr x
)) x insum
))
121 ((and (listp (car x
)) (eq (caar x
) 'MTIMES
)) ; monomial
122 (let ((h-length 0) (n-terms (length (cdr x
))))
123 (if (charsets_impuremonomialp x
) (setq n-terms
(1- n-terms
)))
124 (if (not insum
) (setq h-length
3)) ; maple sees it as a sum
126 (charsets_partial-length h-length n-terms x insum
)))
127 ((and (listp (car x
)) (eq (caar x
) 'MEXPT
))
129 (+ 4 (reduce #'+ (mapcar #'charsets_atomlength
(cdr x
)))) ; isolated x^m
130 (reduce #'+ (mapcar #'charsets_atomlength
(cdr x
))))) ; x^m in a product
131 (t (mapcar #'(lambda(y)(charsets_polyrecur y insum
)) x
))))) ; list of monomials or list of terms
134 ;; (%i3) polylength( (2*x^3*y^5+3*y*z^2)/5);
136 ;; (%i4) polylength(x+y);
138 ;; (%i5) polylength(2*x);
140 ;; (%i6) polylength(2*x^2*y^3);
142 ;; All the same values as in maple. It should be remarked that this length function doesn't
143 ;; discriminate as much as one would like, e.g. x+y and x*y have same length 9
145 ;; Extension to sets and lists. In maple there is a header of length n+3 where n is
146 ;; the length or the set or list.
148 (defun $charsets_length
(x)
149 "Length function similar to maple one for lists of polynomials"
150 (cond ((and (listp x
) (listp (car x
)) (or (eq (caar x
) 'MLIST
) (eq (caar x
) '$SET
)))
151 (+ 3 (length (cdr x
)) (reduce #'+ (mapcar #' $charsets_polylength
(cdr x
)))))
152 (($charsets_polynomialp x
) ($charsets_polylength x
))
153 (t (merror "Only lists or sets of polynomials supported."))))
156 ;; (%i8) charsets_length([ (2*x^3*y^5+3*y*z^2)/5,2*x^2*y^3]);
158 ;; Same result as in maple.