29899 Reputation

29 Badges

18 years, 203 days
Ontario, Canada

Social Networks and Content at

MaplePrimes Activity

These are answers submitted by acer

Here's one way to handle an example like that.

The steps are to select the indices in which you're interested, and then to map table-lookup across those indices, and then take the min of the resulting values.

f := rand(1..100):

T := table([seq([R||i=f(),a||i=f(),b||i=f(),b||i=f()][], i=1..3)]);

table( [( R2 ) = 98, ( a1 ) = 45, ( R3 ) = 38, ( R1 ) = 93, ( a2 ) = 59, ( b3 ) = 96, ( a3 ) = 69, ( b2 ) = 100, ( b1 ) = 6 ] )






The steps of that are,



[[a1], [a2], [a3]]


[45, 59, 69]




It's not clear whether you're asking about how to programmatically determine the version of Maple in which code gets run, or whether you're asking about how to determine the version in which a worksheet was last saved.

I'm guessing it's the former.

The command kernelopts(version) returns a name that contains the version number. That could be converted to a string.

You can chop up that string to take only a particular portion, eg.


   str := "Maple 2018.2, X86 64 LINUX, Nov 16 2018, Build ID 1362973"

str[7 .. StringTools:-Search(".",str)-1];


You could use either InertForm:-Display or (undocumented) Typesetting:-Typeset for this.



R := 10:


                 font=[Helvitica,bold,14]],labels=[T," "]);

                 font=[Helvitica,bold,14]],labels=[T," "]);


Your given example can be handled by the define command.








Is this the kind of effect you're after?

Note that there's no need for any isolation/resubstitution to attain the first target form: collect is enough.

Note a sign difference in the second term of the target form.

The same algsubs result can also be obtained directly from the original expression (expanded), without the intermediate target form.


expr := 3*G*(`Δγ`*H - `σy`(`Δγ`) + q)/(-q + `σy`(`Δγ`))^2;


targ := collect(expr,H,simplify);


RR := G*`Δγ`=y/3*(q - `σy`(`Δγ`));

G*`Δγ` = (1/3)*y*(-`σy`(`Δγ`)+q)

algsubs(RR, targ);


ans := simplify(%);


algsubs(RR, expand(expr));




sort(ans, q);



[edit] Even though your intermediate target form is not necessary to achieve the algsubs result, it could also be obtained with,

   sort(%,order=plex(H,q));   # optional

For some values of parameter Cl the dsolve command may here return a result containing an inert integral, rather than a fully explicit answer.

In that case you could apply the value command. (This aspect of dsolve is mentioned in a bullet point a section of the ?dsolve,details Help page.)


     plot(value(sol(t)), t = 0 .. 48)

note: There are other ways to deal with it (changing the Int integral to use some specific numeric methods, or doing a numeric dsolve, etc.) Let us know if you'd like to see such.

@jrive First I'll show a form similar to that in nm's Answer, and discuss more on how that is not equivalent to the original even if all parameters are real. (See also nm's pertinent note, "sqrt(a)/b is same as sqrt(a/b^2) assuming b>0", by which he qualifies his answer.)


sol := (-v + sqrt(-4*a^2*R^2 + v^2))/(2*a*omega*L);


alt := evalindets(expand(sol),`*`,


Example for which they're not equal.

eval([sol,alt], [R=1,v=1,a=1,L=1,omega=-1]);

[1/2-(1/2)*(-3)^(1/2), 1/2+(1/2)*(-3)^(1/2)]

combine(simplify( sol-alt )) assuming real, a*omega*L>0;


combine(simplify( sol-alt )) assuming real, a*omega*L<0;



Regarding your comment about bringing a term into a radical, consider this simpler example,

ee := sqrt(x^2)/x;


simplify(ee) assuming x>0;


simplify(ee) assuming x<0;


If we absorb that x^1 into the radical (by squaring it) and make no other changes then we've mistakenly lost the multiplicative sign of x. If x is positive then it's ok. But if x is negative then we've mistakenly lost the negative sign.

With that in mind, here is a variant on your original query, with a form which retains the signum of a*omega*L outside the radical. Notice the broader equivalence, compared to your original target.


sol := (-v + sqrt(-4*a^2*R^2 + v^2))/(2*a*omega*L);


alt2 := -v/(2*a*omega*L) + sqrt((-4*R^2*a^2 + v^2)/(a^2*omega^2*L^2))/(2*signum(a*omega*L));


combine(simplify(sol - alt2)) assuming real;


alt2 assuming a*omega*L>0;


alt2 assuming a*omega*L<0;



Note: If, say, x=-3 then by convention sqrt(x^2) taken to be 3, not -3. That positive answer is known as the principal square root. See also the third paragraph here. Or see notes on the square-root case on principal value or n-th roots.

Is this the kind of thing you're trying to accomplish?

(I made no effort to optimize, or figure out what you're doing with tau at the end.)

I'll find a value for parameter beta that attains the goal g(10)=1. I'll do this in two ways, first using my own solving procedure and second using Doug Meade's Shoot package (see URL below).




alias( U=u(x,y), V=v(x,y) ):

PDE:={ U*diff(U,x)+V*diff(U,y)-nu*diff(U,y$2)=0,

       diff(U,x)+diff(V,y)=0 }:

simsubs := eta(x, y) = y*sqrt((1/2)*u[0]/(nu*x)):

stream := psi(x, y) = sqrt(2*nu*x*u[0])*f(eta(x, y)):

Usubs := U = diff(rhs(stream), y):

Vsubs := V = -(diff(rhs(stream), x)):

ODE := simplify(subs(Usubs, Vsubs, simsubs, PDE)):

simsubs2 := solve(subs(eta(x, y) = eta, simsubs), {y}):

ODE := simplify(subs(simsubs2, ODE), symbolic):

FNS := {f(eta), g(eta), h(eta)};

{f(eta), g(eta), h(eta)}

ODE:={ diff(f(eta),eta)=g(eta),


       diff(h(eta),eta)=-f(eta)*h(eta) }:

IC:={ f(0)=0, g(0)=0, h(0)=beta }:



findbeta := proc(b) local tt;
  if not b::numeric then return 'procname'(b); end if;
  tt := dsolve(eval(ODE union IC, beta=b),{f(eta),g(eta),h(eta)},numeric):
end proc:

betaval := beta = fsolve(findbeta(beta)-1, beta=0..1);

beta = .469600090249286

Sf := dsolve(eval(ODE union IC, betaval),{f(eta),g(eta),h(eta)},numeric,output=listprocedure):

Check that g(10)=1 for this solution, computed using betaval.

eval(g(eta), Sf)(10);


odeplot( Sf, [ [eta,f(eta)],

            [eta,g(eta)], [eta,h(eta)] ],0..4,
            labels=[`eta`,``], legend=["f","f '","f ''"],
            title="Blasius solution for flat-plate boundary layer" );

fp0:=subs( Sf, g(eta) ):

fp := proc(x)

  if not type(evalf(x),`numeric`) then




  end if;

end proc:

eta[`99%`] = fsolve(fp(eta) = .99, eta = 3 .. 4);

eta[`99%`] = 3.47188559058681

delta[`99%`] = subs(eta = rhs(%), combine(rhs(op(simsubs2))));

delta[`99%`] = 3.47188559058681*2^(1/2)/(u[0]/(nu*x))^(1/2)

tau := mu*simplify(diff(subs(simsubs, rhs(Usubs)), y));


tau[w] := subs(((D@@2)(f))(0) = (subs(Sf, h(eta)))(0), subs(y = 0, tau));


Now do the same thing using,



infolevel[shoot] := 1:

S:=shoot( ODE, IC, BC, FNS, beta=1,

          abserr=Float(5,-7), output=listprocedure, method=taylorseries ):

shoot: Step #  1

shoot: Parameter values :  beta = 1
shoot: Step #  2
shoot: Parameter values :  beta = HFloat(0.4062401739572171)
shoot: Step #  3
shoot: Parameter values :  beta = HFloat(0.46805773973620646)

shoot: Step #  4
shoot: Parameter values :  beta = HFloat(0.4695991426488529)
shoot: Step #  5
shoot: Parameter values :  beta = HFloat(0.46959998836128514)

Check that g(10)=1 for this solution (approximately), computed using betaval.
(You could vary the options to shoot.)

eval(g(eta), S)(10);




odeplot( S, [ [eta,f(eta)],

            [eta,g(eta)], [eta,h(eta)] ],0..4,
            labels=[`eta`,``], legend=["f","f '","f ''"],
            title="Blasius solution for flat-plate boundary layer" );

fp0:=subs( S, g(eta) ):

fp := proc(x)

  if not type(evalf(x),`numeric`) then




  end if;

end proc:

eta[`99%`] = fsolve(fp(eta) = .99, eta = 3 .. 4);

eta[`99%`] = 3.47188688127711

delta[`99%`] = subs(eta = rhs(%), combine(rhs(op(simsubs2))));

delta[`99%`] = 3.47188688127711*2^(1/2)/(u[0]/(nu*x))^(1/2)

tau := mu*simplify(diff(subs(simsubs, rhs(Usubs)), y));


tau[w] := subs(((D@@2)(f))(0) = (subs(S, h(eta)))(0), subs(y = 0, tau));



Is this the kind of effect you're after?

[edit:The solution(s) in terms of explicit radicals can be obtained by using the explicit option of the solve command. The simplification to your target form can be achieved via the evala command -- though there are a few longer incantations that also get it.]


NULLeq1 := (R2+Rhi)*R1/(R1+R2+Rhi) = RloNULL

(R2+Rhi)*R1/(R1+R2+Rhi) = Rlo


NULLeq2 := R1*Rlo/(R1+Rlo)+R2 = RhiNULL

R1*Rlo/(R1+Rlo)+R2 = Rhi

evala({solve({eq1, eq2}, {R1, R2}, explicit)})

{{R1 = ((Rhi-Rlo)*Rhi)^(1/2)*Rlo/(Rhi-Rlo), R2 = ((Rhi-Rlo)*Rhi)^(1/2)}, {R1 = -((Rhi-Rlo)*Rhi)^(1/2)*Rlo/(Rhi-Rlo), R2 = -((Rhi-Rlo)*Rhi)^(1/2)}}


Maybe there is something nicer which "understands" the inert `%.` (as well as recognizes the distinct Matrix instances with equal entries as being equivalent), but it's less ad hoc.

[edit] Here is very a minor revision to that, splitting to show the simplify step separately,

restart; Digits := 14: with(PDEtools): with(LinearAlgebra): with(plots):

pde:= diff(u(t,x),t$2) = diff(u(t,x),x$2):

 Subs:= {r1(t,x) = diff(u(t,x),t), r2(t,x)= diff(u(t,x),x)}:

eq1 := map(z->diff(z,t),<r1(t,x),r2(t,x)>) = Matrix(2,[0,1,1,0])>diff(z,x),<r1(t,x),r2(t,x)>):


GenerateStencil := proc(F,N,{orientation:=center,stepsize:=s,showorder:=true, showerror:=false}) loc...


eq6 := <rhs(eq2),rhs(eq3)> = Matrix(2,[0,1,1,0]) %. <rhs(eq4),rhs(eq5)>:

eq7 := [seq(seq(r1(t+i*s,x+j*h)= r1[n+i,m+j],i=0..1),j=-1..1)]:
eq8 :=[seq(seq(r2(t+i*s,x+j*h)= r2 [n+i,m+j],i=0..1),j=-1..1)]:

eq9 := map(z->subs(eq7,eq8,z),eq6):

eq10 := [seq(seq(r1(t+i*s,x+j*h)= r1[n+i,m+j]-E1[n+i,m+j],i=0..1),j=-1..1)]:

eq11 :=[seq(seq(r2(t+i*s,x+j*h)= r2 [n+i,m+j]-E2[n+i,m+j],i=0..1),j=-1..1)]:

eq12 := map(z->subs(eq10,eq11,z),eq6):

eq13 := simplify(eq12-eq9,'mindeg');

(Vector(2, {(1) = (E1[n, m]-E1[n+1, m])/s, (2) = (E2[n, m]-E2[n+1, m])/s})) = `%.`(Matrix(2, 2, {(1, 1) = 0, (1, 2) = 1, (2, 1) = 1, (2, 2) = 0}), Vector(2, {(1) = (1/2)*(-r1[n, m-1]+E1[n, m-1]+r1[n, m+1]-E1[n, m+1])/h, (2) = (1/2)*(-r2[n, m-1]+E2[n, m-1]+r2[n, m+1]-E2[n, m+1])/h}))-`%.`(Matrix(2, 2, {(1, 1) = 0, (1, 2) = 1, (2, 1) = 1, (2, 2) = 0}), Vector(2, {(1) = (1/2)*(-r1[n, m-1]+r1[n, m+1])/h, (2) = (1/2)*(-r2[n, m-1]+r2[n, m+1])/h}))

eq14 := subsindets(subsindets(subsindets(thaw(%),And(`*`,satisfies(u->ormap(type,u,list))),

(Vector(2, {(1) = (E1[n, m]-E1[n+1, m])/s, (2) = (E2[n, m]-E2[n+1, m])/s})) = `%.`(Matrix(2, 2, {(1, 1) = 0, (1, 2) = 1, (2, 1) = 1, (2, 2) = 0}), Vector(2, {(1) = -(1/2)*(-r1[n, m-1]+r1[n, m+1])/h+(1/2)*(-r1[n, m-1]+E1[n, m-1]+r1[n, m+1]-E1[n, m+1])/h, (2) = -(1/2)*(-r2[n, m-1]+r2[n, m+1])/h+(1/2)*(-r2[n, m-1]+E2[n, m-1]+r2[n, m+1]-E2[n, m+1])/h}))


(Vector(2, {(1) = (E1[n, m]-E1[n+1, m])/s, (2) = (E2[n, m]-E2[n+1, m])/s})) = `%.`(Matrix(2, 2, {(1, 1) = 0, (1, 2) = 1, (2, 1) = 1, (2, 2) = 0}), Vector(2, {(1) = (1/2)*(E1[n, m-1]-E1[n, m+1])/h, (2) = (1/2)*(E2[n, m-1]-E2[n, m+1])/h}))


The technique might be adapted to handle several kinds of more involved Matrix/vector expressions with inert `%.`. That's related to a major reason why I made the code so involved -- for generality.

If results is a list, set, Vector/Array, or expression sequence (of, say, 7 elements) then you could do any of,

    return  results[2];

    return results[3..6];

    return results[2],results[4],results[5];

    return results[1],results[7];

Here are a few edits. I've added comments as to why I've made the changes.

Note that I've also allowed your utility formatters (Code-Edit region) to continue to function like the original.

(In the actual Maple GUI the units render more nicely. The double-braces appearing around units below are an artefact of this website's old backend.)



`Maple 2024.0, X86 64 LINUX, Mar 01 2024, Build ID 1794891`





totvol := proc (ht) options operator, arrow; Pi*.4^2*ht^2*ht+(1/3)*Pi*.4^2*ht^2*((2/3)*ht) end proc

proc (ht) options operator, arrow; .6143558967*ht^3 end proc

The procedures defined before this package is loaded
(ie. your utilities, as well as `totvol`) get the global
bindings for arithmetic.
That allows the utilities to work as intended, and
it allows the body of `totvol` to automatically simplify
at creation time, as well as to print as you wanted.


Automatically loading the Units[Simple] subpackage

Utilize the foot-pound-second system instead of SI.




fsolve(totvol(ht) = 8.169367284, ht)


volReq := 130*Unit('gallon'['US_liquid'])


volReq := 1.2*volReq


Alternate to next pair of commands below.
This produces result in ft, without having to first
convert volReq from gal to ft^3. For the FPS system
length dimensions computations simplify to ft.

volReq := convert(volReq, 'units', ft^3)


By default fsolve computes real roots.
It's suitable for your floating-point example.
Note that the result is in ft, not meters.

Also, by assigning directly to ht__main_tank we
avoid assigning to name `ht` which is used as
dummy name in a few places. This allows these
parts of your worksheet to be recomputed out-of-order,
since name ht is not clobbered.

ht__main_tank := fsolve(totvol(ht) = volReq, ht)



With the computed height in ft, we don't need
to convert all of these results separately.

ht__pan := (2/3)*ht__main_tank; rad := .4*ht__main_tank; total_height := ht__main_tank+ht__pan




Note that your utilities still function as intended.
(They don't continue to work properly if you just follow the
Answers suggesting that all you need to do it utilize `unapply`...)

conv2ftin(ht__main_tank); conv2ftin(ht__pan); conv2ftin(rad); conv2ftin(total_height)





convert(totvol(ht__main_tank), 'units', gallons)


Download Tank_Design_Calculation_-_Units_Question_(v00)

You can utilize the assuming facility to place separate assumptions during individual computations.

That allows you to compute under the assumption m::integer, but with no assumption on alpha.

For example, using Maple 2022 because the OP did,



`Maple 2022.2, X86 64 LINUX, Oct 23 2022, Build ID 1657361`

expr2 := 4*cos(Pi*m+2*alpha*Pi)/(Pi*(2*m + 1));


combine(expand(expr2)) assuming m::integer;



It sounds as if you want nice pretty-printed ways to both enter and print those (2D Input and Output), and not just the means to compute.

For a more involved attempt you could look at this old Answer thread (and also some later revisions in worksheets attached to replies in the thread.)

For a preview, here's some simple functionality along those lines, again with 2D Input/Output.

end proc:
   uses Typesetting;
end proc:
end proc:

`&angle;` := degpolar





a := 1/2+sqrt(3)/2*I;


ans := convert(a, degpolar);

degpolar(1, 60)




For the next I've used the symbol from the Operators Palette.


q := `&angle;`(230, 0)/`&angle;`(92, -53.13)

degpolar(230, 0)/degpolar(92, -53.13)

convert(evalc(q), degpolar)

degpolar(2.500000001, 53.12999999)


You specifically inquired about implicitplot3d, so in coding below I will address that in particular. It's documented [123] and not too difficult to color/shade a surface constructed by plot3d, etc. Hence if you could break up your implicit x-y-z region into explicitly defined portions then you could use another 3d plotting command. So I'm supposing that you wouldn't be asking about implicitplot3d if you had only an example that was subject to such recourse.

I'm just going to address coloring (arbitrarily) with implicitplot3d, since dharr's already treated your particular surface examples with a split into explicitly formulated portions.

You can in fact utilize a float[8] Array to color the triangles by which the GUI renders the surface, when it displays an ISOSURFACE plotting structure generated by the implicitplot3d command. You can use such an Array to specify coloring by either RGB or HSV values.

But the big problem is that those triangles don't match the set of x-y-z points stored as data in the ISOSURFACE. The ISOSURFACE values are just for the regularly spaced points in the ranges. The location of the vertices of those triangles are a result of the interpolating process by which the GUI's plot driver figures out where the surface might be, and we are not privy to that. So we lack programmatic access to the x-y-z values for the vertices of the GUI-rendered triangles.

Even the number of the mesh points of stored function values doesn't match the number of triangles in the rendered surface. And that number of triangles is also a function of the proportion of the plotting window which the surface occupies.

Here's an example. This code does not form those triangles. The GUI does that. This code merely adds a COLOR substructure to a usual implicitplot3d result, to specifiy hue values for its rendered triangles.






note: If you changed that to utilize grid=[6,6,7] instead then in Maple 2016.2 and later you could see an example of the GUI message spit out when the coloring Array doesn't have the right number of entries.

As it happens that COLOR substructure's Array can match either the number of segments of the number of vertices (whichever is closest, I suspect). And the GUI spits out a message when there's a bad mismatch. But in neither case do we know the x-y-z coordinates of those vertices, and so we don't know how to populate that COLOR structure's Array. (If I had such a means I'd ditch ISOSURFACE myself, and do the math and draw those portions by my own construction, with full control...)

1 2 3 4 5 6 7 Last Page 1 of 311