~ubuntu-branches/ubuntu/karmic/maxima/karmic

« back to all changes in this revision

Viewing changes to share/contrib/diffequations/ode1_riccati.mac

  • Committer: Bazaar Package Importer
  • Author(s): Camm Maguire
  • Date: 2004-11-13 18:39:14 UTC
  • mto: (2.1.2 hoary) (3.2.1 sid) (1.1.5 upstream)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20041113183914-ttig0evwuatnqosl
Tags: upstream-5.9.1
ImportĀ upstreamĀ versionĀ 5.9.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ode1_riccati.mac 
 
2
 
 
3
  Attempt to solve Riccati ode y' = f2(x)*y^2+f1(x)*y+f0(x)
 
4
 
 
5
   References: 
 
6
 
 
7
   D Zwillinger, Handbook of Differential Equations, 3rd ed
 
8
   Academic Press, (1997), pp 354-355
 
9
   
 
10
   G M Murphy, Ordinary Differential Equations and Their 
 
11
   Solutions, Van Nostrand, 1960, pp 15-23
 
12
 
 
13
 
 
14
  Copyright (C) 2004  David Billinghurst
 
15
 
 
16
  This program is free software; you can redistribute it and/or modify
 
17
  it under the terms of the GNU General Public License as published by
 
18
  the Free Software Foundation; either version 2 of the License, or 
 
19
  (at your option) any later version. 
 
20
                                                                                 
 
21
  This program is distributed in the hope that it will be useful,
 
22
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
23
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
24
  GNU General Public License for more details.
 
25
                                                                                 
 
26
  You should have received a copy of the GNU General Public License     
 
27
  along with this program; if not, write to the Free Software            
 
28
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
29
*/
 
30
 
 
31
declare(method,special);
 
32
put('ode1_riccati,001,'version)$
 
33
 
 
34
ode1_riccati(eq,y,x) := block(
 
35
  [de,%a,f0,f1,f2,ans],
 
36
  de:expand(lhs(eq)-rhs(eq)),
 
37
  %a:coeff(de,'diff(y,x),1),
 
38
  if %a=0 then return(false),
 
39
  de:expand(de/%a),
 
40
  f2:-ratsimp(coeff(de,y,2)),
 
41
  if not(freeof(y,f2)) then return(false),
 
42
  if f2=0 then return(false),
 
43
  f1:-expand(ratsimp(coeff(de,y,1))),
 
44
  if not(freeof(y,f1)) then return(false),
 
45
  f0:-expand(ratsimp(de-'diff(y,x)+f2*y^2+f1*y)),
 
46
  if not(freeof(y,f0)) then 
 
47
    return(false),
 
48
  if not(is(ratsimp(expand(de-'diff(y,x)+f2*y^2+f1*y+f0))=0)) then 
 
49
    return(false),
 
50
 
 
51
  ode_disp("      is Ricatti equation"),
 
52
  ode_disp2("       f0: ",f0),
 
53
  ode_disp2("       f1: ",f1),
 
54
  ode_disp2("       f2: ",f2),
 
55
 
 
56
  /* Following Murphy, (3-1, p15) see if the equation has the form
 
57
     of the original equation studied by Riccati
 
58
 
 
59
      y' + b*y^2 = c*x^m
 
60
   
 
61
      => f1 = 0
 
62
         b:-f2(x) is constant
 
63
         f0 = c*x^m
 
64
  */
 
65
  ans: block(
 
66
    [b,c,m],
 
67
    if ( f1#0 ) then return(false),
 
68
    if (not freeof(x,f2) ) then return(false),
 
69
    b:-f2,
 
70
    m:hipow(f0,x),
 
71
    c:coeff(f0,x,m),
 
72
    if ( ratsimp(f0-c*x^m)#0 ) then return(false),
 
73
    ode_disp("      equation is original Riccati equation"),
 
74
    ode1_riccati_original(b,c,m,y,x)
 
75
  ),
 
76
  if ( ans#false ) then (
 
77
    method:'RICCATI,
 
78
    return(ans)
 
79
  ),
 
80
 
 
81
  /* Perhaps it has the special form Murphy (3-3, p21-22)
 
82
 
 
83
     x*y' -a*y + b*y^2 = c*x^n
 
84
 
 
85
     => a: f1(x)*x  constant
 
86
        b:-f2(x)*x  constant
 
87
        f0 = c*x^(n-1) 
 
88
  */
 
89
  ans: block(
 
90
    [a,b,c,m,n],
 
91
    if ( not freeof(x,a:ratsimp( f1*x)) ) then return(false),
 
92
    if ( not freeof(x,b:ratsimp(-f2*x)) ) then return(false),
 
93
    m:hipow(f0,x),
 
94
    c:coeff(f0,x,m),
 
95
    /* May want to check c and m */
 
96
    if ( is(ratsimp(f0-c*x^m)#0) ) then return(false),
 
97
    n:m+1,
 
98
    ode_disp("      equation is special Riccati equation"),
 
99
    ode1_riccati_special(a,b,c,n,y,x)
 
100
  ),
 
101
  if ( ans#false ) then (
 
102
    method:'RICCATI,
 
103
    return(ans)
 
104
  ),
 
105
 
 
106
  /* The equation doesn't have a special form, so it is a general
 
107
     Riccati equation.
 
108
  */
 
109
  ans:ode1_riccati_general(f0,f1,f2,y,x),
 
110
  if ( ans#false ) then (
 
111
    method:'RICCATI,
 
112
    return(ans)
 
113
  ),
 
114
 
 
115
  /* Default return value */
 
116
  false
 
117
)$
 
118
 
 
119
/* Solve the original Riccati equation y' + b*y^2 = c*x^m
 
120
   Murphy (3-2, p20-21)
 
121
*/
 
122
ode1_riccati_original(b,c,m,y,x) := block(
 
123
  [ans,k,w,s,i],
 
124
  ode_disp("    -> In ode1_riccati_original"),
 
125
  ode_disp2("       b: ",b),
 
126
  ode_disp2("       c: ",c),
 
127
  ode_disp2("       m: ",m),
 
128
 
 
129
  /* Solve  m*(2*k+1)+4*k=0  =>  k= m/(2*m+4)
 
130
  
 
131
  If k is an integer then the equation is integrable
 
132
  in finite terms.
 
133
 
 
134
  The solution is then found using the transformation y = w/x, giving
 
135
 
 
136
    x*w'(x)-w+b*w^2=c*x^(m+2)
 
137
 
 
138
  which is the special Riccati equation with a=1 and n=m+2
 
139
  */
 
140
  if ( not(equal(m,-2)) and integerp(k:m/(2*m+4)) ) then (
 
141
    ode_disp("       Equation is integrable in finite terms"),
 
142
    ode_disp("       Transforming using y=w/x and calling ode1_riccati_special"),
 
143
    ans:ode1_riccati_special(1,b,c,m+2,w,x),
 
144
    ode_disp2("      Solution to transformed equation is ",ans),
 
145
    return(y=ratsimp(rhs(ans)/x))
 
146
  )
 
147
  else (
 
148
    ode1_riccati_original_not_integrable(b,c,m,y,x)
 
149
  )
 
150
)$
 
151
 
 
152
/* Solve the original Riccati equation y' + b*y^2 = c*x^m 
 
153
   for cases not integrable in finite terms
 
154
*/
 
155
ode1_riccati_original_not_integrable(b,c,m,y,x) := block(
 
156
  if is(equal(m,-2)) then
 
157
    ode1_riccati_original_2(b,c,y,x)
 
158
  else
 
159
    ode1_riccati_original_3(b,c,m,y,x)
 
160
)$
 
161
 
 
162
/* Solve the original Riccati equation y' + b*y^2 = c*x^-2
 
163
    - Transform to second order linear ode, Murphy (3-2c, p20-21)
 
164
    - Solve using Murphy A3-250
 
165
*/
 
166
ode1_riccati_original_2(b,c,y,x) := block(
 
167
  [a:-b*c,r,r2,%c],
 
168
  ode_disp("    -> In ode1_riccati_original_2"),
 
169
  ode_disp("       Original Riccati equation with m=-2"),
 
170
  ode_disp2("       b: ",b),
 
171
  ode_disp2("       c: ",c),
 
172
  ode_disp2("       a: ",a),
 
173
 
 
174
  /* Let b*y*u(x)=u'(x) so that ode becomes
 
175
 
 
176
       u''(x) - b*c*x^-2*u(x) = 0
 
177
 
 
178
     NOTE: Murphy (p21) has sign of second term wrong.
 
179
  */
 
180
  r2:a-1/4,
 
181
  ode_disp2("       r2: ",r2),
 
182
 
 
183
  if is(r2>0) then (
 
184
    /* Murphy A3-250-i */
 
185
    ode_disp("       Case i:   r2>0"),
 
186
    r:sqrt(r2),
 
187
    ode_disp2("       r: ",r),
 
188
    u:sqrt(x)*(cos(r*log(x))+%c*sin(r*log(x)))
 
189
  )
 
190
  else if (r2<0) then (
 
191
    /* Murphy A3-250-ii  */
 
192
    ode_disp("       Case ii:  r2<0"),
 
193
    r:sqrt(-r2), /* typo in Murphy: missing "-" */
 
194
    ode_disp2("       r: ",r),
 
195
    u:sqrt(x)*(x^r+%c*x^-r)
 
196
  )
 
197
  else if is(equal(r2,0)) then (
 
198
   /* Murphy A3-250-iii */
 
199
    ode_disp("       Case iii: r2=0"),
 
200
    u:sqrt(x)*(1+%c*log(x))
 
201
  )
 
202
  else (
 
203
    error("ode1_riccati_original_2: Impossible case")
 
204
  ),
 
205
  ode_disp2("       u: ",u),
 
206
  return(y=ratsimp(diff(u,x)/(b*u)))
 
207
)$
 
208
 
 
209
/* Solve the original Riccati equation y' + b*y^2 = c*x^m for m#-2
 
210
    - Transform to second order linear ode, Murphy (3-2c, p20-21)
 
211
    - Solve using Murphy A3-41
 
212
*/
 
213
ode1_riccati_original_3(b,c,m,y,x) := block(
 
214
  [p:m+2,n:1/(m+2),%c,u,signb,signc],
 
215
  ode_disp("    -> In ode1_riccati_original_3"),
 
216
  ode_disp("       Original Riccati equation with m#-2"),
 
217
  ode_disp2("       b: ",b),
 
218
  ode_disp2("       c: ",c),
 
219
  ode_disp2("       m: ",m),
 
220
  ode_disp2("       p: ",p),
 
221
  ode_disp2("       n: ",n),
 
222
 
 
223
  /* Let b*y*u(x)=u'(x) so that ode becomes
 
224
 
 
225
       u''(x) - b*c*x^m*u(x) = 0
 
226
 
 
227
     NOTE: Murphy (p21) has sign of second term wrong.
 
228
 
 
229
     Solution expressed in terms of Bessel functions of order n.
 
230
  */
 
231
  signb:asksign(b),
 
232
  signc:asksign(c),
 
233
 
 
234
  /* b*c<0 */
 
235
  if ( (signb='pos and signc='neg) or (signb='neg and signc='pos) ) then
 
236
    if integerp(n) then (
 
237
      u: sqrt(x)*(bessel_j(n,2*sqrt(-b*c)*x^(p/2)/p)
 
238
             + %c*bessel_y(n,2*sqrt(-b*c)*x^(p/2)/p) )
 
239
    ) else (
 
240
      u: sqrt(x)*(bessel_j(n,2*sqrt(-b*c)*x^(p/2)/p)
 
241
             + %c*bessel_j(-n,2*sqrt(-b*c)*x^(p/2)/p) )
 
242
    )
 
243
  else if ((signb='pos and signc='pos) or (signb='neg and signc='neg)) then
 
244
    if integerp(n) then (
 
245
      u: sqrt(x)*(bessel_i(n,2*sqrt(b*c)*x^(p/2)/p)
 
246
             + %c*bessel_k(n,2*sqrt(b*c)*x^(p/2)/p) )
 
247
    ) else (
 
248
      u: sqrt(x)*(bessel_i(n,2*sqrt(b*c)*x^(p/2)/p)
 
249
             + %c*bessel_k(-n,2*sqrt(b*c)*x^(p/2)/p) )
 
250
    )
 
251
  else
 
252
    /* b and c are non-zero constants, so this is an error */
 
253
    error("ode_riccati_original_3:  Impossible case has just happened"),
 
254
  return(y=ratsimp(diff(u,x)/(b*u)))
 
255
)$
 
256
 
 
257
/* Solve the special Riccati equation x*y' -a*y + b*y^2 = c*x^n
 
258
   Murphy (3-3, p21-22) 
 
259
*/
 
260
ode1_riccati_special(a,b,c,n,y,x) := block(
 
261
  [k,s,u,%c,signb,signc],
 
262
  ode_disp("    -> In ode1_riccati_special"),
 
263
  ode_disp2("       a: ",a),
 
264
  ode_disp2("       b: ",b),
 
265
  ode_disp2("       c: ",c),
 
266
  ode_disp2("       n: ",n),
 
267
 
 
268
  /* Certain cases are integrable. */
 
269
 
 
270
  /* Case (a.i). n=2*a
 
271
     Equation can be made exact using integrating factor x^(a-1)
 
272
     and integrated 
 
273
   */
 
274
  if ( is(equal(n,2*a)) ) then (
 
275
     ode_disp("      Case (a.i)"),
 
276
     return(ode1_riccati_special_i(a,b,c,n,y,x))
 
277
  )
 
278
 
 
279
  /* Case (a.ii) (n-2*a)/(2*n) a positive integer */
 
280
  else if ( n#0 and integerp(k:(n-2*a)/(2*n)) and k>0 ) then (
 
281
    ode_disp2("      Case (a.ii) with k = ",k),
 
282
    if oddp(k) then
 
283
      s:rhs(ode1_riccati_special_i(n/2,c,b,n,y,x)) 
 
284
    else
 
285
      s:rhs(ode1_riccati_special_i(n/2,b,c,n,y,x)),
 
286
    for i:(k-1) thru 1 step -1 do (
 
287
      if oddp(i) then
 
288
        s:(a+i*n)/c+x^n/s
 
289
      else
 
290
        s:(a+i*n)/b+x^n/s 
 
291
    ),
 
292
    return(y=a/b+x^n/s)
 
293
  )
 
294
 
 
295
  /* Case (a.iii) (n+2*a)/(2*n) a positive integer */
 
296
  else if ( n#0 and integerp(k:(n+2*a)/(2*n)) and k>0 ) then (
 
297
    ode_disp2("      Case (a.iii) with k = ",k),
 
298
    if oddp(k) then
 
299
      s:rhs(ode1_riccati_special_i(n/2,c,b,n,y,x))
 
300
    else
 
301
      s:rhs(ode1_riccati_special_i(n/2,b,c,n,y,x)),
 
302
    for i:(k-1) thru 1 step -1 do (
 
303
      if oddp(i) then
 
304
        s:(i*n-a)/c+x^n/s
 
305
      else
 
306
        s:(i*n-a)/b+x^n/s 
 
307
    ),
 
308
    return(y=x^n/s)
 
309
  )
 
310
 
 
311
  /* Not integrable in finite terms.  For a=0 we have
 
312
     x*y' + b*y^2 = c*x^n
 
313
 
 
314
     Let y = x*u'(x)/(b*u(x)) => x^2*u'' + x*u' - b*c*x^n*u = 0
 
315
 
 
316
     This is Murphy A3.202 or Abramowitz and Stegun 9.1.53
 
317
  */
 
318
  else if is(equal(a,0)) then (
 
319
    /* Can never have n=0 so division is always safe */
 
320
    ode_disp("      Case (c.i)"),
 
321
    signb:asksign(b),
 
322
    signc:asksign(c),
 
323
 
 
324
    /* b*c<0 */
 
325
    if ( (signb='pos and signc='neg) or (signb='neg and signc='pos) ) then
 
326
      u:    bessel_j(0,2*sqrt(-b*c)*x^(n/2)/n) 
 
327
       + %c*bessel_y(0,2*sqrt(-b*c)*x^(n/2)/n)
 
328
    /* b*c>0 */
 
329
    else if ((signb='pos and signc='pos) or (signb='neg and signc='neg)) then
 
330
      u:    bessel_i(0,2*sqrt(b*c)*x^(n/2)/n) 
 
331
       + %c*bessel_k(0,2*sqrt(b*c)*x^(n/2)/n)
 
332
    else
 
333
      /* b and c are non-zero constants, so this is an error */
 
334
      error("ode_riccati_special:  Impossible case has just happened"),
 
335
   
 
336
    return(y=ratsimp(x*diff(u,x)/(b*u)))
 
337
  )
 
338
  /*   For a#0, transform using y=z*u(z) with z=x^a
 
339
     to give u' + (b/a)*u^2 = (c/a)*z^((n-2*a)/a)
 
340
     which is the original Riccati equation
 
341
  */
 
342
  else (
 
343
    ode_disp("      Case (c.ii)"),
 
344
    s:ode1_riccati_original_not_integrable(b/a,c/a,(n-2*a)/a,u,z),
 
345
    ode_disp2("      Solution of transformed eqn is ",s),
 
346
    return(y=ratsimp(subst(x^a,z,z*rhs(s))))
 
347
  )
 
348
)$
 
349
 
 
350
/* Solve the special Riccati equation x*y' -a*y + b*y^2 = c*x^n
 
351
   for the case n=2*a.  Murphy (3-3, p21-22).
 
352
 
 
353
   Note: Signs changed from Murphy in cases a.i.1 and a.i.3.
 
354
*/
 
355
ode1_riccati_special_i(a,b,c,n,y,x) := block(
 
356
  [%c,signb,signc],
 
357
  ode_disp("    -> In ode1_riccati_special_i"),
 
358
  ode_disp2("       a: ",a),
 
359
  ode_disp2("       b: ",b),
 
360
  ode_disp2("       c: ",c),
 
361
  ode_disp2("       n: ",n),
 
362
 
 
363
  if not(equal(n,2*a)) then error("ode1_riccati_special_i: n#2*a"),
 
364
 
 
365
  /* Case (a.i). n=2*a
 
366
     Equation can be made exact using integrating factor x^(a-1)
 
367
     and integrated to give solution(s) below. 
 
368
   */
 
369
  signb:asksign(b),
 
370
  signc:asksign(c),
 
371
  /* b*c > 0 */
 
372
  if ( signb='pos and signc='pos ) then (
 
373
    /* Murphy has the sign of the solution wrong  */
 
374
    ode_disp("      Case (a.i.1) b*c>0, b>0 and c>0"),
 
375
    return(y=sqrt(c/b)*x^a*tanh(sqrt(b*c)*x^a/a+%c))
 
376
  ) 
 
377
  else if ( signb='neg and signc='neg ) then (
 
378
    ode_disp("      Case (a.i.2) b*c>0, b<0 and c<0"),
 
379
    return(y=sqrt(c/b)*x^a*tanh(%c-sqrt(b*c)*x^a/a))
 
380
  )
 
381
  /* b*c < 0 */
 
382
  else if ( signb='pos and signc='neg ) then (
 
383
    ode_disp("      Case (a.i.3) b*c<0, b>0 and c<0"),
 
384
    return(y=sqrt(-c/b)*x^a*tan(%c-sqrt(-b*c)*x^a/a))
 
385
  ) 
 
386
  else if ( signb='neg and signc='pos ) then (
 
387
    ode_disp("      Case (a.i.4) b*c<0, b<0 and c>0"),
 
388
    /* Murphy has the sign of the solution wrong */
 
389
    return(y=sqrt(-c/b)*x^a*tan(sqrt(-b*c)*x^a/a+%c))
 
390
  ),
 
391
 
 
392
  /* b and c are non-zero constants, so this is an error */
 
393
  error("ode_riccati_special_i:  Impossible case has just happened")
 
394
)$
 
395
 
 
396
/* The equation doesn't have a special form, so it is a generalized
 
397
     Riccati equation.  Try transforming it to a linear second order
 
398
     ode.
 
399
 
 
400
   Substitute y = -z'/(z*f2)
 
401
 
 
402
     => f2*z''-(f2'+f1*f2)z'+f2^2*f0*z=0
 
403
 
 
404
   Solve this second order linear ode for z.  The solution has form 
 
405
   z=%k1*f+%k2*g, with two constants, but a first order ode only has 
 
406
   one constant %c.  Without loss of generality take %k1=1 and %k2=%c
 
407
 
 
408
     y = -z'/(z*f2) = -(f'+%c*g')/((f+%c*g)*f2)
 
409
  */
 
410
ode1_riccati_general(f0,f1,f2,y,x) := block(
 
411
  [de,z,ans,%c,%k1,%k2],
 
412
  ode_disp("    Transforming to 2nd order ode"),
 
413
  de: f2*'diff(z,x,2)-(diff(f2,x)+f1*f2)*'diff(z,x)+f2^2*f0*z=0,
 
414
  if get('contrib_ode,'verbose) then disp(de),
 
415
 
 
416
  ans:contrib_ode(de,z,x),
 
417
  ode_disp("    with solution"),
 
418
  if get('contrib_ode,'verbose) then disp(ans),
 
419
 
 
420
  if is(ans=false) then (
 
421
    ode_disp("    Cannot solve 2nd order ode"),
 
422
    false
 
423
  )
 
424
  else if (lhs(ans[1])#z) then (
 
425
    /* give up on parametric solutions for z */
 
426
    ode_disp("    2nd order ode has parametric solution"),
 
427
    ode_disp("    giving up"),
 
428
    false
 
429
  )
 
430
  else (
 
431
    ode_disp("    solution found"),
 
432
    method:'RICCATI,
 
433
    ans:rhs(ans[1]), ans:subst(1,%K1,ans), ans:subst(%C,%K2,ans),
 
434
    return(y=ratsimp(-diff(ans,x)/(ans*f2)))
 
435
  )
 
436
)$