Search code examples
matlabsymbolic-mathmupad

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:

result from code with sum

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:

result from code with product

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)

enter image description here

Problem: Calculate multinomials of the form

hold(sum(x(i), i=i_0..i_k)^n)

enter image description here

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);

enter image description here

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)

enter image description here

For example, the sum

n := 3:
m := 3:
sumf(x[i], i=1..m)^n = sum(x[i], i=1..m)^n;

enter image description here

would call for these combinations of powers, each of which is one vector alpha:

A := C(n,m)

enter image description here

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))

enter image description here

For example, the number of times that the second composition appears, is:

multinomial(n, A[2])

enter image description here

Summation over all compositions yields:

sum(multinomial(n,A[i])*product(x[t]^A[i][t], t = 1..m), i = 1..nops(A))

enter image description here

The powers are correct, but the coefficients are not. This seems related to the boiled-down abstract problem stated first in this question.


Solution

  • 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

              MuPAD ouput 1

    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

              MuPAD ouput 2


    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

              MuPAD output 3

    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.