Carl Love

Carl Love

26488 Reputation

25 Badges

12 years, 299 days
Himself
Wayland, Massachusetts, United States
My name was formerly Carl Devore.

MaplePrimes Activity


These are answers submitted by Carl Love

Square brackets cannot be used instead of parentheses. The square of the derivative could be entered as (diff(f(eta),eta))^2 or diff(f(eta),eta)^2; they mean the same thing.

I think that you're causing yourself confusion by making an unnecessary distinction between procedures and subprocedures.  A procedure B only needs to be considered a subprocedure of procedure A if B directly refers to the locals or parameters of A. In the code that follows, SelectX is a subprocedure of ModuleApply, but maxmin and pluralize are not. SelectX needs to be declared inside ModuleApply, but the others do not although they are used within ModuleApplySelectX itself has a subprocedure, j-> Y[j]=y. Such a procedure is called anonymous because it has no proper name.

The code that you're using as examples uses a very bad programming practice: The procedures return their values through parameters declared evaln rather than through the normal return mechanism.

A group of related procedures and other code can be put together into a module:

optimize:= module()
export
    maxmin:= proc(A::{list, set, table, rtable}(numeric))
    local minv:= infinity, maxv:= -infinity, v;
        for v in A do
            if v < minv then minv:= v fi;
            if v > maxv then maxv:= v fi
        od;
        (maxv, minv)
    end proc,

    Vals:= Record("maxy", "miny", "xmaxs", "xmins")
;
local
    format:= "M%simum y-value is %a and occurs at x-value%s %a.",
    pluralize:= x-> `if`(numelems(x)=1, ["", seq(x)], ["s", x])[],

    ModuleApply:= proc(f, ab::range(realcons), N::posint)
    uses V= Vals;
    local 
        a:= lhs(ab), J:= [$1..N+1],
        X:= a+(rhs(ab)-a)/N*rtable(J-~1, 'datatype'= 'float'), 
        Y:= f~(X),
        SelectX:= y-> [seq](X[select(j-> Y[j]=y, J)])
    ; 
        (V:-xmaxs, V:-xmins):= SelectX~(
            [((V:-maxy, V:-miny):= maxmin(Y))]
        )[];
        plot(
            `[]`~(`[]`~(X,0), `[]`~(X,Y)), 'color'= 'black',
            'thickness'= 0,
            'caption'= sprintf(
                cat(format, "\n", format),
                evalf[4]([
                    "ax", V:-maxy, pluralize(V:-xmaxs),
                    "in", V:-miny, pluralize(V:-xmins)
                ])[]
            ),
            _rest
        )
    end proc
;
end module
:

optimize(x-> 3+10*(-x^2+x^4)*exp(-x^2), -1..4, 150);

eval(optimize:-Vals);
   
Record(maxy = 6.08806665291368, miny = 1.39153873739412, 
   xmaxs = [1.63333333333333], 
   xmins = [-0.633333333333333, 0.633333333333333])


optimize:-Vals:-maxy;
                       
6.08806665291368

After separating the real and imaginary parts with evalc, as shown by Thomas Richard, there are still a few more things to consider before plotting them. The resulting equations have three (real) variables---pq, and y---and they can't be explicitly solved for any of those. The command plot is not for plotting equations. An equation in three variables could theoretically be plotted by plots:-implicitplot3d if you specified ranges for all three variables. Given the high degree of your equation, I wouldn't expect very good results from this. If you give a specific value to one variable and specify ranges for the other two, then the resulting equation could be plotted with plots:-implcitplot. This could be done in succession for different specific values of that one variable, producing an animation as in this command:

plots:-animate(plots:-implicitplot, [evalc(a), p= -2..2, q= -2..2], y= 0..2);

The Explore command can also be used in conjunction with plots:-implicitplot, as shown by Kitonum, to produce animations, or they can be used as he showed to produce static plots with a viewer-adjustable free variable (parameter).

is the universal gravitational constant, not the acceleration due to gravity in any particular place:

G:= evalf(ScientificConstants:-Constant('G', units));
                                        /  3  \
                                -11     | m   |
                 G := 6.67408 10    Unit|-----|
                                        |    2|
                                        \kg s /

 

A simple eval or subs will change all the f regardless of whether they are functions. To change only the functions f(...to h(...) in an expression e, use

subsindets(e, specfunc(f), h@op)

That'll work for functions of any number of arguments, including 0.

Here's a possibility for your more-general question, i.e., changing F(f(x)) to H(h(x)). Using the above will change all the f regardless of whether they occur inside F. That doesn't seem to be what you want. So, let e be an expression containing subexpressions of the form F(..., f(...), ...), no matter how deeply nested. For example:

e:= 3+F(7, f(3), F(1+f(2,4)), F(7)) + f(2,4):

Then do

subsindets(
    e, And(specfunc(F), satisfies(F-> hastype(F, specfunc(f)))), 
    H @op@subsindets, specfunc(f), h @op
);
         3 + H(7, h(3), H(1 + h(2, 4)), F(7)) + f(2, 4)

I decided not to change F(...) to H(...) in cases where F(...doesn't contain f(...). I'm not sure what you intend along those lines, but either way is easily doable.

To give an Answer to your title Question "How can one make substitutions of general expressions?": Almost always, subsindets or evalindets is what I'd use. (The two commands are very similar both in syntax and results. Don't expend any effort trying to decide between the two.)

Looking at the code showstat(GraphTheory:-VertexConnectivity), it's very easy to see why it's so slow. It's only 29 lines, and easy to read. To simplify this discussion a bit, let's suppose that is a simple connected undirected unweighted graph with no self loops and no articulation points, and G's vertices are named simply through n. So, that still covers the vast majority of practical cases, and you can ignore lines 3-9 which take care of the weird and degenerate cases. Lines 15-16 are a quick return in G is complete, so you can ignore them also.

As usual, n is the number of vertices, and is the edge set. A (which is extracted as op(4,G)) is a structure equivalent to the adjacency matrix. The actual data structure is an n-vector such that A[k] is the set of vertices that share an edge with k. A permutation of is done such that the vertices are ordered by degree.

A weighted directed graph of 2*n vertices and n + 2*nops(E) (directed) arcs is constructed. The simple formula for N's arcs is in lines 17-18. All of the weights are 1. No changes are made to for the rest of this algorithm.

The really slow part is the double loop in lines 22-28. For every pair {i,j} of G's vertices, if {i,j} is not[*1] in E, then a max-flow problem in is solved (using GraphTheory:-MaxFlow) using N's vertex corresponding to i as the source and that corresponding to j as the sink.

Now, if this is the best-known algorithm we should optimize it so that there's no duplication of effort due to repeated calls to MaxFlow on exactly the same digraph, with only the source and sink being changed.

Edit: I originally said that had n + nops(E) arcs. I've corrected that to n + 2*nops(E).

[*1] Because of that "not", any sparsity of is not a big help (unless it's so sparse as to have an articulation point).

This is more efficient than remove and also shorter to type:

L:= subs(
    ""= (), 
    StringTools:-Split(
        "This string has some    extra 		whitespace    in it."
    )
);

I'm not sure whether () will work in 2D Input. If it doesn't, replace it with NULL (which is a named constant equivalent to ()).

Setting list or set entries to NULL simply creates a new list or set without those entries. It does not create a list or set that contains NULL; Maple doesn't allow such a list or set. But tables and rtablecan contain NULL entries.

Here's a group of procedures for finding the critical points of 2-variable functions, classifying them, plotting the function with labeled and indexed critical points, and showing a table with the same information. The ranges for the plot are automatically determined in all three dimensions.

Gradient:= proc(f)
local x, y, V:= (x,y); 
    unapply(diff~(f(V), [V]), [V])
end proc
:
Hessian:= proc(f)
local x, y, V:= (x,y);
    unapply(Matrix(2, (i,j)-> D[i,j](f)(V), 'shape'= 'symmetric'), [V])
end proc
:
Mn:= (s::string)-> `#mn("` || s || `")`
:
Classify:= proc(H, P::list(realcons))
local E:= evalf(LinearAlgebra:-Eigenvalues(H(P[]))), M, m;
    (M,m):= (max,min)(E);
    Mn(
        if M<0 then "max" 
        elif m>0 then "min" 
        elif M*m < 0 then "saddle"
        else "inconclusive"
        fi
    )
end proc
:
CritPts:= proc(f)
local x, y, V:= (x,y);
    map2(
        eval,
        [V, f(V)], 
        evalf(
            [solve](
                {Gradient(f)(V)[]}, {V}, 'explicit', 'allsolutions'
            )
        )
    )
end proc
:    
ViewRange:= proc(L::list(realcons), stretch::positive:= 2)
local M,m,d,c;
    (M,m):= (max,min)(L); d:= stretch*(M-m)/2; c:= (M+m)/2;
    (c-d)..(c+d)
end proc
:
PlotAndTable:= proc(
    f, 
    V::list(name):= [x,y,z],
    {
        pointopts::list(name= anything):= [
            'color'= 'black', 'symbol'= 'solidsphere', 
            'symbolsize'= 16
        ],
        funcopts::list(name= anything):= [],
        textopts::list(name= anything):= [
            'align'= {'ABOVE', 'RIGHT'}, 'font'= ['times', 'bold', 24],
            'color'= 'red'
        ]
    }
)
local 
    C:= CritPts(f), R:= V=~ViewRange~(map2(index~, C, [1,2,3])), 
    k, L:= <seq(1..nops(C))>
;
    (print@plots:-display)(
        plot3d(
            f(V[]), R[1..2][], 
            'view'= rhs~(R), 'labels'= V, funcopts[]
        ),
        plots:-pointplot3d(C, pointopts[]),
        plots:-textplot3d(
            {seq}([C[k][], cat(" ",k)], k= L), textopts[]
        ),
        transparency= .05,
        _rest
    );
    < 
        <Mn("label"), V[], Mn("type")>^%T, 
        < L | Matrix(C) | map2(Classify, Hessian(f), <C>)>
    >
end proc
:

Example use:

PlotAndTable((x,y)-> x^4 - 3*x^2 - 2*y^3 + 3*y + x*y/2);

MaplePrimes won't let me copy-and-paste plots!

MaplePrimes won't let me display worksheets inline!

  • Maple Worksheet - Error
    Failed to load the worksheet /maplenet/convert/ExtremaAndSaddles.mw .

You'll need to download and run it yourself:

Download ExtremaAndSaddles.mw

To get the curl of a 2D field, embed it in a 3D field making the 3rd component 0.

To extract the components of a vector field V, do [seq](V)

The variables t[1] and t are not independent: Making an assignment to one affects the other. But if you change t[1] to t__1, then everything will work.

Here are 3 one-line procedures that do it:

Enumerate1:= (L::list, f)-> [for local p in L do [p, f(p)] od]:
Enumerate2:= (L::list, f)-> local p; [seq]([p, f(p)], p= L):
Enumerate3:= (L::list, f)-> `[]`~(L, f~(L)):

<Enumerate||(1..3)([1, 3, 5, 7, 9], isprime)>;

This works regardless of whether the entries of L are numeric or f is a procedure.

(The first 2 of those procedures require 1D input.)

Edit: Parentheses error noted by Acer corrected.

Where you have defined

f(x):= ...

change that to

f:= x-> f__0(x) + f__w*lambda^(-1/2)*f__1(x) + f__2(x)/lambda:

When you re-examine ODE, you'll see that the change has taken effect. You must use subscripted names f__0, f__w, f__1, f__2 rather than indexed names f[0], f[w], f[1], f[2] for this to work. A subscripted name appears the same as an indexed name in the prettyprinted output, but computationally they mean different things: The subscripted name f__0 is independent from its parent name f, but the indexed name f[0] is not independent from f (changes made to f will affect f[0] but not f__0).

Here's a way to print the nested function:

for i from 0 to 3 do
    print(
        nprintf(`#msup(mi("A"),mn("<%d>"))`, i)(
            nprintf(`#msup(mi("x"),mn("<%d>"))`, i)(0)
        ) = `#mn("Mat")`(i)
    )           
od;

Note that this keeps the numerals upright (even those in angle brackets) and displays Mat upright. The A and x are in the usual italics used for variables.

[This is an Answer to your followup Question "DirectSearch skips a parameter".]

There are several issues:

1. Neither I nor anyone else here can duplicate what you're doing because your original Question doesn't show the value of dsys, your system of ODEs. So, what I've said so far has necessarily been based on guessing.

2. DirectSearch:-DataFit has 9 different ways of computing residuals, including your standard least squares. Perhaps one would suit your needs?

3. Your resid needs to politely ignore non-numeric input the same way your ffit2 does. Also, you should use add instead of sum (sum is intended for symbolic summation).

resid:= (eta_L, L0)->
    if [args]::list(numeric) then add((ffit2~(eta_L, L0, X0) - Y0)^~2)
    else 'procname'(args)
    fi

:

4. This was probably just a transcription error as you were moving text to MaplePrimes, but note that you used resid2 in the code below your definition of resid.

A radical conversion is not always possible (usually not possible for irreducibles with degree > 4), but viewing the RootOf form of the factors is also quite unwieldy. Here's a way that I think helps one to see the relationships between the irrational roots:

restart:
p:= x^4 - x^2 + x - 1:

(* This procedure is only to compactify the display of RootOf
expressions. It has no effect computationally; in particular, further
processing of output displayed by this should ignore the radical symbol
(`&radic;`) and Z and treat them as the usual RootOf and _Z.
*) 
`print/RootOf`:= p-> local Z; `&radic;`(subs(_Z=Z, p), _rest):

(* This command--equivalent to the 1st step of Kitonum's Answer--shows
the factorization with nested RootOfs, from which it's still unwieldy 
to understand the relationships between the irrational roots.
*)
evala(AFactor(p)); #equivalent to PolynomialTools:-Split
                                     /           /  
          /           / 3    2    \\ |           | 2
  (x - 1) \x - &radic;\Z  + Z  + 1// \x - &radic;\Z 

                                                          2
       /           / 3    2    \\            / 3    2    \ 
     + \1 + &radic;\Z  + Z  + 1// Z + &radic;\Z  + Z  + 1/ 

                           \\ /                               
              / 3    2    \|| |               / 3    2    \   
     + &radic;\Z  + Z  + 1/// \x + 1 + &radic;\Z  + Z  + 1/ + 

           /                                 
           | 2   /           / 3    2    \\  
    &radic;\Z  + \1 + &radic;\Z  + Z  + 1// Z

                           2                       \\
              / 3    2    \           / 3    2    \||
     + &radic;\Z  + Z  + 1/  + &radic;\Z  + Z  + 1///

#Of course, the above looks better in Maple's 2D output, which I can't 
#display here. `&radic;` (HTML code) will be display as a single-character-width root
#symbol.

(* This technique recursively nests and 'veils' the RootOfs, which I
think makes it easier to see the relationships. Here, nu could be any
unassigned name.
*)
LE:= LargeExpressions:
evalindets(evala(AFactor(p)), RootOf, LE:-Veil[nu]), 
    <seq(nu[k]=LE:-Unveil[nu](nu[k]), k= 1..LE:-LastUsed[nu])>
(x - 1)*(x - nu[1])*(x - nu[2])*(x + 1 + nu[1] + nu[2]), 
nu[1] = `&radic;`(Z^3 + Z^2 + 1), 
nu[2] = `&radic;`(Z^2 + (1 + nu[1])*Z + nu[1]^2 + nu[1])

 

First 45 46 47 48 49 50 51 Last Page 47 of 382