Carl Love

Carl Love

27306 Reputation

25 Badges

11 years, 364 days
Himself
Wayland, Massachusetts, United States
My name was formerly Carl Devore.

MaplePrimes Activity


These are answers submitted by Carl Love

To get a Crout decomposition, first get a standard LUDecomposition of the transpose of the coefficient matrix, then transpose each of the returned matrices, then reverse the order that they are multiplied. Although that may seem like a lot of steps, it can all be done in one short command in Maple:

restart:

Eqs:= [4*x+y+z=4, x+4*y-2*z=4, 3*x+2*y-4*z=6]:

(A,B):= LinearAlgebra:-GenerateMatrix(Eqs, [x,y,z]):

(P,L,U):= LinearAlgebra:-LUDecomposition(A^%T, output= ['P','U','L'])^~%T;

P, L, U := Matrix(3, 3, {(1, 1) = 1, (1, 2) = 0, (1, 3) = 0, (2, 1) = 0, (2, 2) = 1, (2, 3) = 0, (3, 1) = 0, (3, 2) = 0, (3, 3) = 1}), Matrix(3, 3, {(1, 1) = 4, (1, 2) = 0, (1, 3) = 0, (2, 1) = 1, (2, 2) = 15/4, (2, 3) = 0, (3, 1) = 3, (3, 2) = 5/4, (3, 3) = -4}), Matrix(3, 3, {(1, 1) = 1, (1, 2) = 1/4, (1, 3) = 1/4, (2, 1) = 0, (2, 2) = 1, (2, 3) = -3/5, (3, 1) = 0, (3, 2) = 0, (3, 3) = 1})

L.U.P - A;

Matrix(3, 3, {(1, 1) = 0, (1, 2) = 0, (1, 3) = 0, (2, 1) = 0, (2, 2) = 0, (2, 3) = 0, (3, 1) = 0, (3, 2) = 0, (3, 3) = 0})

 

Download Crout.mw

Note the order specified in the output option: ['P', 'U', 'L'] rather than the usual ['P', 'L', 'U'].

You are trying to solve 2 equations for 1 variable. It's not usually possible to get an unconditional solution when there are more equations than variables being solved for. Here are 2 options:

  • Add a 2nd variable (of your choice) to solve for,
  • Accept a conditional solution.

To add a second variable (for example, Clm):

solve({tau = `τopt`, lambda = `λopt`}, {w, Clm})

To get a possibly conditional solution, use eliminate instead of solve:

eliminate({tau = `τopt`, `λopt` = lambdaopt}, {w})

The return will be a list of two sets. The first set is the solution(s) for w (only one in this case). The second set is expressions (only one in this case) that must equal 0 in order for the first set to be valid.

You've made a quite interesting discovery (Vote up): Overloads in modules don't explicitly have option overload, although they do otherwise contain the correct programmatic structure of an overload. So, the workaround for your procedure Isee is to explicily insert option overload when that's needed, like this:

Isee:= proc(a::procedure)
local vp:= interface('verboseproc'= 3), p:= eval(a);
    if op([5,1], ToInert(eval(a)))::specfunc(_Inert_OVERLOADLIST) then
        p:= subsop(3= overload, eval(a))  #op(3,a) is the explicit options
    fi;
    printf("%P", eval(p));
    interface('verboseproc'= vp);
    return
end proc:

 

There are several things that I did to make your double and quadruple summations faster. The most important and the most obvious is that any factor in a sum that doesn't depend on the summation variable should be factored out. Otherwise, those binomials (and other things) get recomputed many times,. Some other tricks:

  1. GAMMA(s1+h+1)/(GAMMA(s1+1)*h!) = binomial(s1+h, h), even when s1 isn't an integer.
  2. All necessary binomials can be pre-computed once, via very simple recursive formulae:
    [1, seq[scan= `*`]((n+1)/k - 1, k= 1..n)] generates the sequence binomial(n,k) $ k= 0..n (i.e., the entire (n+1)st row of Pascal's triangle). By changing the order of subtraction to 1 - (n+1)/k, we generate (-1)^k*binomial(n,k).
    [1, seq[scan= `*`](1 + s/k, k= 1..upto)] generates binomial(s+k, k) $ k= 0..upto.
  3. (beta1 - 1)^h*(-1)^h = (1 - beta1)^h, and of course this is trivial to generate recursively.
  4. The additions of fixed terms in the denominators can be pre-computed:
    e.g.DL:= x+y + b1*(s1+h) + b2*(s2+v).
  5. The undocumented command inner(A, B) computes the inner (or "dot") product of two lists of equal length; i.e.inner(A,B) = add(A*~B) = sum(A[k]*B[k], k= 1..nops(A)).
  6. The updating assignment operators +=*=, and ++ work exactly the same as they do in the numerous other languages that have them:
    S+= a  <=>  S:= S+a
    B*= k  <=>  B:= B*k
    d++  
    <=>  (d+= 1) - 1, i.e., it increments d and returns the pre-incremented value,

Here is my worksheet with all my improvements and verifications that my methods give the same results as @dharr.

 

restart:

n1:= 423: x:= 16: n2:= 81: y:= 35: s1:= 1/10: b1:= 7: beta1:= 21/10: s2:= 1/10: b2:= 7:
beta2 := 21/10:

First I verify that my simplifications produce the same results as @dharr:

A:= proc(h,v,r)
local
    L, j, S:= 0, n1x:= n1-x+1, n2y:= n2-y+1, Ls:= [$0..n2y-1],
    Dj:= r + x + b1*(s1+v), DL:= x+y + b1*(s1+h) + b2*(s2+v),
    BL:= [1, seq['scan'= `*`](1-n2y/L, L= 1..n2y-1)], Bj:= 1
;
    for j to n1x do
        S+= inner(BL, 1/~(DL++ +~ Ls))*Bj/Dj++;
        Bj*= 1 - n1x/j
    od;
    S*binomial(s1+h, h)*binomial(s2+v, v)*(1-beta1)^h*(1-beta2)^v
end proc
:

CodeTools:-Usage(A(2,2,0));

memory used=7.72MiB, alloc change=0 bytes, cpu time=0ns, real time=33.00ms, gc time=0ns

11727199469241514779864393729287999595266717038898384405454822453889989726964576758757729551099323484694782170822448350244634045448648056150840927233527350118380124119264858615283201523602923810903830006171445640638533014964609388484372553536841310967853824558690932280088151544584971199415788181111551306532754880119508566210291084045598562471540440317095151211911113829813243986384020095260781211101363284506805774438303489939264952762167438202379620004245323297602579179457497328410039101743209644168235298998961095392278935981336337925654946855818892100272459692432824817768478928223155226897063053135874218725475831316965225841532156062303907670391646481346412180543470550738955412983380825233032396184376956505282354537912590976013025195012646732190615857238658037431378033943474292755126953125/6382265268317256219633710058998499818340873590563036702803822950484199699636302738462052037083809489945501654638778705432982835407262106422716055822223400225220629848888603203921980303115472012139298206087469920885254016501522878034151924440738350864243996392880003254552368644323922787997879524243559004914030851003740366052093558872264913393738584398643237741388376227019971696955206515106578177861348809414199987981935214749218771677333981945489142846776730080142869549055976924435701756372241817375336920507491648219754129346141714754707551648893025832772408084923821700316568058764587634659823042662378587917652228685077432247136823506786967161644710468316981814899035776299987989971099597861998466613316946045883428522261542320902882571202585668513207901611181230727412654811333329187224660577277205763279177427978308304241574151519438327049907892296647014672715620294656

evalf(%);

0.1837466632e-77

f:= (r, upto)->
local
    h, v, j, L, n1x:= n1-x+1, n2y:= n2-y+1, Ls:= [$0..n2y-1], js:= [$0..n1x-1],
    BL:= [1, seq['scan'= `*`](1-n2y/L, L= 1..n2y-1)],
    Bj:= [1, seq['scan'= `*`](1-n1x/j, j= 1..n1x-1)],
    Beta1:= 1-beta1, Beta2:= 1-beta2,
    Bs1:= [1, seq['scan'= `*`](1+s1/h, h= 1..upto)],
    Bs2:= [1, seq['scan'= `*`](1+s2/h, h= 1..upto)],
    B1:= [1, seq['scan'= `*`](Beta1, h= 1..upto)],
    B2:= [1, seq['scan'= `*`](Beta2, h= 1..upto)],
    A0:= (h,v,r)->
    local j, Dj:= r + x + b1*(s1+v), DL:= x+y + b1*(s1+h) + b2*(s2+v);
        add(inner(BL, 1/~(DL++ +~ Ls))*Bj[j]/Dj++, j= 1..n1x),
    B0:= (h,v,r)->
    local L, DL:= y - r + b2*(s2+h), Dj:= x+y + b2*(s2+h) + b1*(s1+v);
        add(inner(Bj, 1/~(Dj++ +~ js))*BL[L]/DL++, L= 1..n2y)
;
    add(Bs1[h]*B1[h]*add(A0(h-1,v-1,r)*Bs2[v]*B2[v], v= 1..upto+1), h= 1..upto+1)
    +
    add(Bs1[v]*B1[v]*add(B0(h-1,v-1,r)*Bs2[h]*B2[h], h= 1..upto+1), v= 1..upto+1)
:

CodeTools:-Usage(f(0,12));

memory used=3.80GiB, alloc change=0 bytes, cpu time=1.92s, real time=6.81s, gc time=531.25ms

114249022902597666588491400529505235216742049616231180869631619194167698464302221521109360278934161699249264126826236228253701293270492644550135177145016349814982113455183820820735876815796463679992519208283503642450130209375877055834771405738601458875577451563602032933837943025767731232207854934759236939341322568521090401156938484109405395425106996068885180201446511126644125409694777192264543924174126949778005106553840262917702653247531868774015140088404720078587672388076732410686714770939922375245824000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000/4478112673625161634402912271274057087521425782459964471363322850631457597742398047074088546911131451856756368982860023346654177624065136219112870362974132591633772922976976016146648645581986021657025573763585023497503972196876316120665545360282282680322522472194461718178716824852465782992306776138047404097571796261065850414338472933710797700189622470162561730240651195333635833352277583626670180879730361251512986788399320104862652482661166302364468264845833967133426250993316566352774199352462247496894848151055424852777184106477710417868463737767180212637570654326336497085984319988974445914462490654328034321182352155451367268612522705340661230039301539950445376032066380305314154637436491880112866704742279027028488977660000585169277423676424285496535951865146024850581707926633898571343437487693846692653268159361127272552016275556640003360341921899571661034103268149587939236207824679329125781964757872174171342424591595209864084608515982176191174973912465653082613424079377178453298484585210385316658608895204147668705453968995722653400843313999068483592478297363991

evalf(%);

0.2551276201e-55

CodeTools:-Usage(f(0,30)):

memory used=22.50GiB, alloc change=0 bytes, cpu time=9.80s, real time=40.99s, gc time=3.25s

evalf(%);

0.2551276201e-55

 

The terms from 13 to 30 were too small to make any difference.

Download FasterQuadrupleSum.mw

You wrote:

  • The combine function applies transformations which combine terms in sums,...

Unfortunately, that is just the most simplistic purpose of combine. In my mind, the primary purpose of combine is to make function arguments more complicated (such as changing func1(x) to func2(2*x)); expand does the reverse, changing 2*x to x. The could be replaced by any integer.

This has always seemed intuitively clear to me, and I never use a menu to do something that can be done with a typed command. Perhaps those two things are related to each other.

You simply need to use Typesetting:-Typeset in the plot option:

labels= [y(x), Typesetting:-Typeset(diff(y(x),x))]

To get a decimal version of the real value of a, use

evalf(a[1])

instead of your eval(a[1]). The f in evalf stands for floating-point. A more straightforward alternative is to replace your solve command with fsolve:

fsolve(period_eqn, a)
             
 8058.994329

There is no problem with Maple itself here. The problem is only with MaplePrimes's ability to display the worksheet inline. Downloading the worksheet link produces exactly the file that you uploaded.

Here, I've downloaded, executed, and re-uploaded your worksheet. If you download this link, I think you'll see that it's equivalent to your original:

Download predator_prey.mw

First, I'll compactify the code that produces your static plot, and I'll add hooks for controlling the parameters with more finesse. In particular, note the parameters option to dsolve and the solitary call to numsols with the parameters option:

restart:
vars:= [w, x, y, z]:
sys:= {
    diff~(vars(t), t)[]=~ ((y*z)(t), a*w(t), (x*z + w)(t), (-x*y)(t)),
    (vars(0)=~ vars||~0)[]
}:
params:= [a, w0, x0, y0, z0]:
param_vals:= [2, -0.727367040, -0.728244724, -0.237753623, 0.014225402]:
numsol:= dsolve(sys, numeric, method= rkf45, 'parameters'= params):
col:= [red, magenta, cyan, blue]:
numsol('parameters'= param_vals):
plots:-odeplot(
    numsol, `[]`~(t, vars(t)), t= 0..3, color= col, legend= vars(t)
):


The next step is to abstract that into a procedure that produces that static plot for given parameter values:

OnePlot:= proc(param_vals, tf)
    numsol('parameters'= param_vals);
    plots:-odeplot(
        numsol, `[]`~(t, vars(t)), t= 0..tf, 'color'= col, 'legend'= vars(t)
    )
end proc
: 


And finally the Explore:

Explore(
    OnePlot(params, tf),
    'parameters'= [(params[], tf)=~ (1. .. 3., (-1. .. 0.) $ 3, 0. .. 1., 3. .. 9.)],
    'initialvalues'= [(params[], tf)=~ (param_vals[], 3)]
);

 

Like this:

seq(cat("%15s" $ k), k= 1..4);

To continue, you need to say what mathematically makes the difference between solid and dashed lines.

params:= {
    h= piecewise(
        z <= d+1,   1,
        z <= d+4,   1-delta/2*(1 + cos(2*Pi*(z - 1 - 1/2))),
        z <= d+6,   1 
    ),
    w0= -c*h^2/4 + 3/64*(b*c-4*a)*h^4 + 19/2304*b*(b-4*a)*h^6,
    w1= c/4 + (4*a-b*c)*h^2/16,
    w2= (4*(b*c-4*a)-b*h^2)/256,
    w3= b*(b-4*a)/2304,
    a= x4*S*Gr*sin(alpha)/(4*x1*x5),
    b= 1/Da + x3*M/(x1*(1+m^2)),
    c= Dp/x1,
    Dp= 96*x1/((6-b*h^2)*h^4)*(F + a*h/24 - 11/6144*b*(b-4*a)*h^8),
    x1= ((1-phi1)*(1-phi2))^(-5/2),
    x2= (1-phi2)*(1 - phi1 + phi1*Rs1/Rf) + phi2*Rs2/Rf,
    x3= shnf/sf,
    x4= (1-phi2)*(1 - phi1 + phi1*RBs1/RBf) + phi2*RBs2/RBf,
    x5= khnf/kf,
    shnf= sbf*(ss2+2*sbf-2*phi2*(sbf-ss2))/(ss2+2*sbf+phi2*(sbf-ss2)),
    sbf= sf*(ss1+2*sf-2*phi1*(sf-ss1))/(ss1+2*sf+phi1*(sf-ss1)),
    khnf= kbf*(ks2+2*kbf-2*phi2*(kbf-ks2))/(ks2+2*kbf+phi2*(kbf-ks2)),
    kbf= kf*(ks1+2*kf-2*phi1*(kf-ks1))/(ks1+2*kf+phi1*(kf-ks1)),
    RBs1= 8933*16.7e6,
    RBf= 1063*1.8e6,
    RBs2= 6320*18e6,
    kf= 0.492,
    sbf= 6.67e-1, ss2= 2.7e-8,
    sf= 6.67e-1, ss1= 59.6e6,
    ks2= 76.5, kf= 0.492, ks1= 401,
    phi1= 0.01, phi2= 0.02, alpha= Pi/4, m= 0.5, Da= 0.1, Gr= 5, 
    delta= 1, S= 0.5,  d= 1,
    F= 1, z= 1
}:
                                      
W1:= eval[recurse](w0+w1*r^2+w2*r^4+w3*r^6, params):

plot(
    eval~(W1, M=~ [2, 5, 7]), r= 0..1,
    color= [red, blue, green], axes= boxed,
    legend= typeset~(M^2=~ [2,5,7]),
    labels= [r, w(r,1)], labeldirections= [horizontal, vertical],
    axesfont= [helvetica, 16], labelfont= [helvetica, 16],
    caption= typeset(
        ``(seq(v = eval[recurse](v, params), v= (m, Da, Gr, S, alpha, phi1, phi2)))
    )
);

If I translate your f into 1D-input, it becomes this:

f:= (u[1], u[2])-> u[1]^2*diff(u[2], x);

It's simply a nuance of Maple syntax that indexed variables such as u[1] are not allowed to be formal parameters of procedures. There is a simple fix that allows the variables to still display as subscripted:

f:= (u__1, u__2)-> u__1^2*diff(u__2, x);

c__1 is an alias. Aliases are very different from ordinary variables (and I think it was a bad design choice to use them for dsolve). One of the weird things about aliases is that if they are used in a procedure, they must be defined before the procedure is defined, whereas an ordinary global variable only needs to be defined before the procedure is called. To verify this, re-enter the definition of foo (without restart), and re-call foo (shown below). Also shown below is a safer way to code foo by being agnostic about what the constant will be.

Your Example 2 Question: Solving for _C1 works, even though the ode has c__1 , why?

Because _C1 is an ordinary global variable, not an alias. c__1 is an alias for _C1. To see this:

_C1;
                       c__1

Your Example 3 Question: Forcing arbitraryconstants = subscripted it still does not work inside proc. Why?

c__1 is still an alias. The weird interaction between aliases and procedures supercedes everything else.

 

Example (1) (modified) solving for constant of integration fails inside proc but works outside

 

restart;

foo:=proc(ode::`=`)
local sol,the_constant;
   sol:=dsolve(ode);
   print("sol is ",sol);
   the_constant:=solve(sol,c__1);
   print("the constant is ",the_constant);
end proc
:

#this does not work
ode:=diff(y(x),x) = 3/4*y(x)/x;
foo(ode)

diff(y(x), x) = (3/4)*y(x)/x

"sol is ", y(x) = c__1*x^(3/4)

"the constant is "

#this works
ode:=diff(y(x),x) = 3/4*y(x)/x;
sol:=dsolve(ode);
print("sol is ",sol);
the_constant:=solve(sol,c__1);

diff(y(x), x) = (3/4)*y(x)/x

y(x) = c__1*x^(3/4)

"sol is ", y(x) = c__1*x^(3/4)

y(x)/x^(3/4)

 

####
# All below added by Carl
####
#
#This works (Note: No additional restart!):

foo:= proc(ode::`=`)
local sol,the_constant;
   sol:=dsolve(ode);
   print("sol is ",sol);
   the_constant:=solve(sol,c__1);
   print("the constant is ",the_constant);
end proc
:

foo(ode);

"sol is ", y(x) = c__1*x^(3/4)

"the constant is ", y(x)/x^(3/4)

restart:

#A better way to code foo:
foo:= proc(ode::`=`)
local
    sol:= dsolve(ode),
    C:= indets(sol, And(symbol, Not(constant))) minus indets(ode, And(symbol, Not(constant))),
    the_constant
;
    print("sol is ",sol);
    if nops(C) <> 1 then error "Can't find specific constant:", C fi;
    the_constant:= solve(sol, C[]);
    print("the constant is ", the_constant)
end proc:

ode:=diff(y(x),x) = 3/4*y(x)/x;
foo(ode);

diff(y(x), x) = (3/4)*y(x)/x

"sol is ", y(x) = c__1*x^(3/4)

"the constant is ", y(x)/x^(3/4)

Download AliasedDsolveConstants.mw

When applied to a first-order nonlinear ODE, the term homogeneous has a completely different and standard definition than the one used for linear ODEs and referenced by @C_R . There is no connection between the two definitions. A quick Google search turns up many references to this definition of homogeneous for 1st-order nonlinear ODEs, and it's equivalent to the defintion given on the Maple help page that you referenced. So, I think that that quote from Advanced Engineering Mathematics with Maple is not telling the whole story.

Each of your three algebraic solutions of your ode for diff(y(x), x) can be put in the form F(y(x)/x) (using three slightly different Fs). To see this, after your PDEtools:-Solve command do

simplify(eval(rhs~([sol]), y(x)= x*v), symbolic);

You'll see that none of the three depend on x. (Note that v = y(x)/x.)

What benefit do you think you're getting by using alias? Aliases are quite weird, and if you're thinking of XX as just another variable, you'll likely make mistakes. Why not instead use

export XX:= Sqr1;

or

macro(XX= Sqr1);

?

It seems to me as if you just want an abbreviation for a longer command name. The export above will do that. The only possible reason I know of to use an alias is that it's an abbreviation that gets back-substituted on output. 

3 4 5 6 7 8 9 Last Page 5 of 390