# Substituting main diagonal elements when a condition is satisfied

I'm trying to substitute the main diagonal elements when their value is less or equal to zero. I've tried the following:

testmat = {{0, 1, 3}, {2, 0, 0}, {2, 4, 1}};
ReplacePart[testmat, {i_, i_} -> $MachineEpsilon /; # <= 0 &]  This doesn't work. I've also used ReplacePart[testmat, Position[testmat, # <= 0 &]->$MachineEpsilon]


but doesn't work either. I've always had a bit a of trouble with patterns and rules. Any good bibliography recommendation is welcome...

ReplacePart[testmat, {i_, i_} /; testmat[[i, i]] <= 0 :> \$MachineEpsilon]


{{2.220446049250313*^-16, 1, 3}, {2, 2.220446049250313*^-16, 0}, {2, 4, 1}}

Also

ReplacePart[testmat,
Select[#[[1]] == #[[2]] &]@Position[testmat, _?(# <= 0 &)] :> $$MachineEpsilon] MapIndexed[If[Equal @@ #2 && # <= 0,$$MachineEpsilon, #] &, testmat, {2}]


same result

• thanks for the answer. However, I don't get why the second line of code would give the same result... Where is the check of the pattern {i_,i_}? Nov 18, 2018 at 0:44
• @Anoldmaninthesea, fixed now.
– kglr
Nov 18, 2018 at 1:06

The same with While and If - less elegant but perhaps easier to read. For your toy matrix, maxi the numbers of rows (columns), i the first column and sth the value you want to replace in the diagonal,

testmat = {{0, 1, 3}, {2, 0, 0}, {2, 4, 1}};
maxi = 3;
i = 1;
sth = 10;


Then

While[i < maxi + 1,
If[testmat[[i, i]] <= 0,
testmat = ReplacePart[testmat, {i, i} -> sth],]; i++]


Output is

{{10, 1, 3}, {2, 10, 0}, {2, 4, 1}}