Is there an elegant way to change the diagonals of a matrix to a new list of values, the equivalent of Band with SparseArray?
Say I have the following matrix (see below)
(mat = Array[Subscript[a, ##] &, {4, 4}]) // MatrixForm
and I'd like to change the main diagonal to the following to get "new mat" (see below)
newMainDiagList = Flatten@Array[Subscript[new, ##] &, {1, 4}]
I know it is easy to change the main diagonal to a given value using ReplacePart. For example:
ReplacePart[mat, {i_, i_} -> 0]
I'd also like not to be restricted to the main diagonal (in the same way that Band is not so restricted with SparseArray)
(The method I use at the moment is the following!)
(Normal@SparseArray[Band[{1, 1}] -> newMainDiagList] +
ReplacePart[mat, {i_, i_} -> 0]) // MatrixForm
(Desired Output is 'new mat')
DiagonalMatrix[list,-k] puts the elements k positions below. diagonal of a square matrix with the elements from list. Different values of k lead to different matrix dimensions. DiagonalMatrix[list,k,n] always creates an n×n matrix, even if this requires dropping elements of list. »
D = diag( v ) returns a square diagonal matrix with the elements of vector v on the main diagonal. D = diag( v , k ) places the elements of vector v on the k th diagonal. k=0 represents the main diagonal, k>0 is above the main diagonal, and k<0 is below the main diagonal.
The diag() function is used to extract a diagonal or construct a diagonal array. If v is a 2-D array, return a copy of its k-th diagonal. If v is a 1-D array, return a 2-D array with v on the k-th diagonal.
Actually, you don't need to use Normal
whatsoever. A SparseArray
plus a "normal" matrix gives you a "normal" matrix. Using Band
is, on initial inspection, the most flexible approach, but an effective (and slightly less flexible) alternative is:
DiagonalMatrix[newDiagList] + ReplacePart[mat, {i_,i_}->0]
DiagonalMatrix
also accepts a second integer parameter which allows you to specify which diagonal that newDiagList
represents with the main diagonal represented by 0.
The most elegant alternative, however, is to use ReplacePart
a little more effectively: the replacement Rule
can be a RuleDelayed
, e.g.
ReplacePart[mat, {i_,i_} :> newDiagList[[i]] ]
which does your replacement directly without the intermediate steps.
Edit: to mimic Band
's behavior, we can also add conditions to the pattern via /;
. For instance,
ReplacePart[mat, {i_,j_} /; j==i+1 :> newDiagList[[i]]
replaces the diagonal immediately above the main one (Band[{1,2}]
), and
ReplacePart[mat, {i_,i_} /; i>2 :> newDiagList[[i]]
would only replace the last two elements of the main diagonal in a 4x4
matrix (Band[{3,3}]
). But, it is much simpler using ReplacePart
directly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With