Working on a problem in matrix structural analysis. I am writing a program in Python (using Anaconda 3) to analyze a truss. Each individual truss member generates one 4x4 matrix, for a total of n 4x4 matrices. Then, these 4x4 matrices are compiled into an NxN matrix, arranged like so, for matrices A, B, C:
As you can see, each successive submatrix is placed one row over and one row down from the preceding one. Further, because the size of the truss and the number of truss joints (nodes) is specified by the user, the size of the NxN matrix has to be determined dynamically (the submatrices are always 4x4).
I've got an NxN zero matrix; I am trying to figure out how to compile the submatrices correctly.
I found a few similar questions but none of them scaled the larger matrix dynamically.
I appreciate any assistance you folks can provide.
The simple
for
-loop way would be to add each 4x4 matrix to an appropriate slice of the big zero matrix:You could also do this with no Python loops by creating a strided view of the zero matrix and using
np.add.at
for unbuffered addition. This should be particularly efficient if your 4x4 matrices are packed into a k-by-4-by-4 array:Is
n
potentially large, so the result is a large sparse matrix with nonzero values concentrated along the diagonal? Sparse matrices are designed with this kind of matrix in mind (from FD and FE PDE problems). I did this a lot in MATLAB, and some with thescipy
sparse module.That module has a block definition mode that might work, but what I'm more familiar with is the
coo
tocsr
route.In the
coo
format, nonzero elements are defined by 3 vectors,i
,j
, anddata
. You can collect all the values forA
,B
, etc in these arrays (applying the appropriate offset for the values inB
etc), without worrying about overlaps. Then when that format is converted tocsr
(for matrix calculations) the overlapping values are summed - which is exactly what you want.I think the
sparse
documentation has some simple examples of this. Conceptually the simplest thing to do is iterate over then
submatrices, and collect the values in those 3 arrays. But I also worked out a more complex system whereby it can be done as one big array operation, or by iterating over a smaller dimension. For example each submatrix has 16 values. In a realistic case 16 will be much smaller than n.I'd have play around with code to give a more concrete example.
==========================
Here's a simple example with 3 blocks - functional, but not the most efficient
Define 3 blocks:
lists to collect values in; could be arrays, but it is easy, and relatively efficient to append or extend lists:
If I've done this right, overlapping values of A,B,C are summed.
More generally:
Coming up with a way of doing this more efficiently may depend on how the individual submatrices are generated. If they are created iteratively, you might as well collect the i,j,data values iteratively as well.
==========================
Since the submatrices are dense, we can get the appropriate
i,j,data
values directly, without going through acoo
intermediary. And without looping if theA,B,C
are collected into one larger array.If I modify
foo1
to return acoo
matrix, I see thei,j,data
lists (as arrays) as given, without summation of duplicates. In the example with 5 matrices, I get 80 element arrays, which can be reshaped asI should be able generate those without a loop, especially the
row
andcol
.the coordinates for the elements of an array
replicate them with offset via broadcasting
Collect the data into one large array:
or as a compact function
In this modest example the 2nd version is 2x faster; the first scales linearly with the length of the list; the 2nd is almost independent of its length.