File: mnewton.mac

package info (click to toggle)
maxima-sage 5.45.1-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, sid, trixie
  • size: 113,788 kB
  • sloc: lisp: 440,833; fortran: 14,665; perl: 14,369; tcl: 10,997; sh: 4,475; makefile: 2,520; ansic: 447; python: 262; xml: 59; awk: 37; sed: 17
file content (150 lines) | stat: -rw-r--r-- 5,295 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*  mnewton.mac v1.1 for Maxima (tested with Maxima 5.9.0).

Multiple nonlinear functions solution using the Newton method.

Usage:
  mnewton(FuncList, VarList, GuessList);
    FuncList  - list of functions to solve.
    VarList   - list of variable names.
    GuessList - list of initial approximations.

Flags:
  newtonepsilon
    default: [10.0^(-fpprec/2)] - precision to determine when the
    process has converged towards the solution. 
  newtonmaxiter
    default: [50] - maximum number of iterations to stop the process
    if this one does not converge or if it converges too much slowly.

Results:
  The solution is returned in the same format that SOLVE() returns.
  If the solution isn't found, [] is returned.

History:
  2003-11 Salvador Bosch Perez - version 1.0

--

Copyright (C) 2003  Salvador Bosch Perez

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

newtonepsilon:10.0^(-16/2)$ /* Default vaule is 10.0^-8 */
newtonmaxiter:50$
newtondebug:false$

solve_by_lu(eqs, vars, field) := block(
    [M, b, n : length(vars), sol],
    M : augcoefmatrix(eqs, vars),
    b : -col(M, n+1),
    M : submatrix(M, n+1),
    sol : linsolve_by_lu(M, b, field),
    map("=", vars, first(args(transpose(sol[1]))))
)$

mnewton(FuncList, VarList, GuessList):=
  block([nfunc, Solutions, Increments, solved:false, h, DF, numer:numer, extra_vars,
         i, j, k, keepfloat:true, ratprint:false, field : 'complexfield, float2bf : true],
    local(h),

    if (not(listp(FuncList))) then FuncList: [FuncList],    
    if (not(listp(VarList))) then VarList: [VarList],    
    if (not(listp(GuessList))) then GuessList: [GuessList],    

    /* Refuse to proceed if FuncList depends on some variable other than VarList.
     * Even in that case (which means that the result will just be an expression
     * containing any other variables), it is plausible that mnewton could carry
     * out a fixed number of iterations, but mnewton would have to reorganized
     * somewhat to implement that. For now require that FuncList depends only on VarList.
     */

    if (extra_vars: setdifference (setify (listofvars (FuncList)), setify (VarList))) # {}
      then (printf (true, "mnewton: extra variables in equations; found: ~{~a~^, ~}~%", extra_vars),
            return (false)),

    /* Decide which field to use */
    if bfloatp(newtonepsilon) then field : 'bigfloatfield,

    if field = 'bigfloatfield then
       FuncList : map(lambda([u], lhs(u)-rhs(u)), bfloat(FuncList))
    else (
       numer : true,
       FuncList : map(lambda([u], lhs(u)-rhs(u)), float(FuncList))),

    /* Depuration of the function arguments */   
    nfunc:length(FuncList),
    if length(VarList) # nfunc then (
      print("mnewton: incorrect number of variable names (", nfunc,
            "functions but", length(VarList), "variable names)."),
      return(false)
    ),
    if length(GuessList) # nfunc then (
      print("mnewton: incorrect number of approach values (", nfunc,
            "variables but", length(GuessList), "approximation values)."),
      return(false)
    ),
    /* apply(kill, VarList), */

    DF: zeromatrix (nfunc, nfunc),
    h : makelist (h[i], i, 1, nfunc),
    for i:1 thru nfunc do
      for j:1 thru nfunc do
        DF[i][j] : diff (FuncList[i], VarList[j]),  /* Jacobian matrix */

    if field = 'complexfield then
      GuessList: float (GuessList)
    else
      GuessList: bfloat(GuessList),
      
    if newtondebug
       then print ("DEBUG: initial GuessList:", GuessList),

    /* Solution of the functions system */
    for k:1 thru newtonmaxiter do (
      Solutions:map("=", VarList, GuessList),

      /* Solve 0 = F(x) + DF(x) h for h.
       */
      block
        ([DFx: subst (Solutions, DF),
        Fx: subst (Solutions, FuncList)],
        Increments: solve_by_lu (transpose (DFx . h + Fx)[1], h, field)),

      GuessList:GuessList + map ('rhs, Increments),
      if field = 'complexfield then
        GuessList: float (GuessList)
      else
        GuessList: bfloat(GuessList),

      if newtondebug
         then print ("DEBUG: Increments:", Increments, "GuessList:", GuessList),

      solved:true,
      for i:1 thru nfunc do
        solved: solved and abs (rhs (Increments[i])) < newtonepsilon,
      if solved then return(0)
    ),

    /* Return of solution or error */
    if solved = false then (
      print("mnewton: the process doesn't converge or it converges too slowly."),
      return([])
    ),
    Solutions:map("=", VarList, GuessList),
    if newtondebug
       then print ("DEBUG: subst (Solutions, FuncList) =>", subst (Solutions, FuncList)),
    return([Solutions])
  )$