# Is it possible to implement symbolic sub matrices?

The accepted answer in the question Symbolic matrices in Mathematica with unknown dimensions provides a functionality to create symbolic matrices which behave pretty much as the name suggests. However, there is one problem with those matrices. They cannot be used as submatrices in regular matrices. For instance, if we define:

A1 = SymbolicMatrix["A1", {n, n}];
V1 = SymbolicMatrix["V1", n];
A2 = SymbolicMatrix["A2", {n, n}];
V2 = SymbolicMatrix["V2", n];
M1 = {{m1,Transpose[V1]},{V1,A1}};
M2 = {{m2,Transpose[V2]},{V2,A2}};


The multiplication M1.M2 will carry out simply as a 2x2 matrix multiplication and the operator . will not emerge between i.e. A1 and A2 in the components: As a result, the information that the symbols A1 and A2 do not necessarily commute, is lost. I am not good enough with Mathematica to be able to write an improvement for the above code so that it continues to work properly for submatrices. Therefore, I am forced to ask here if someone could accomplish it?

EDIT: Also, while I'm at it. It appears that the symbolic matrices above cannot be defined as general functions of one or more variables. For instance:

A[u] = SymbolicMatrix["A[u]", {n, n}];


Gives D[A[u],u]=0, which does not behave well. Would it be possible to add this kind of functionality too? I realize that I am asking something relatively involved. Hopefully, there is someone knowledgeable out there who will find it interesting to look into it.

Due to not having such a framework at hand, I used the following workaround, which allowed me to still shorten some computation time as compared to doing everything by hand. It boils down to having a set of conventions in place for how to write functions of arbitrarily many variables (or vectors or matrices of these). Here is a summary of the main ideas:

Choose a set of symbols which you will assign a special meaning in this formalism and will never use in your other definitions. In this example we pick: x,A,B,usedi,nexti,addi,i#, where i# stands for i1, i2, i3, ... etc. x will be a dummy variable allowing for proper differentiation. A and B will be free indices on matrices (or vectors) which are not summed over. i# will be indices which are implicitly summed over (performing matrix multiplication). Therefore, in any expression any index i# should appear either exactly twice or exactly zero times.

Make a clear distinction between simple numbers and functions. For numbers we can write the usual symbols in Mathematics, but functions should always be defined as

Superscript[#,0][x]


where the # is a placeholder for the type of function you prefer. For instance, a simple function $f$ would be Superscript[f,0][x], and a vector of functions (with arbitrarily many components, simply denoted by the free index A) will be Superscript[Subscript[v,A],0][x] and so on (generalisation to matrices or tensors is straightforward).

Along with functions we should define a differentiation scheme. Consider defining:

d[f_,v_]:=D[f,x]/.Superscript[fun_,sup_]'[x]->Superscript[fun,sup+v][x];


Clearly, if we use d[#,#] instead of D[#,#] with arbitrary functions defined as described above, then we can take derivatives with respect to any variables we like. The superscript of a function is zero if it was differentiated zero times. Once differentiation is done, the variables in respect to which the differentiation happens will appear in the superscript, keeping track of the derivatives.

Finally, when we define composite expressions, which feature free indices as well as summed over indices, we make these quantities into functions of the free indices. For example, we could write:

result1[A_,B_] = Superscript[Subscript[M1, A, i1],0][x] Superscript[Subscript[M2, i1, B],0][x];


(Note how the index i1 appears exactly twice, since it is summed over). For example, we could also define:

result2[A_,B_] = Superscript[Subscript[M3, A, i2],0][x] Superscript[Subscript[M4, i2, B],0][x];


And then consider the matrix multiplication of both results:

result1[A,i3]result2[i3,B]


Or, even the derivative with respect to for example y of this whole thing:

d[result1[A,i3]result2[i3,B],y]


Further usage should be intuitively clear at this point.

We should keep track of which indices i# have already been used (they should not appear again in any other expression, which might get combined with i.e. result1[A_,B_], since it would lead to loss of information about which matrix is multiplied with which). If we feel like we could loose track of the i#, it might be convenient to define the following list before we use any of the i#

usedi = {0};


Whenever we want to use an i# in our equations or definitions, we can obtain the proper next number for # by calling nexti given by:

nexti:=Dimensions[usedi][];


And once we use a certain amount of i#s, lets say i1,i2,i3, we should call addi given by

addi[y_] := Module[{}, usedi = ConstantArray[0, nexti + y];];


to append the same amount of zeros to usedi as i#s used, in order for nexti to give us the correct number the next time we call it. This is more of a precaution, in practice I never lost track of my i#s without making use of usedi and the others.

With this the formalism is basically set up. Clearly, using the above it is straightforward to setup "submatrices" (quantities with indices written as subscripts) of actual matrices realised in Mathematica. Like for instance:

Mat[A_,B_] = {{Superscript[s11,0][x],Superscript[Subscript[v1tr,B],0][x]},{Superscript[Subscript[v2,A],0][x],Superscript[Subscript[m,A,B],0][x]}}


This whole business might not look particularly nice or wieldy, but the desired properties of having functions of arbitrary many variables and a submatrix structure is realised.