rewrite MATLAB to Maple - matlab

I have a small MATLAB symbolic script as following
syms z;
psi(2)=exp(2*z-exp(z))/(1-exp(-exp(z)));
psi(3)=exp(2*z-exp(z))/(1-exp(-exp(z)))*z;
psi(4)=exp(2*z-exp(z))/(1-exp(-exp(z)))*z^2;
f(1,1)=exp(2*z-exp(z))/(1-exp(-exp(z)));
for i=2:4
f(i,1)=diff(psi(i),z);
for j=2:i
f(i,j)=diff(f(i,j-1)/f(j-1,j-1),z);
end
end
given a symbolic vector psi consist of functions of z, it create a lower triangle symbolic matrix f. it works well.
I'm trying to rewrite this part in Maple, which I'm new to. I tried
psi(2) := exp(2*z-exp(z))/(1-exp(-exp(z)));
psi(3) := exp(2*z-exp(z))*z/(1-exp(-exp(z)));
psi(4) := exp(2*z-exp(z))*z^2/(1-exp(-exp(z)));
f(1, 1) := exp(2*z-exp(z))/(1-exp(-exp(z)));
for i from 2 to 4 do f(i,1):=exp(2*z-exp(z))/(1-exp(-exp(z)));
for j from 2 to i do f(i,j):=diff(f(i,j-1)/f(j-1,j-1),z);
od;
od;
something ambiguous in the "diff" line, I just select function definition. if I let it output f(4,4), it report
Error, (in f) too many levels of recursion
but it did print f(4,1).
could some one tell what's wrong? Thanks!

Your code is pretty close (and reminds me how similar these two languages are at times). The reason for the error message is that you need to declare f before you start filling it with values.
Here's one possible solution:
psi[2] := exp(2*z-exp(z))/(1-exp(-exp(z)));
psi[3] := exp(2*z-exp(z))*z/(1-exp(-exp(z)));
psi[4] := exp(2*z-exp(z))*z^2/(1-exp(-exp(z)));
f := Matrix(1..4,1..4):
f[1, 1] := exp(2*z-exp(z))/(1-exp(-exp(z))):
for i from 2 to 4 do
f[i,1] := diff(psi[i],z):
for j from 2 to i do
f[i,j] := diff(f[i,j-1]/f[j-1,j-1],z):
end do:
end do:
f;
Note here that I declare f to be a 4x4 Matrix before I start filling it. Also, here the [] notation is used for specifying indices.
Another option which may scale better for larger problems is to grow your data structure for f as you add values to it. Here we start with a 1x1 Array and add values to it.
psi[2] := exp(2*z-exp(z))/(1-exp(-exp(z)));
psi[3] := exp(2*z-exp(z))*z/(1-exp(-exp(z)));
psi[4] := exp(2*z-exp(z))*z^2/(1-exp(-exp(z)));
f:=Array(1..1,1..1):
f(1, 1) := exp(2*z-exp(z))/(1-exp(-exp(z))):
for i from 2 to 4 do
f(i,1):=diff(psi[i],z):
for j from 2 to i do
f(i,j):=diff(f[i,j-1]/f[j-1,j-1],z):
end do:
end do:
f;
Here you'll notice that we are using the () notation for Array indices at time of creation. If you use an Array for storage, this is one technique that allows for you to grow the Array as you add values.
Now in both cases you can also note that I've used [] to index a term that already exists; square brackets are the default notation in Maple for specifying indices in a data structure.
Also note that I've suppressed output in each loop using the : operator; this way you can just echo back the resulting Matrix f at the end.

Related

Maple Error: final value in for loop must be numeric or character

I have this simple procedure in Maple that I want to plot.
test:=proc(n)
local i,t;
for i from 1 to n do
t:=1;
od;
return t;
end:
The procedure itself works fine.
> test(19)
1
When I want to plot I get the following Error:
> plot(test(x),x=1..10)
Error, (in test) final value in for loop must be numeric or character
Please help
Maple's usual evaluation model is that arguments passed to commands are evaluated up front, prior to the computation done within the body of the command's own procedure.
So if you pass test(x) to the plot command then Maple will evaluate that argument test(x) up front, with x being simply a symbolic name.
It's only later in the construction of the plot that the plot command would substitute actual numeric values for that x name.
So, the argument test(x) is evaluated up front. But let's see what happens when we try such an up front evaluation of test(x).
test:=proc(n)
local i,t;
for i from 1 to n do
t:=1;
od;
return t;
end:
test(x);
Error, (in test) final value in for loop
must be numeric or character
We can see that your test procedure is not set up to receive a non-numeric, symbolic name such as x for its own argument.
In other words, the problem lies in what you are passing to the plot command.
This kind of problem is sometimes called "premature evaluation". It's a common Maple usage mistake. There are a few ways to avoid the problem.
One way is to utilize the so-called "operator form" calling sequence of the plot command.
plot(test, 1..10);
Another way is to delay the evaluation of test(x). The following use of so-called unevalution quotes (aka single right ticks, ie. apostrophes) delays the evaluation of test(x). That prevents test(x) from being evaluated until the internal plotting routines substitute the symbolic name x with actual numeric values.
plot('test(x)', x=1..10);
Another technique is to rewrite test so that any call to it will return unevaluated unless its argument is numeric.
test:=proc(n)
local i,t;
if not type(n,numeric) then
return 'procname'(args);
end if;
for i from 1 to n do
t:=1;
od;
return t;
end:
# no longer produces an error
test(x);
test(x)
# the passed argument is numeric
test(19);
1
plot(test(x), x=1..10);
I won't bother showing the actual plots here, as your example produces just the plot of the constant 1 (one).
#acer already talked about the technical problem, but your case may actually have a mathematical problem. Your function has Natural numbers as its domain, i.e. the set of positive integers {1, 2, 3, 4, 5, ...} Not the set of real numbers! How do you interpret doing a for-loop for until a real number for example Pi or sqrt(2) to 5/2? Why am I talking about real numbers? Because in your plot line you used plot( text(x), x = 1..10 ). The x=1..10 in plot is standing for x over the real interval (1, 10), not the integer set {1, 2, ..., 10}! There are two ways to make it meaningful.
Did you mean a function with integer domain? Then your plot should be a set of points. In that case you want a points-plot, you can use plots:-pointplot or adding the option style=point in plot. See their help pages for more details. Here is the simplest edit to your plot-line (keeping the part defininf test the same as in your post).
plot( [ seq( [n, test(n)], n = 1..10 ) ], style = point );
And the plot result is the following.
In your function you want the for loop to be done until an integer in relation with a real number, such as its floor? This is what the for-loop in Maple be default does. See the following example.
t := 0:
for i from 1 by 1 to 5/2 do
t := t + 1:
end do;
As you can see Maple do two steps, one for i=1 and one for i=2, it is treated literally as for i from 1 by 1 to floor(5/2) do, and this default behavior is not for every real number, if you replace 5/2 by sqrt(2) or Pi, Maple instead raise an error message for you. But anyway the fix that #acer provided for your code, plots the function "x -> test(floor(x))" in your case when x comes from rational numbers (and float numbers ^_^). If you change your code instead of returning constant number, you will see it in your plot as well. For example let's try the following.
test := proc(n)
local i,t:
if not type(n, numeric) then
return 'procname'(args):
end if:
t := 0:
for i from 1 to n do
t := t + 1:
end do:
return(t):
end:
plot(test(x), x=1..10);
Here is the plot.
It is indeed "x -> test(floor(x))".

hyperpolic function integration in maple

Im trying to evaluate this function in maple
but I keep getting this answer, why isn't maple integrating properly. I tried numerically integrating it and it works but I need the analytical solution too.
restart;
sig := x->(exp((x-t)/a)-exp((-x-t)/a))
/(exp((x-t)/a)+exp((-x-t)/a)):
new := convert(simplify(convert(expand(sig(x)),trigh)),tanh);
new := tanh(x/a)
simplify(expand(convert(sig(x) - new, exp)));
0
Now, you originally wrote int(f*sig(x)/x,x).
You didn't indicate that f was a function of x, and as a mere constant it's not really important and could simply be pulled out in front of the integral as a constant factor. If f is some function of x then you really need to state what it is!
Let's consider int(sig(x)/x,x=c..d). Using the simplification new, that is just,
Q := Int( new/x, x=c..d );
Q := Int(tanh(x/a)/x, x = c .. d)
QQ := IntegrationTools:-Change(Q, y=x/a, y);
QQ := Int(tanh(y)/y, y = c/a .. d/a)
You said that you wanted an "analytical solution" by which I take it you mean an explicit formula for the symbolic integration result. But what do you want if the integral does not (mathematically) have a closed form exact, symbolic result?
Would you be content with an (exact, symbolic) series approximation?
H := (a,ord,c,d)
-> int(convert(series(eval(new/x,:-a=a),x,ord),
polynom),x=c..d):
# order 5
H(a, 5, c, d);
3 3 / 5 5\
d - c -c + d 2 \-c + d /
----- - -------- + ------------
a 3 5
9 a 75 a
For a specific example, taking a=2 and an (exact) series approximation of order 25, then the integral from x=0 to x=1 gets evaluated as an exact rational.
evalf(H(2, 25, 0, 1));
0.4868885956
Here's the numeric integration for those same values,
evalf(Int( eval(new/x,a=2), x=0..1 ));
0.4868885956
Specialized numeric quadrature could be as good as a series approximation for a variety of applications, but of course that would depend on what you intend on doing with the result.
This raises the question: what do you hope to do with some supposed "analytical result" that you cannot do with a black-box function that generates the floating-point numeric approximation? Why do you "need" an "analytic result"?
BTW, another way to simplify it (in case the construction above of new does not succeed in your Maple version):
new := convert(simplify(expand( numer(sig(x))/exp(-t/a) ))
/simplify(expand( denom(sig(x))/exp(-t/a) )),
compose,trigh,tanh);
/x\
new := tanh|-|
\a/

Display expression and result of calculation in MuPad

Imagine I define two variables within a MuPad Notebook:
x:=2;
y:=5
For the product
z=x*y
I get displayed:
And if I use hold, I can get the expression:
z=hold(x*y)
But now I'd like to have both, the expression displayed and the result. The two options which appeared logical to me, do not worK:
z=hold(x*y);z
and
z=hold(x*y);eval(z);
How can I get displayed the expression AND the result?
If in two lines it would be alright, but I'd prefer in one line like:
z = x y = 10
I tried some combinations with print, expr2text, hold and _concat but couldn't find a convincing solution to get the desired result. But there is an explanation why the second line just returns z and not 10.
Assignment vs. Equation
z is the result in the second line because you didn't assign something to z yet. So the result says that z is z. In MuPad = is part of an expression. The assignment operator is := and therefore not the same as in Matlab. The only difference between them is the colon.
Writing an equation
For writing an equation, we use = as part of the expression. There is an equivalent function: _equal. So the following two lines generate the same result:
x+y = 2
_equal(x+y, 2)
Assign value to x
For an assignment we use := (in Matlab this would be only =). There is an equivalent function: _assign. So again, the following two lines generate the same result:
x := value
_assign(x, value)
Assign the equation x+y = 2 to eqn
Here we can clearly see the difference:
eqn := x+y = 2
_assign(eqn, _equal(x+y, 2))

MuPAD evaluation of local variables, Sum of row of array

I have discovered a strange behavior in MuPAD version 5.7.0 (MATLAB R2011b), and I would like to know whether this is a bug, and if not so, what I am doing wrong. Ideally, I would also like to know why MuPAD does what it does.
Consider the array C of size 3x3, the elements of which have some example values. I would like to regard this array as an array of arrays and thus use cascaded indexing.
The problem apparently arises when both indices are local variables of different nested scopes, namely when the first index's scope is wider than the second index's one. There is no problem if the first index is a constant.
When I enter:
reset();
C := [[a,b,c],[d,e,f],[g,h,i]];
sum((C[3])[t], t = 1..3);
S := j -> sum((C[j])[t], t = 1..3);
S(3);
I get the following result:
I would expect lines 3 and 5 in the code (2 and 4 in the output) to yield the same result: g+h+i. Instead, line 5 produces a+e+i, which seems to be the diagonal of C.
When I do the same with product instead of sum, the result is even stranger, but might reveal more about the "error's" source, particularly DOM_VAR(0,2):
reset();
C := [[a,b,c],[d,e,f],[g,h,i]];
product((C[3])[t], t = 1..3);
eval(product((C[3])[t], t = 1..3));
S := j -> product((C[j])[t], t = 1..3);
S(3);
eval(S(3));
I get:
I might be on the wrong track here, but I suspect that a closure is created that tried to save the surrounding scope's local variables, which are undetermined at the time of the closure's creation. Also, substitutions seem to stop at some point, which is overridden by eval().
Practical Problem
The practical problem I am trying to solve is the following:
reset();
aVec := Symbol::accentUnderBar(Symbol::alpha)
Problem: Calculate multinomials of the form
hold(sum(x(i), i=i_0..i_k)^n)
On Wikipedia, the following form is defined:
sumf := freeze(sum):
hold(sum(x[i], i=1..m)^n)=sumf(binomial(n,aVec)*product(x[t]^aVec[t], t = 1..m), abs(aVec)=n);
In order to implement this, we need to define the set of vectors alpha, the sum of which equals m.
These correspond to the set of possible compositions of n with length m and possible zero elements:
C := (n,m) -> combinat::compositions(n, MinPart = 0, Length = m)
For example, the sum
n := 3:
m := 3:
sumf(x[i], i=1..m)^n = sum(x[i], i=1..m)^n;
would call for these combinations of powers, each of which is one vector alpha:
A := C(n,m)
Additionally, we need the multinomial coefficients.
Each such coefficient depends on vector alpha and the power n:
multinomial := (n, aVec) -> fact(n) / product(fact(aVec[k]), k = 1..nops(aVec))
For example, the number of times that the second composition appears, is:
multinomial(n, A[2])
Summation over all compositions yields:
sum(multinomial(n,A[i])*product(x[t]^A[i][t], t = 1..m), i = 1..nops(A))
The powers are correct, but the coefficients are not. This seems related to the boiled-down abstract problem stated first in this question.
The expression [[a,b,c],[d,e,f],[g,h,i]] is not an array in MuPAD. It is a "list of lists." I'm guessing that's not what you're after. Lists are commonly used to initialize arrays and matrices and other objects (more here). For these examples, either arrays or matrices will work, but note that these two data types have different advantages.
Using array:
reset();
C := array([[a,b,c],[d,e,f],[g,h,i]]);
sum(C[3, t],t=1..3);
S := j -> sum(C[j, t], t = 1..3);
S(3);
which returns
Note the different way row/column indexing is represented relative to that in your question. Similarly, modifying your other example
reset();
C := matrix([[a,b,c],[d,e,f],[g,h,i]]);
product(C[3, t], t = 1..3);
S := j -> product(C[j, t], t = 1..3);
S(3);
results in
If you do happen to want to use lists for this, you can do so like this
reset();
C := [[a,b,c],[d,e,f],[g,h,i]];
_plus(op(C[3]));
S := j -> _plus(op(C[j]));
S(3);
which returns
The _plus is the functional form of + and op extracts each element from the list. There are other ways to do this, but this is one of the simplest.
I am posting this answer only to provide a working example of the practical problem from the question. horchler provided the decisive solution by proposing to use a matrix instead of a list of lists.
Basically, this is a modified transscript of the practical problem.
Practical Solution
The practical problem I am trying to solve is the following:
reset();
aVec := Symbol::accentUnderBar(Symbol::alpha)
Problem: Calculate multinomials of the form
hold(sum(x(i), i=i_0..i_k)^n)
On Wikipedia, the following form is defined:
sumf := freeze(sum):
hold(sum(x[i], i=1..m)^n)=sumf(binomial(n,aVec)*product(x[t]^aVec[t], t = 1..m), abs(aVec)=n);
In order to implement this, we need to define the set of vectors alpha, the sum of which equals m.
These correspond to the set of possible compositions of n with length m and possible zero elements:
C := (n,m) -> combinat::compositions(n, MinPart = 0, Length = m)
For example, the sum
n := 3:
m := 3:
sumf(x[i], i=1..m)^n = sum(x[i], i=1..m)^n;
would call for these combinations of powers, each of which is one vector alpha:
A := matrix(nops(C(n,m)),m,C(n,m));
Additionally, we need the multinomial coefficients.
Each such coefficient depends on vector alpha and the power n:
multinomial := (n, aVec) -> fact(n) / product(fact(aVec[k]), k = 1..nops(aVec))
For example, the number of times that the second composition appears, is:
multinomial(n,A[2,1..m])
Summation over all compositions yields:
sum(multinomial(n,A[i,1..m])*product(x[t]^A[i,t], t = 1..m), i = 1..nops(C(n,m)));
Finally, prove that the result transforms back:
simplify(%)

Custom correlation function in matlab

I am trying to create a custom function for pearson's correlation coefficient with this code in matlab 2010
function [p] = customcorr(o)
x := a
y := b
x_mean := mean(a)
y_mean := mean(b)
x_std := std(a)
y_std := std(b)
n := length(o)
r := (1/(n-1))*((x-x_mean)*(y-y_mean))/(x_std*y_std)
end
But i get an error when trying to execute it
Error in ==> customcorr at 2
x := a
Anybody might know what the problem is? Thank you
First, check the correct MATLAB syntax: a "normal" assignment is done by =, not by :=.
Second, you use a and b but these are not defined as parameters of the function. Replace the function head by function p = customcorr(a,b).
Third, I am not really sure what o should be, I assume it can be replaced by length(a) or length(b).
The estimator for an unbiased correlation coefficient is given by
(from wikipedia)
Thus you need to sum all the (a-a_mean).*(b-b_mean) up with sum. Note that it is required to write .* to get the element-wise multiplication. That way you subtract the mean from each element of the vectors, then multiply the corresponding a's and b's and sum up the results of these multiplications.
Together this is
function p = customcorr(a,b)
a_mean = mean(a);
b_mean = mean(b);
a_std = std(a);
b_std = std(b);
n = length(a);
p = (1/(n-1)) * sum((a-a_mean).*(b-b_mean)) / (a_std*b_std);
end
What MATLAB does in their corr function (besides many other interesting things) is, they check the number of arguments (nargin variable) to see if a and b were supplied or not. You can do that by adding the following code to the function (at the beginning)
if nargin < 2
b = a;
end