Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I have a matrix like this:

Reverse@Array[List, {8, 8}] // MatrixForm

matrix

I need a function that given an element of this matrix will return all the elements corresponding to the two diagonals that run through it.

The first diagonal can be found like this:

Diagonal[matrix, j-i]

where {i,j} is the element. How can I get the diagonal that runs orthogonally to this through the same given element {i,j}?

(It is somewhat related to this question but my problem is more that I can't figure out which diagonal I want once I've reversed the matrix.)

share|improve this question
    
You mean without Reverse, right? –  Szabolcs Mar 1 at 20:50
    
@Szabolcs There is a reason why my matrix is reversed but I will gladly accept answers that use a matrix that wasn't reversed to begin with. –  Pickett Mar 1 at 20:55
    
Sorry for being unclear. I was asking, are you looking for answers which don't use Reverse? I posted an answer which does use reverse. –  Szabolcs Mar 1 at 21:33
    
@Szabolcs Your solution is fine, actually it is the same kind of solution I attempted but I somehow never got it to work. Look forward to my +1. –  Pickett Mar 1 at 21:34

5 Answers 5

up vote 6 down vote accepted

As you said, to get the main diagonal through $(i,j)$, you use

Diagonal[mat, j - i]

To get the other one, you can use

Diagonal[Reverse[mat, 2], (Dimensions[mat][[2]] - j + 1) - i]

Check correctness visually:

{i, j} = {3, 5}
MatrixForm[mat /. ((# -> Style[#, Red]) & /@ Diagonal[mat, j - i])]
MatrixForm[
 mat /. ((# -> Style[#, Red]) & /@ 
    Diagonal[Reverse[mat, 2], (Dimensions[mat][[2]] - j + 1) - i])]

share|improve this answer
    
Ahh... come on. One minute faster?? –  halirutan Mar 1 at 21:37
    
@halirutan 1 minute and 53 seconds! :D –  Szabolcs Mar 1 at 21:40

The relation for the indices of matrix diagonals is easy to infer, and you can observe this from the following image:

If $A_{i_0,j_0}=A_{5,3}$ is the chosen element, then the diagonal elements have indices satisfying $i-j = i_0-j_0$ and the skew diagonal elements have indices satisfying $i+j=i_0+j_0$.

The problem is now almost solved! We just feed these exact rules to SparseArray:

Clear@orthoDiags
orthoDiags[{p_, q_}, n_] := 
    SparseArray[{
        {i_, j_} /; j + i == p + q :> 1, 
        {i_, j_} /; i - j == p - q :> 1}, 
        {n, n}
]

and use Pick to extract the elements:

Flatten@Pick[mat, orthoDiags[{5, 3}, 8], 1]

share|improve this answer
    
+1, had same idea, I think it quite elegant since it can be easily generalized to other "shapes". Well done. –  rasher Mar 1 at 22:08

There are many solutions. I like one based on FrobeniusSolve (see e.g. this answer How to find lattice points on a line segment?):

d[i_Integer, j_Integer] /; i > 0 && j > 0 := 
  DeleteCases[ FrobeniusSolve[{1, 1}, i + j], {___, 0, ___}]

Then

matrix[[#1, #2]]& @@@ d[3, 4]
{{8, 6}, {7, 5}, {6, 4}, {5, 3}, {4, 2}, {3, 1}}

yields that second diagonal orthogonal to Diagonal[matrix, 4 - 3].
But as far as you work with matrices like matrix you needn't use neiter Apply nor Part, one has only to put adequate initial values (equations) to FrobeniusSolve.

As an alternative to d function one can use diag based on Array:

diag[i_, j_] := Array[{# + i, j - #} &, i + j - 1, -i + 1]
share|improve this answer

May late entry (called away). Short and sweet I think.

Edit: Ooops, did not read OP closely enough - this works for nXm shapes, not nXmXo... I'll leave answer for searchers with the former unless OP wants removal. See update below...

xDiag[mat_, {er_, ec_}] := 
 SparseArray[{r_, c_} :> mat[[r, c]] /; Abs[r - er] == Abs[c - ec], 
   Dimensions[mat]]["NonzeroValues"]

Row[{(test = Table[10 x + y, {x, 1, 5}, {y, 1, 5}]) // MatrixForm
  , xDiag[test, {2, 3}]},"  "]

enter image description here

After discovering the flaw in the above (shape limited to nXm, and fails with zero elements in diagonals) came up with one I like even better. It is shape agnostic, that is, it works with any array shape treating "diagonals" at the top level:

(* cross diagonals *)
Diag2[mat_, {er_, ec_}] := 
 Join @@ Cases[
   ReplacePart[mat, {r_, c_, ___} /; Abs[r - er] != Abs[c - ec] -> Sequence[]], {__}, {1}]

(* tests *)
Column[{Column[{(test1 = Table[10 x + y, {x, 1, 5}, {y, 1, 5}]) // 
     MatrixForm, xDiag2[test1, {3, 2}]}, Left, 1],
  Column[{(test2 = Array[List, {5, 5}]) // MatrixForm, 
     xDiag2[test2, {3, 2}]}, Left, 1]
   Column[{(test3 = Array[List, {5, 5, 2}]) // MatrixForm, 
     xDiag2[test3, {3, 2}]}, Left, 1]}, Left, 2]

(* results *)

enter image description here

share|improve this answer

As far as I can see, using Diagonal it should be something like this:

extract[m_, {i_, j_}] := 
 {Diagonal[m, j - i], Diagonal[Reverse[m], (i + j) - (Length[m] + 1)]}

And then:

m = Array[List, {8, 8}];
m // MatrixForm

Mathematica graphics

you have:

extract[m,{6,2}]//Column
(* {{5,1},{6,2},{7,3},{8,4}}
   {{7,1},{6,2},{5,3},{4,4},{3,5},{2,6},{1,7}} *)
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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