# How to zero (or replace) the diagonal of a square matrix?

Zeroing the diagonal of a square matrix is an operation I need frequently, but somehow I still haven't managed to find an elegant solution that satisfies all these requirements:

• works with both numeric and symbolic matrices
• doesn't get tripped up by Infinity or Indeterminate
• doesn't unpack packed arrays
• performs reasonably

So what do you use to zero out your diagonals? Is there any concise implementation for this at all?

Notes: Arithmetic with infinities tends to give indeterminates and DiagonalMatrix strangely doesn't work with inifinities at all (even though it works with symbols). Writing an integer 0 into a packed array of reals unpacks it (or generally, trying to write an un-matching type of integer, real, complex).

• Anything wrong with UpperTriangularize[arg, 1] + LowerTriangularize[arg, -1]?
– ciao
Aug 31, 2015 at 7:21
• @ciao Looks like it might be exactly the thing I need. Can you post it as an answer? Aug 31, 2015 at 7:36
• Done - I was surprised at speed...
– ciao
Aug 31, 2015 at 7:40
• @ciao Thanks! I think this will be very hard to beat, but I'll wait until tomorrow with the accept. And I know the solution looks trivial, but I never thought of this specific one, and all the other (more obvious) ones have problems. Aug 31, 2015 at 7:53
• Well, It seem I have beat that. :)
– yode
Jul 13, 2017 at 20:55

As requested, posting my comment as an answer:

UpperTriangularize[arg, 1] + LowerTriangularize[arg, -1]


seems to meet all the criteria, quite quick (surprisingly so to me).

• @ciao...very nice (as usual) +1 :) Aug 31, 2015 at 7:46

The following works for a numeric matrix, should be OK for symbolic ones

exmat = {{0, 5, 2, 3, 1, 0}, {4, 3, 2, 5, 1, 3}, {4, 1, 3, 5, 3, 2},
{4, 4, 1, 1, 1, 5}, {3, 4, 4, 5, 3, 3}, {5, 1, 4, 5, 2, 0}};

MatrixForm[ReplacePart[exmat, {i_, i_} -> 0]]

(*   0   5   2   3   1   0

4   0   2   5   1   3

4   1   0   5   3   2

4   4   1   0   1   5

3   4   4   5   0   3

5   1   4   5   2   0 *)

• This is a good start, so +1, but it fails on one count: if the array is packed, I'd need to explicitly check whether its type is real, integer or complex, and replace with 0., 0 or 0. + 0. I accordingly. Otherwise it unpacks. Aug 31, 2015 at 7:26
• OK now I see what u mean by "packed". Aug 31, 2015 at 7:29
• Aug 31, 2015 at 9:26

### Method one:LinearAlgebraSetMatrixDiagonal

mat = RandomReal[10, {3, 3}];
LinearAlgebraSetMatrixDiagonal[mat,Array[0 &, Length[mat]]] // MatrixForm DeveloperPackedArrayQ[mat]


True

### Method two:LinearAlgebraAddVectorToMatrixDiagonal

mat = RandomReal[10, {3, 3}];
LinearAlgebraAddVectorToMatrixDiagonal[mat, -Diagonal[mat]] // MatrixForm DeveloperPackedArrayQ[mat]


True

ps:Note this two method will change the original mat.

# Compare with ciao's answer here

arg = RandomReal[10, {10^4, 10^4}];
LinearAlgebraSetMatrixDiagonal[arg,Array[0 &, Length[arg]]]; // AbsoluteTiming


{0.406152, Null}

arg = RandomReal[10, {10^4, 10^4}];


{0.356579, Null}

arg = RandomReal[10, {10^4, 10^4}];
AbsoluteTiming[UpperTriangularize[arg, 1] + LowerTriangularize[arg, -1];]


{1.41651, Null}

• cool method +1 ! Jul 13, 2017 at 20:46

Just to play with no great idea to solve all issues... and looking forward to answers. This respects packed arrays but does not deal with Infinity or Indeterminate diagonal entries...

mat = RandomReal[1, {100, 100}];
sa = SparseArray[mat];
zr = 1 - SparseArray[IdentityMatrix]
res = zr sa Although perhaps this unpacks but it seems to be fast:

replaceDiagonal[m_] := Module[{mat = m},
Scan[(mat[[Sequence @@ #]] = 0) &, Table[{i, i}, {i, Length@m}]];
mat];


checking performance:

mat = RandomReal[1, {1000, 1000}];
replaceDiagonal[mat]; // RepeatedTiming

(* {0.04, Null} *)


with a bigger matrix:

mat = RandomReal[10, {10000, 10000}];
replaceDiagonal[mat]; // AbsoluteTiming
(* {2.57671, Null} *)


How does it compare to other methods posted above for matrix of size 1000 x 1000:

@thils method

ReplacePart[mat, {i_, i_} -> 0]; // RepeatedTiming
(* {0.32, Null} *)


@ciao's method

UpperTriangularize[mat, 1] + LowerTriangularize[mat, -1]; // RepeatedTiming
(* {0.01, Null} *)


All the methods give the same result for an input matrix

• Why not simply use Do[mat[[i, i]] = 0., {i, Length@m}]? Also see this comment about condition when this method doesn't unpack. Jul 14, 2017 at 7:44