I am completely baffled by this.
I noticed when a proc deep inside one of my modules is reached, where the original call was generated from command line, it works correctly than when the same proc is reached when the call flow is originated from inside another proc which is called from the command line.
I found it comes down to this one line. In the debugger, I see this
if hastype(z,radical) then
...
This gives false in the second case, and it gives true when called in the first case. It should give true in both cases.
In the debugger, I look at z, it says it has this value
1/x*sqrt(x^2*u)
Now, in the debugger command, when I type
hastype(z,radical)
It gives false. But when I type the actual value of u into the command:
hastype(1/x*sqrt(x^2*u),radical)
Now it gives true!
Everything is local to this proc:
dsolve_step:-dsolve_step_homog:-convert_to_homog := proc(f0, x, y, u)
local f, z, tmp;
1 f := f0;
2 f := subs(y = u*x,expand(f));
3 for z in op(f) do
4 ! if hastype(z,radical) then ##<=======
5 tmp := sqrt(collect(z^2,x));
6 f := subs(z = tmp,f)
end if
end do;
7 return simplify(f)
end proc
So I have no idea why hastype(z,radical) gives false, and hastype(1/x*sqrt(x^2*u),radical) gives true, when z itself is 1/x*sqrt(x^2*u).
And this happens only when I call the module as in case 2 described above.
As you can see, everything is local. z,f,tmp are local. Same call the the above
function is made from both cases. All the input is the same in both cases.
Here are screen shots from the actual debugging:
Now I check
Now I check by type the actual z value shown
It seems like scoping issue, which I can't figure what it is. May be what I am looking at, is not what it appears to be.
Again, the same call works OK when I call the module from the command line, from another worksheet.
Both worksheets (case 1 and case 2), use different math engines. (I set up Maple to start new math engine for each work sheet to be safe)
I am looking for any suggestion why this happens. The calling proc in the second case, does not use any global variables either. I always start from clean kernel (restart).
Any hint what is going on and what to look for? Or what to try to find what is the problem?
Maple 2018.1, windows 10.
Update
I found the problem. But I really think this is a bug in Maple.
I found if I use eval(z) then it works in the second case, like this:
if hastype(eval(z),radical) then
Now I get true:
I do not see why I need to add eval() there, since Maple should automatically evaluate z to its value when using for z in op(f) do and then reference z inside the loop.
So my question has changed to: Why is eval() needed here?
Any way, I have a workaround for this. But this makes no sense to me now.
convert_to_homog:=proc(f0,x,y,u)
local f,z,tmp;
f:=f0;
f:=subs(y=u*x,expand(f));
#this below can give wrong answer sometimes. It tries to
#change 1/X*sqrt(x^2) to sqrt(1)
#by moving x under the sqrt. But this is valid only when x>0
# i..e 1/x => sqrt(1/x^2) only when x>0
#keep it for now, until I implement exact solver.
for z in op(f) do
if hastype(eval(z), radical) then
tmp:=sqrt(collect(z^2,x));
f:=subs(z=tmp,f);
fi;
od;
return(simplify(f));
end proc;
Of key importance here is that (as shown by you), the value of z is involves an unevaluated call to sqrt and not something to power 1/2.
The unevaluated sqrt call is not of type radical, though what it evaluates to is of that type.
First, let's deal with such an unevaluated call to sqrt at the top-level (ie. not inside any procedure body). We first assign to name z the expression containing the unevalated call to sqrt.
We'll test the type of 1-level evaluation of name z, as well as the full evaluation of the name z.
restart;
z := '1/x*sqrt(x^2*u)';
2
sqrt(x u)
z := ----------
x
1-level evaluation of z produces its value, but with no other evaluation. The sqrt call remains unevaluated.
eval(z, 1); # 1-level evaluation
2
sqrt(x u)
----------
x
The unevaluated call to sqrt is not of type radical.
hastype(eval(z, 1), radical);
false
Now here is the full evaluation of z, which is default behavior at the top-level.
eval(z); # full evaluation
2 1/2
(x u)
---------
x
z;
2 1/2
(x u)
---------
x
Passing z to hastype now passes the full evaluation to hastype. That is, the expression passed to hastype now contains something to power 1/2, and it recognized as being of type radical.
hastype(z, radical);
true
Now read this, from a bullet point in the section "Evaluation Rules" on the help-page for TOPIC proc,
"Within a procedure, during the execution of its
statementSequence, local variables have single level
evaluation. This means that using a variable in an
expression will yield the current value of that variable,
rather than first evaluating that value."
Let's look at a similar example as above, but within a procedure.
First, we'll deal with z in the procedure. As earlier, the name z is assigned the expression containing the unevaluated sqrt call. In contrast to the top-level behavior, within the procedure the assigned local z is evaluated only 1-level.
restart;
f := proc( f0 )
local z;
lprint( f0 );
z := f0;
lprint( z );
hastype(z, radical);
end proc:
f( '1/x*sqrt(u*x^2)' );
1/x*sqrt(u*x^2)
1/x*sqrt(u*x^2)
false
And now we'll alter the procedure to deal with eval(z), which gets the expression containing something to power 1/2.
restart;
f := proc( f0 )
local z;
lprint( f0 );
z := f0;
lprint( eval(z) );
hastype(eval(z), radical);
end proc:
f( '1/x*sqrt(u*x^2)' );
1/x*sqrt(u*x^2)
1/x*(u*x^2)^(1/2)
true
So it appears that you are experiencing the documented and intended behavior for evaluation of assigned local variables within a procedure. That is not a bug.
You have only supplied a fragment of the code, and have not shown exactly what are the arguments f0, x, y, u passed to procedure convert_to_homog. But you have shown that local z is 1/x*sqrt(x^2*u) and not 1/x*(x^2*u)^(1/2) and if that is true then it is not a bug that hastype(z,radical) returns false.
With you current set up, yes, you can pass eval(z) to hastype and get the true result you expect.
But perhaps you should also re-examine why z is being assigned the unevaluated expression in the first place. Is that deliberate, or because of accidental programming earlier?
Related
I'm new to Maple and I'm looking for a simple way to automate some tasks. In particular, I'm looking for a way to define custom "action" that perform some steps automatically.
As as an example I would like to define a quick way to compute the determinant of the Hessian of a polynomial. Currently the way I do this is opening Maple, create a new worksheet than performing the following commands:
p := (x, y) -> x^2*y + 3*x^3 + y^3
with(VectorCalculus):
h := Hessian(p(x, y), [x, y])
Determinant(h)
What I would like to do is to compute the hessian determinant directly with something like
HessDet(p)
where HessDet would be a custom command that performs the operations above. How does one achieve something like this in Maple?
First things first: The value assigned to your p is a procedure which can return a polynomial expression, but not itself a polynomial. It's important not to muddle expressions and procedures. Doing so is a common cause of problems for new users.
Being able to throw around p(x,y) may be visually pleasing to your eye, but it serves little programmatic purpose here. The fact that the formal parameters of procedure p happen to be called x and y, along with the fact that you called procedure p with arguments x and y, is actually just another common source of confusion. Don't create procedures merely to call them in this way.
Also, your call p(x,y) makes it look magic that your code snippet "knows" how many arguments would be required by procedure p. So it's already a muddle to have your candidate HessDet accept p as a procedure.
So instead let's keep it straightforward, by writing HessDet to accept a polynomial rather than a procedure. We can programmatically ascertain the names in which this expression of of type polynom.
restart;
HessDet:=proc(p::algebraic)
local H,vars;
vars:=indets(p,
And(name,Non(constant),
satisfies(u->type(p,polynom(anything,u)))));
H:=VectorCalculus:-Hessian(p,[vars[]]);
LinearAlgebra:-Determinant(H);
end proc:
Now some examples of using it,
P := x^2*y + 3*x^3 + y^3;
HessDet(P);
p := (x, y) -> x^2*y + 3*x^3 + y^3;
HessDet(p(x,y));
HessDet(x^3-x^2+4*x);
HessDet(s^2*t + 3*s^3 + t^3);
HessDet(s[r]^2*t[r] + 3*s[r]^3 + t[r]^3);
You might also wonder how you could re-use this custom procedure across sessions, without having to type it in each time. Two reasonable ways are:
Put the (above) defining plaintext definition of HessDet inside a personal initialization file.
Create a (.mla) Maple Library Archive file, then Save your HessDet to that, and then augment the Library search path in your initialization file.
It might look like 2) is more effort, but only the Save step is needed for repeats, and you can store many custom procedures to the same archive. Your choice...
[edit] The OP has asked for clarification of the first part of the above procedure HessDet, which I suspect means the call to indets.
If P is assigned an expression then then the call indets(P,name) will return a set of all the names present in that expression. Basically, it returns the set of all indeterminate subexpressions of the expression which are of type name in Maple's technical sense.
For example,
P := x*y + sin(a*Pi)*x;
x y + sin(a Pi) x
indets( P,
name );
{Pi, a, x, y}
Perhaps the name of the constant Pi is not wanted here. Ie,
indets( P,
And( name,
Non(constant) ) );
{a, x, y}
Perhaps we want only the non-constant names in which the expression is a polynomial? Ie,
indets( P,
And( name,
Non(constant),
satisfies(u->type(p,polynom(anything,u))) ) );
{x, y}
That last result is an advanced way of using the following tests:
type(P, polynom(anything, x));
true
type(P, polynom(anything, y));
true
type(P, polynom(anything, a));
false
A central issue here is that the OP made no mention of what kind of polynomials are to be handled by the custom procedure. So I guessed with some defensive coding, in hope of less surprises later on. The original Question states that the input could be a "polynomial", but we weren't told what kind of coefficients there might be.
Perhaps the coefficients will always be real and exact or numeric. Perhaps the custon procedure should throw an error when not supplied such. These details weren't mentioned in the Question.
Consider this code.
foo(int x, int y){
x = y + 1;
y = 10;
x++;
}
int n = 5;
foo(n,n);
print(n);
if we assume that the language supports pass-by-value result, what would be the answer? As far as I know, pass-by-value-result copies in and out. But I am not sure what would be n's value when it is copied to two different formal parameters. Should x and y act like references? Or should n get the value of either x or y depending on which is copied out last?
Thanks
Regardless of whether it's common pass-by-value or pass-by-value-result, then x and y would become separate copies of n, they are in no way tied to each other, except for the fact they start with the same value.
However, pass-by-value-result assigns the value back to the original variables upon function exit meaning that n would take on the value of x and y. Which one it gets first (or, more importantly, last, since that will be its final value) is open to interpretation since you haven't specified what language you're actually using.
The Wikipedia page on this entry has this to say on the subject ("call-by-copy-restore" is its terminology for what you're asking about, and I've emphasised the important bit and paraphrased to make it clearer):
The semantics of call-by-copy-restore also differ from those of call-by-reference where two or more function arguments alias one another; that is, point to the same variable in the caller's environment.
Under call-by-reference, writing to one will affect the other immediately; call-by-copy-restore avoids this by giving the function distinct copies, but leaves the result in the caller's environment undefined depending on which of the aliased arguments is copied back first. Will the copies be made in left-to-right order both on entry and on return?
I would hope that the language specification would clarify actual consistent behaviour so as to avoid all those undefined-behaviour corners you often see in C and C++ :-)
Examine the code below, slightly modified from your original since I'm inherently lazy and don't want to have to calculate the final values :-)
foo(int x, int y){
x = 7;
y = 42;
}
int n = 5;
foo(n,n);
print(n);
The immediate possibilities I see as the most likely are:
strict left to right copy-on-exit, n will become x then y, so 42.
strict right to left copy-on-exit, n will become y then x, so 7.
undefined behaviour, n may take on either, or possibly any, value.
compiler raises a diagnostic and refuses to compile, if it has no strict rule and doesn't want your code to end up behaving in a (seemingly) random manner.
If I have a function f(x,y), I want to know how to define another function (say g) where g(x) = f(x,y), where y has been defined beforehand, either explicitly or as the input of another function.
I know this is probably quite simple but my code does not seem to work and I cannot find a solution in the documentation.
You are probably looking for anonymous functions.
A very common use-case is minimiziation. You often need to minimize a function of multiple variables along a single parameter. This leaves you without the option of just passing in constants for the remaining parameters.
An anonymous definition of g would look like this:
g = #(x) f(x, y)
y would have to be a variable defined in the current workspace. The value of y is bound permanently to the function. Whether you do clear y or assign a different value to it, the value of y used in g will be whatever it was when you first created the function handle.
As another, now deleted, answer mentioned, you could use the much uglier approach of using global variables.
The disadvantages are that your code will be hard to read and maintain. The value of the variable can change in many places. Finally, there are simply better ways of doing it available in modern versions of MATLAB like nested functions, even if anonymous functions don't work for you for some reason.
The advantages are that you can make g a simple stand alone function. Unlike the anonymous version, you will get different results if you change the value of y in the base workspace, just be careful not to clear it.
The main thing to remember with globals is that each function/workspace wishing to share the value must declare the name global (before assigning to it to avoid a warning).
In the base workspace:
global y
y = ...
In g.m:
function [z] = g(x)
global y;
z = f(x, y);
I am not particularly recommending this technique, but it helps to be aware of it in case you can't express g as a single statement.
A note about warnings. Both anonymous functions and globals will warn you about assigning to a variable that already exists. That is why putting a global declaration as the first line of a function is generally good practice.
f = #(a,b) a^2 + b^2;
y = 4;
g = #(x) f(x,y);
g(2)
ans = 20
I am doing another coursera assignemnt, this time with aerial robotics. I have to program a pd controller using the matlab ode45 (ordinary diff. equation). And the file that has to contain this code gets called as follows:
pd_controller(~, s, s_des, params)
I searched around but couldn't find anthing that explain this to me and how it works.
In the main program the function is called with a time variable which I would need for my ODE:
controlhandle(t, s, s_des, params)
Where this controlhandle is the functionhandler for pd_controller.
So, what does this mean? And can I access whatever is behind ~?
Besides:
I found one example, but the other around. A function, let's call it function = f(a,b) was called with f(~, b) where a and b has been declared inside the function.
The symbol is called a tilde, and it signifies that you are ignoring that input argument.
See the documentation here: https://mathworks.com/help/matlab/matlab_prog/ignore-function-inputs.html
In your case, the function controlhandle will not be passed a t variable, and probably has (should have) some check for this and perhaps a default t if none is given.
This works the same with output arguments, for example if you want the index of a max in an array, but not the max itself, you would use
a = [pi, 3.6, 1];
[~, idx] = max(a); % idx = 2, we don't know what the max value is
It means you don't need pass this parameter in this function call. Also, you can use it in the output of some functions too. For example:
A = [1 4 2 2 41];
[~, B] = sort(A);
this means you don't need the second output, and you can ignore that.
In your case, when no value sent for the first parameter t, probably the function acts on a default value for t in his computation.
Also, you can find more about that in matlab documentation.
I should have mentioned that this post exists as an answer, but it might be here instead.
I'm using MATLAB 2012b.
I want to get d²/dxdy of a simple function:
f(x,y) = (x-1)² + 2y²
The documentation states that I can use syms and diff as in the following example:
> syms x y
> diff(x*sin(x*y), x, y)
ans =
2*x*cos(x*y) - x^2*y*sin(x*y)
But doing the same I got the wrong answer:
> syms x y
> f = (x-1)^2 + 2*y^2;
> diff(f,x,y)
ans =
4*y
The answer is right if I use diff like this:
diff(diff(f,x),y)
Well, it's not a problem for me to use it this way, but nevertheless why is the first variant not working? Is it a version issue?
The actual documentation from R2010a:
diff(expr) differentiates a symbolic expression expr with respect to its free variable as determined by symvar.
diff(expr, v) and diff(expr, sym('v')) differentiate expr with respect to v.
diff(expr, n) differentiates expr n times. n is a positive integer.
diff(expr, v, n) and diff(expr, n, v) differentiate expr with respect to v n times.
So, the command diff(f,x,y) is the last case. It would be equal to differentiating f w.r.t. x, y times, or w.r.t y, x times.
For some reason I don't quite understand, you don't get a warning or error, but one of the syms variables gets interpreted as n = 1, and then the differentiation is carried out. In this case, what diff seems to do is basically diff(f, y, 1).
In any case, it seems that the behavior changed from version to version, because in the documentation you link to (R2016b), there is an additional case:
diff(F,var1,...,varN) differentiates F with respect to the variables var1,...,varN
So I suspect you're running into a version issue.
If you want to differentiate twice, both w.r.t x and y, your second attempt is indeed the correct and most portable way to do that:
diff( diff(f,x), y )
or equivalently
diff( diff(f,y), x )
NB
I checked the R2010a code for symbolic/symbolic/#sym/diff.m and indeed, n is defaulted to 1 and only changed if one of the input variables is a double, and the variable to differentiate over is set equal to the last syms variable in the argument list. The multiple syms variable call is not supported, nor detected and error-trapped.
Syms is only creating symbolic variables.
The first code you execute is only a single derivative. The second code you provided differentiates two times. So I think you forgot to differentiate a second time in the first piece of code you provided.
I am also wondering what answer you expect? If you want 4*y as answer, than you should use
diff(f,y)
and not
diff(f,x,y)
Performing the second derivative is giving me zero?
diff(diff(f,x),y)
If you want 4 as answer than you have to do following:
diff(diff(f,y),y)