1 ;; Author Barton Willis
2 ;; University of Nebraska at Kearney
3 ;; Copyright (C) 2004, Barton Willis
5 ;; Brief Description: Maxima code for linear homogeneous second order
6 ;; differential equations.
8 ;; Maxima odelin is free software; you can redistribute it and/or
9 ;; modify it under the terms of the GNU General Public License,
10 ;; http://www.gnu.org/copyleft/gpl.html.
12 ;; Maxima odelin has NO WARRANTY, not even the implied warranty of
13 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 ($put
'$lazysolver
1 '$version
)
18 #+gcl
(load compile eval
)
19 #-gcl
(:load-toplevel
:compile-toplevel
:execute
)
22 (defmvar $aalgsys_is_loquacious nil
)
25 (or ($symbolp e
) ($subvarp e
)))
27 ;; Check that sol is a solution to eqs and that nz is nonvanishing.
29 (defun $checksolution
(sol eqs
&optional
(nz `((mlist))))
30 (let (($gcd
'$spmod
) ($algebraic t
) ($ratfac nil
) ($ratprint nil
))
31 (if (not ($listp sol
)) (setq sol
`((mlist) ,sol
)))
32 (if (not ($listp eqs
)) (setq eqs
`((mlist) ,eqs
)))
33 (if (not ($listp nz
)) (setq nz
`((mlist) ,nz
)))
34 (setq eqs
(mapcar #'meqhk
(cdr eqs
)))
35 (setq eqs
`((mlist) ,@eqs
))
37 (every #'mequalp
(cdr sol
))
38 (every #'(lambda (s) (variablep ($lhs s
))) (cdr sol
))
39 (every #'(lambda (s) (like 0 s
)) (cdr (sratsimp ($substitute sol eqs
))))
40 (every #'(lambda (s) (not (like 0 s
)))
41 (cdr (sratsimp ($substitute sol nz
)))))))
43 ;; The function 'checkedalgsys' tries to return the "simplest" solution.
44 ;; it uses this simple-minded measure of simple.
46 (defun my-expr-size (e)
47 (xmy-expr-size ($totaldisrep e
)))
49 (defun xmy-expr-size (e)
50 (if (consp e
) (apply #'+ (mapcar #'my-expr-size
(margs e
))) 1))
52 (defun my-freeof (unks q
)
53 (every #'(lambda (x) ($freeof x q
)) (cdr unks
)))
55 ;; This function solves 'eqs' for 'vars' and returns a solution such that
56 ;; no expression in the Maxima list 'nz' vanishes. Since
57 ;; 'algsys' sometimes returns bogus solutions--checkedalgsys checks
58 ;; the putative solutions and rejects bogus solutions. To return
59 ;; the 'simpliest' solution, we sort the putative solutions using
62 (defun $checkedalgsys
(eqs vars
&optional
(nz `((mlist))))
64 (let ((sol) ($ratfac nil
) ($ratprint nil
) ($realonly nil
) ($algexact t
)
65 ($gcd
'$spmod
) ($algebraic t
)
66 ($programmode t
) ($globalsolve nil
) ($solveexplicit t
)
67 ($listconstvars t
) ($solveradcan nil
) ($ratvars nil
))
69 (if $aalgsys_is_loquacious
70 (mtell "...solving ~:M equations in ~:M variables~%"
71 ($length eqs
) ($length vars
)))
73 (setq sol
(cdr ($algsys eqs vars
)))
74 (setq sol
(sort sol
#'(lambda (a b
) (< (my-expr-size a
) (my-expr-size b
)))))
76 (if ($checksolution si eqs nz
) (return si
)))))
78 ;; The function 'checkedalgsys' tries to return the "simplest" solution.
79 ;; it uses this simple-minded measure of simple.
81 (defun nonconstant-factors (e vars
)
84 (setq e
(if (mtimesp e
) (margs e
) (list e
)))
85 (dolist (ei e
`(($set
) ,@acc
))
86 (if (mexptp ei
) (setq ei
(car (margs ei
))))
87 (if (not (my-freeof vars ei
)) (push ei acc
)))))
90 (or ($symbolp e
) ($subvarp e
)))
92 (defun $checksolution
(sol eqs
&optional
(nz `((mlist))))
93 (let (($gcd
'$spmod
) ($algebraic t
) ($ratfac nil
) ($ratprint nil
))
94 (if (not ($listp sol
)) (setq sol
`((mlist) ,sol
)))
95 (if (not ($listp eqs
)) (setq eqs
`((mlist) ,eqs
)))
96 (if (not ($listp nz
)) (setq nz
`((mlist) ,nz
)))
97 (setq eqs
(mapcar #'meqhk
(cdr eqs
)))
98 (setq eqs
`((mlist) ,@eqs
))
100 (every #'mequalp
(cdr sol
))
101 (every #'(lambda (s) (variablep ($lhs s
))) (cdr sol
))
102 (every #'(lambda (s) (like 0 s
)) (cdr (sratsimp ($substitute sol eqs
))))
103 (every #'(lambda (s) (not (like 0 s
)))
104 (cdr (sratsimp ($substitute sol nz
)))))))
106 (defun unks-in-eq (eq unks
)
107 (let (($listconstvars nil
))
108 ($intersection
($setify
($listofvars eq
)) unks
)))
110 (defun $aalgsys
(e-eqs eqs unks
&optional
(nz `((mlist))))
111 (let ((e-vars) (sol) (e-sol) ($gcd
'$spmod
) ($algebraic t
)
112 ($ratvars nil
) ($radexpand nil
) ($ratfac nil
) ($ratprint nil
))
114 (setq unks
($setify unks
))
115 (setq unks
(mbag-map #'$ratdisrep unks
))
117 (setq eqs
($setify eqs
))
118 (setq eqs
(mbag-map #'$ratdisrep eqs
))
120 (setq e-eqs
($setify e-eqs
))
121 (setq e-eqs
(mbag-map #'$ratdisrep e-eqs
))
122 (setq e-eqs
(mbag-map #'$factor e-eqs
))
124 (setq e-eqs
($union e-eqs
125 ($subset eqs
#'(lambda (w)
126 (= 1 (number-of-unks w unks
))))))
128 (setq e-vars
(unks-in-eq e-eqs unks
))
129 (setq e-eqs
($union e-eqs
130 ($subset eqs
#'(lambda (w)
131 (like (unks-in-eq w unks
) e-vars
)))))
133 (setq e-eqs
(mbag-map #'$ratdisrep e-eqs
))
134 (setq e-eqs
(mbag-map #'$factor e-eqs
))
135 (setq e-eqs
($disjoin
0 e-eqs
))
137 ;; (displa `((mequal) eeqs ,e-eqs))
138 (setq e-eqs
($listify e-eqs
))
139 (setq e-vars
($listify e-vars
))
140 (setq eqs
($listify eqs
))
141 (setq unks
($listify unks
))
144 (cond ((not ($emptyp e-vars
))
145 (setq e-sol
($algsys e-eqs e-vars
))
146 (setq e-sol
($setify e-sol
))
148 ($subset e-sol
#'(lambda (w) ($checksolution w e-eqs nz
))))
150 ($subset e-sol
#'(lambda (w) (my-freeof $%rnum_list w
))))
151 (setq e-sol
($listify e-sol
))
153 (cond ((not ($emptyp e-sol
))
154 (setq e-sol
(margs e-sol
))
156 ;; (displa `((mequal) auxeq ,ei))
157 (setq sol
($checkedalgsys
158 ($append ei
($substitute ei eqs
)) unks nz
))
159 (if ($listp sol
) (return-from bailout sol
))))
160 (t ($checkedalgsys
($append e-eqs eqs
) unks nz
))))
161 (t (return-from bailout
($checkedalgsys eqs unks nz
)))))))