Carl Love

Carl Love

28035 Reputation

25 Badges

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

MaplePrimes Activity


These are answers submitted by Carl Love

From your responses to my earlier questions, I inferred that you don't need much precision in your timer: If your program ran approximately once per minute that'd be fine. In that case, use the simple command Threads:-Sleep(60). That simply pauses the program for approximately 60 seconds. Just put that in a loop with a call to your main program.

@mapleq2013 

To understand the answers to all your questions above, you must first understand some fundamental principles of procedures. The most important is

The Non-Evaluation at Definition (NED) principle: No part of a procedure's definition is evaluated at the time that the procedure is defined (except for basic numeric arithmetic and some very trivial algebra). Evaluation only happens when the procedure is called (i.e., when it's passed arguments). In particular, at the time of definition, no non-local variable's value is determined or substituted, and no procedure invocation inside the procedure definition is executed.

An example of NED:

a:= 1:
f:= x-> x+a;

Note that the response isn't f:= x-> x+1, because the a remains unevaluated.

a:= 2:
f(1);

     3

The response is 3, not 2, because a is evaluated at the time the procedure is called. Further changes to a will continue to change how f behaves.

The second fundamental principle is

The Procedures are First-Class Objects (PFCO) principle: In Maple, procedures are first-class objects (see these Wikipedia articles: First-class function, Non-local variable, Closure, and Partial application).

In my opinion, any language that doesn't implement NED can hardly be called a language. (It'd be like a human language that didn't allow the description of hypothetical situations.) Perhaps the qualified name "macro language" could be applied to it. PFCO, however, is a very sophisticated feature (which allows for meta-programming), and there are many quite powerful languages (like C++) that don't fully implement it. A full implementation requires a sophisticated and resource-consuming runtime infrastructure that includes garbage collection.

Here's an example of both NED and PFCO.

f:= x-> 1: #Constant function.
g:= y-> y+f(0);

Because of NED, the f(0) remains unevaluated, even though it'd be trivial for the parser to replace it with 1.

g(2);

     3

(Calling g forces the call to f, obviously.)

Here's some meta-programming (albeit trivial for the sake of example): We'll change f's definition by substituting 2 for 1 inside the definition.

f:= subs(1= 2, eval(f));

That a procedure can be both the argument and the return value of subs is an example of PFCO, and a quite profound one at that. (The need for the eval in the statement above is due to an issue called last name evaluation, which is Maple specific and is completely unrelated to the rest of this post.)

g(2);

     4

Now I'll directly address your questions. You wrote:

I don't quite understand what is "to compute the determinant outside the call to fsolve".

I could've made a procedure like this---computing the determinant inside the call to fsolve:

Sol:= (Y,X)-> fsolve(LinearAlgebra:-Determinant(eval(C, [x= X, y= Y])), w, complex);

That would work, but it'd be inefficient because due to NED, the determinant would be recomputed for each numeric pair (Y,X). To avoid that, the call to Determinant must be outside the definition of Sol, and hence outside the call to fsolve.

My understanding is that, solve(Dt(y,x), w) would create a symbolic solution first and then substitute y and x later during the plotting process.

Correct. And a symbolic solution is usually a good thing----if you can get it.

That didn't work reliably since Maple wasn't able to find a symbolic solution everytime.

Correct. And I wouldn't fault Maple for that, since there's no general solution to a degree-six polynomial.

I tried to use fsolve(Dt(y,x), w) myself earlier but it tries to create numerical solutions and returned me an error.

Yes. Being a strictly numerical solver, fsolve needs to have the same number of equations as unknowns. With symbolic x and y, your Dt(y,x) is one equation with three unknowns.

I also tried to loop through all x and y first and then solve(Dt(y,x), w) ..., but it's very slow because Maple doesn't seem to handle massive loops as well as Matlab.

It has nothing to do with the loop size, and Maple handles massive loops just fine. The issue is that for specific numeric values of x and y, the solve is much slower than fsolve.

So you somehow overcame all of those problems by (y,x)-> Re(fsolve(Dt(y,x), w, complex) in my understanding by letting Maple temporarily hold x and y as variables while calling fsolve and then supply x and y values later.

Yes, that's NED.

Also wouldn't unapply be unnecessary because (y,x)-> already defines a function?

I used unapply to define the procedure (or "function") Dt, not solD, which is a separate procedure. (But you're correct that using (y,x)-> does define a procedure ("function").)

(By the way, your usage of "function" is totally correct from a computer-science viewpoint. Those Wikipedia articles will quickly confirm that. It's just slightly imprecise (although not incorrect) from a Maple viewpoint. So don't be offended that I put quotes on "function". I'll just continue using "procedure" when I want to be precise.)

Now, like I said in an earlier Answer, I could've avoided the use of unapply and still maintained efficiency. It'd be done like this:

Dt:= LinearAlgebra:-Determinant(C);
Sol:= (Y,X)-> fsolve(eval(Dt, [x= X, y= Y]), w, complex);

In the above, Dt is merely an expression, not a procedure. I find that a bit awkward because of the need to use symbols X and Y (as procedure parameters) distinct from x and (which, in this case, are global unevaluated symbols). By using unapply, I convert x and y themselves into the parameters. (They still also exist as globals; they're only parameters inside Dt.)

For the subs being necessary in solD||n:= (y,x)-> Re(fsolve(Dt(y,x), w, complex)[n]): This is my long standing confusion with using Maple to do loops.

I don't see what it has to do with loops. Your previous confusion was due a lack of understanding NED and PFCO.

Because I have some experience progamming with C++ and in there you don't need to do subs each time

I wasn't aware that a compiled language like C++ even had or could have anything like subs. Even if it does, I'd be quite surprised if it could be applied to a function.

I understand Maple is not a progamming language.

Au contraire. Maple is a package that includes a programming language, which is also called Maple---and it's an extremely powerful and rich language. Even if you were to throw away all of Maple's higher mathematical functionality, the plotting, and the GUIs (with all their bugs), you'd still be left with one of the most powerful computer languages ever developed---which nonetheless has an intuitive, simple, and highly consistent syntax. The Maple language is implemented in the kernel, which has much fewer bugs, and the bugs are addressed much more quickly.

what puzzles me is that how Maple doesn't substitute the n directly?

That it doesn't substitute it directly is NED. That one is able to substitute it later is PFCO.

and I think in other languages you don't need to do that either.

Like I said before, any "language" that doesn't have NED hardly qualifies to be called a language. However, there are many ways to implement the substitution (the PFCO aspect) without having a direct subs command that works on procedures. These alternatives can be used in Maple also. One (crude) way is shown in my first example of NED above: You change the value of a global variable, that variable being n for the case at hand. So it'd work like this:

solD:= (y,x)-> fsolve(Dt(y,x), w, complex)[n];
for n to 6 do
     plot3d(solD, -Pi..Pi, -Pi..Pi)
end do;

I say that this method is crude because it relies on a global variable whose usage in the body of the loop is not explicitly apparent. Any code reviewer should flag this and tell the programmer "Your index variable n is not used in the loop."

A more sophisticated approach would be to make both Sol and n exports of a module. This is akin to a class in C++.

Wait, sometimes it does substitute directly because I was looping through x and y and the numbers did go in solve(Dt(y,x), w).  So yea I'm confused here ...

That's because solve(Dt(y,x), w) isn't a procedure definition; thus NED doesn't apply. These issues have nothing to do with loops.

There are a great many ways to do that.

1. My preference:

V:= [2,8,14]:
T:= tau-> 440*(1 - exp(-1/tau)):
t:= evalf(T~(V));

2. A way that uses your original T (without turning it into a procedure):

T:= 440*(1 - exp(-1/tau)):
t:= evalf([seq(eval(T, tau= x), x= V)]);

3. My guess as to what most Maplers would do:

t:= map(x-> evalf(eval(T, tau= x)), V);

Note that eval(T, tau= a) is preferable to subs(tau= a, T).

 

 

You simply need more digits of precision to fsolve this. After restart, set Digits:= 15. Then the fsolve returns

There are no differences.

As implied by Rouben, Maple doesn't handle symbolic matrices. However, if you specify just the size of the Matrix, then the Matrix's contents can be completely symbolic. Then your product rule for derivatives can be verified for that size Matrix like this:

A:= Matrix((3,3), (i,j)-> a[i,j](t)):
B:= Matrix((3,3), (i,j)-> b[i,j](t)):
C:= A^+.B:
diff~(C, t) - (diff~(A^+, t).B + A^+.diff~(B, t));

Update: I apologize that my code is functionally equivalent to Tom Leslie's. A vote up for him. The codes were written independently and simultaneously.

Your error is in statements such as

a[0] := mu*lambda*sqrt(-6*a);

The a and a[0] are not independent variables. The second a needs to be some other variable.

You may have the highest number of errors that I've ever seen in a single line of code that didn't yield an error message.

This is your line, copied as 1D input:

A[k]:= ((d^k/`dλ`^k)[F(sum(lambda^i*e^y[i], i= 0..k))], lambda= 0)/k!

And this is my corrected version:

A[k]:= eval(diff(F(add(lambda^i*exp(y[i]), i= 0..k)), [lambda$k]), lambda= 0)/k!

The errors:

  1. You need to use diff or D for derivatives; d won't do it,
  2. Your dlambda is a single variable.
  3. The arguments to the diff need to be in parentheses.
  4. Square brackets can't be used for algebraic grouping.
  5. The exponential function is denoted exp(y[i]), not e^y[i].
  6. You need wrap it all in the eval command to apply the condition lambda= 0.

Here are the results of my version:

n:= 3:
for k from 0 to n do
     A[k]:= eval(diff(F(add(lambda^i*exp(y[i]), i= 0..k)), [lambda$k]), lambda= 0)/k!
end do;

                        

Try

CodeGeneration:-C([L], resultname="L11", output="dSpDdx1.cpp");

Your current L is a an expression sequence of three terms, not a "vector". When it is passed to CodeGeneration:-C, it is treated as three separate arguments, and any argument after the first is expected to be a option. By enclosing it in square brackets [L], you make it into a list (which is still not exactly a vector, but it's close enough), which will be treated as a single argument.

I have some concern that you are using coeffs to extract the "unevaluated variables" of term. That will only work for a linear polynomial. The correct way to extract the symbolic (i.e., "unevaluated") names (i.e., "variables") from an expression term is

L:= indets(term, And(name, Not(constant)));

That makes L a set; the corresponding list is [L[]]. So, the C call would be

CodeGeneration:-C([L[]], ...);

 

Use

Sol:= solve(
     k^4-k^2*(4*u*m+2*q^2)+k*(8*m*E*q)+4*m^2*(D^2-e^2+(q^2/2*m-u)^2),
     k,
     Explicit
);

Then the four (quite lengthy) solutions can be accessed as Sol[1], ..., Sol[4].

The following worksheet shows what single-level evaluation means. However this is NOT what Preben was trying to explain. What he was trying to explain is that what appears after the arrow -> incurs no evaluation at all at the time that the arrow command is given. Evaluation only occurs when that procedure is later invoked. If you want an expression to be first evaluated and then turned into a procedure, then use unapply rather than the arrow.

Perhaps it'd be best if I stated a rule of thumb for when to use unapply without mentioning the oft-confusing topic of evaluation. So, here it is: If you have an expression that you want to turn into a procedure and that expression contains an indirect reference to a variable that you want to be a parameter of the procedure, then use unapply. This is an indirect reference to x:

f1:= 1+x:
f:= x-> f1:

And this is a direct reference to x:

f:= x-> 1+x:

 

restart:

What follow are two examples of single-level evaluation, the first in a procedure (with local variables) and the second outside a procedure (with global variables).

P:= proc()
local a, b;
     b:= a;
     a:= 1;
     return b
end proc:

P();

a

(1)

%;

1

(2)

restart:

b:= a;  a:= 1;

a

 

1

(3)

eval(b,1);

a

(4)

%;

1

(5)

restart:

What follow are two examples of full evaluation, the first in a procedure (with local variables) and the second outside a procedure (with global variables).

P:= proc()
local a, b;
     b:= a;
     a:= 1;
     return eval(b)
end proc:

P();

1

(6)

restart:

b:= a; a:= 1;

a

 

1

(7)

b;

1

(8)

Note that with local variables, eval is used to force full evaluation, whereas with global variables full evaluation happens by default. With global variables, eval(..., 1)  is used to force single-level evaluation, whereas with local variables it happens by default.

 

Download SingleEval.mw

 

@mapleq2013 You asked some important questions. I'll answer them one by one.

Dt:= unapply(LinearAlgebra:-Determinant(C), (y,x)):

So the unapply here is to convert the expression in x and y into a function, is my understanding correct?

Yes.

If correct, why do we have to do this?

It isn't totally necessary. What's necessary is to compute the determinant outside the call to fsolve or else the determinant would be recomputed for every point (x,y). I could do

Dt:= LinearAlgebra:-Determinant(C):

and then in the call to fsolve replace Dt(y,x) with a call to eval. The unapply syntax is less convoluted.

solD||n:= subs(_n= n, (y,x)-> Re(fsolve(Dt(y,x), w, complex)[_n]))

I don't understand why there is a _n=n

The underscore can be used in a variable name just like any letter.

is it just to avoid using n=n?

That wouldn't work because the left n would evaluate to a number and thus wouldn't match the n (instead of _n) to the right of the ->. This latter n would still be n, because nothing on the right side of an arrow evaluates. But subs('n'= n, ...) would work.

So can I use k=n alright?

You could. However there's a convention that global variables beginning with underscore are never assigned values (except those beginning _Env, called environment variables). What I need in this situation is a global variable without an assigned value. So, by convention, these dummy variables in procedure definitions usually have names beginning with underscore.

Also you mentioned using a procedure, and the usually way I understand procedures is like:

function:= proc(parameter):: returnType
                         procedure content
   end proc

But the procedure you defined is not of the above structure, so I'm a little confused.

The three most common ways to define a procedure are with the arrow ->, with proc (as you describe), and with unapply. (There are also some much more obscure ways that are only used in low-level programming.) Procedures defined with the arrow are often colloquially called functions or operators; however, those words also have more general meanings. Only the word procedure precisely captures the meaning. After they've been created, there's no practical difference between procedures created by any of these methods.

The subs command, why do we need it?

The dummy variable _n in the procedure needs to have an integer value from 1 to 6 substituted for it.

Can I simply write 

solD||n:= (y,x)-> Re(fsolve(Dt(y,x), w, complex)[n]) 

It doesn't work because the second n, being part of a procedure definiton (because it's on the right side of an arrow), won't evaluate at the time of definition even though the n, being a for loop index, has a numeric value at the time.

And how is subs different from eval.

The difference is often subtle, and the two are often interchangeable. I recommend that you read their help pages for more details. But in this particular situation there's no subtlety: Only subs can be used on the outside of a procedure definition to replace a dummy variable inside the definition. This important and fundamental usage of subs is unfortunately not documented on its help page.

 

It isn't true that -> is a "short form" of unapply. Rather, x-> f1 is a short form of proc(x) f1 end proc. If you want a short form for unapply, you could do this:

`&->`:= (x,f)-> unapply(f,x):

Now &-> is short for unapply, and x &-> f1 will return x -> 1+x.

If you want to force the evaluation of f1 in the expression x-> f1, you could do

subs('f1'= f1, x-> f1);

This is just an example, not a recommended coding practice. Indeed, it won't work inside a larger procedure.

You need to use fsolve instead of solve. Since the equation being solved is a polynomial, fsolve (with option complex) will always give six solutions. The call to fsolve needs to be wrapped in a procedure because numeric values for x and y won't be available until they're supplied by plot3d. I made six procedures---one for each of the six eigenvalues.

At the point where you define the matrix C, get rid of the fnormal. Why reduce the precision at this point? Then include these lines:

Dt:= unapply(LinearAlgebra:-Determinant(C), (y,x)):
for n to 6 do
      solD||n:= subs(_n= n, (y,x)-> Re(fsolve(Dt(y,x), w, complex)[_n]))
end do:
plot3d(solD1, -Pi..Pi, -Pi..Pi);

Likewise, you can plot any of the six.

This code can be made faster: The same fsolve is being called six times for each pair (x,y). I can make it faster if you need that.

While waiting for your upload, here's an example of using NonlinearFit with a procedure that has an if statement:

P||(1..2):= 'randpoly(x, degree= 1)' $ 2:
F:= piecewise(x < 0, P1, P2);

X:= Vector(RandomTools:-Generate(list(float(range= -1..1, method= uniform), 99))):
Y:= unapply(F,x)~(X):
M:= proc(x, m1, m2, b1, b2)
     if x < 0 then
          m1*x+b1
     else
          m2*x+b2
     end if
end proc:
Statistics:-NonlinearFit(M, X, Y, output= parametervalues);

We see that the fit is near perfect. (But, of course, every point was exactly computed from the original function.)

First 250 251 252 253 254 255 256 Last Page 252 of 395