7
$\begingroup$

I want to assign new values to the anti-diagonal elements of a square matrix m with the values of its diagonal elements. For that, I want to make use of ReplacePart, with the fact that

Part position specifications can be patterns

as stated in the documentation.

I want to use a command like this:

ReplacePart[m, (*pattern goes here*) :> Diagonal[m]〚i〛]

I need help with writing a pattern to access the anti-diagonal elements.

They have the property of i+j=Length[m]+1 but I can't find a way to implement it into a pattern match.

For example, with

m={
  {100, 9, 3, 8, 0},
  {4, 200, 6, 4, 9},
  {5, 2, 300, 7, 8},
  {7, 9, 6, 400, 5},
  {6, 1, 4, 2, 500}
}

I want to produce the matrix

{
  {100, 9, 3, 8, 100},
  {4, 200, 6, 200, 9},
  {5, 2, 300, 7, 8},
  {7, 400, 6, 400, 5},
  {500, 1, 4, 2, 500}
}
$\endgroup$
2
  • 2
    $\begingroup$ use the replacement rule {i_, j_} /; j == Dimensions[m][[2]] + 1 - i :> Diagonal[m][[i]]? $\endgroup$
    – kglr
    Jun 23, 2022 at 21:15
  • $\begingroup$ Well I am a bit new to conditions and pattern matching. I didn't know how to write it down.. $\endgroup$
    – tush
    Jun 23, 2022 at 21:18

8 Answers 8

5
$\begingroup$

This is the kind of question that might trigger the "how-many-ways-can-you-do-it" game. I'll kick it off with this:

MapIndexed[ReplacePart[#1, -#2 -> #1[[#2[[1]]]]] &, m]

Explanation: The index of each row corresponds to the element that should be used as replacement as well as the one to be replaced (just count from the end). So, that suggested using MapIndexed. Then it's a matter of figuring out how to put the MapIndexed arguments into ReplacePart.

$\endgroup$
2
  • 4
    $\begingroup$ The ReplacePart[]+MapIndexed[] is a good idea. Here's a slightly more compact version: ReplacePart[m, MapIndexed[Join[#2, -#2] -> #1 &, Diagonal[m]]]. $\endgroup$ Jun 23, 2022 at 21:46
  • $\begingroup$ That’s excellent! $\endgroup$
    – lericr
    Jun 23, 2022 at 21:49
7
$\begingroup$

From The Procedural Dodo:

If you can do it in place (destroying the orginal m), this will be fast:

Do[m[[i, -i]] = m[[i, i]], {i, Length@m}]

If m is a small matrix as in the example, then speed won't matter, but the code is easy to read.

To preserve m, use another variable:

m2 = m;
Do[m2[[i, -i]] = m2[[i, i]], {i, Length@m2}]

It's still relatively fast, but now m has to be copied.

$\endgroup$
5
$\begingroup$

Using ReplacePart:

ReplacePart[Association[Thread[Map[{# + 1, Length[m] - #} &, Range[0, Length[m] - 1]] -> Diagonal[m]]]][m] // MatrixForm

enter image description here

$\endgroup$
4
$\begingroup$
  • We can subtract the anti-diagonal to remove it and then add the Reverse of diagonal.
m = {{100, 9, 3, 8, 0}, {4, 200, 6, 4, 9}, {5, 2, 300, 7, 8}, {7, 9, 
    6, 400, 5}, {6, 1, 4, 2, 500}};
antiDiagonal = Reverse[DiagonalMatrix@Diagonal@Reverse[m, {2}], {2}];
reverseDiagonal = Reverse[DiagonalMatrix@Diagonal@m, {2}];
m - antiDiagonal + reverseDiagonal
% // MatrixForm

enter image description here

  • Or we can at first Reverse the matrix m to get the rm and subtract the Diagonal of rm and then Reverse.
m = {{100, 9, 3, 8, 0}, {4, 200, 6, 4, 9}, {5, 2, 300, 7, 8}, {7, 9, 
    6, 400, 5}, {6, 1, 4, 2, 500}};
rm = Reverse[m, {2}];
Reverse[rm - DiagonalMatrix@Diagonal@rm + 
  DiagonalMatrix@Diagonal@m, {2}]
% // MatrixForm
$\endgroup$
3
$\begingroup$

use element-wise operation.

  1. keep the diag-matrix and reverse it.
anti = mat //
Diagonal // (*take diag*)
DiagonalMatrix // (*make mat*)
Map[Reverse] (*rev it*)

{{0, 0, 0, 0, 100}, {0, 0, 0, 200, 0}, {0, 0, 300, 0, 0}, {0, 400, 0, 0, 0}, {500, 0, 0, 0, 0}}

  1. make the mask mat
mask = IdentityMatrix[Length@mat]// (*np.eye*)
Map[Reverse] // (*rev*)
1-#& (*mask*)

{{1, 1, 1, 1, 0}, {1, 1, 1, 0, 1}, {1, 1, 0, 1, 1}, {1, 0, 1, 1, 1}, {0, 1, 1, 1, 1}}

  1. mask it then add anti
mat * mask + anti

{{100, 9, 3, 8, 100}, {4, 200, 6, 200, 9}, {5, 2, 300, 7, 8}, {7, 400, 6, 400, 5}, {500, 1, 4, 2, 500}}

$\endgroup$
3
$\begingroup$
idm = IdentityMatrix[Length@m]
(res = Reverse /@ (m idm) + m (-(Reverse /@ idm ) + 1)
  ) // MatrixForm

$$\left( \begin{array}{ccccc} 100 & 9 & 3 & 8 & 100 \\ 4 & 200 & 6 & 200 & 9 \\ 5 & 2 & 300 & 7 & 8 \\ 7 & 400 & 6 & 400 & 5 \\ 500 & 1 & 4 & 2 & 500 \\ \end{array} \right)$$

$\endgroup$
2
$\begingroup$
With[
  {mask = 
     Reverse[ReplaceAll[DiagonalMatrix[Function /@ Diagonal[m]], 0 -> Identity], 2]},
  MapThread[Construct, {mask, m}, 2]]
$\endgroup$
2
$\begingroup$

Making use of the method posted by ciao (in an answer to How to zero (or replace) the diagonal of a square matrix?)

With[{rm=Reverse@m, dr=Reverse@Diagonal@m},

    (UpperTriangularize[rm,1] + LowerTriangularize[rm,-1] + DiagonalMatrix[dr])//Reverse

    ]

$$ \left( \begin{array}{ccccc} 100 & 9 & 3 & 8 & 100 \\ 4 & 200 & 6 & 200 & 9 \\ 5 & 2 & 300 & 7 & 8 \\ 7 & 400 & 6 & 400 & 5 \\ 500 & 1 & 4 & 2 & 500 \\ \end{array} \right) $$

Alternatively:

Reverse[UpperTriangularize[Reverse@m,1] + LowerTriangularize[Reverse@m,-1]] + 
SparseArray[Band[{1, 5}, Automatic, {1, -1}] -> Diagonal[m], {5, 5}]

(*
{
 {100, 9, 3, 8, 100}, 
 {4, 200, 6, 200, 9}, 
 {5, 2, 300, 7, 8}, 
 {7, 400, 6, 400, 5}, 
 {500, 1, 4, 2, 500}
} 
*)

Also related:

Is there a built in function to obtain the back diagonal of a matrix?

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.