# Add one to a major diagonal of a matrix given a coordinate point

n = 10;

board = ConstantArray[0, {n, n}];

diag1[x0_, y0_] :=
Module[{x = x0, y = y0},
While[{x != 1 || y != 1},
x--;
y--
];
While[{x != n + 1 || y != n + 1},
board[[x, y]]++;
x++;
y++
]
]


I have an n by n matrix of all zeroes. On a given coordinate in the matrix, I need to increase everything in its major diagonal by one. A runchart of this works fine. All that this does, is increase the (x-1,y-1) by one. I believe that the while loops are only executing the statements once, but I can't be sure.

-
Just edited the title of your question. Please re-edit if I missed your point. – eldo Jul 11 '14 at 21:39

Your definition uses While incorrectly, in that the first argument should evaluate to True when you want to keep looping. The braces you wrap around the first argument mean that instead of True or False you'll get {True} or {False}. While has to see plain True; anything else is treated like False.

Also, your conditions should be conjunctions, not disjunctions. Here is a working edit:

diag1[x0_, y0_] :=
Module[{x = x0, y = y0},
While[x != 1 && y != 1,
x--;
y--
];
While[x != n + 1 && y != n + 1,
board[[x, y]]++;
x++;
y++
]
]


Here's another way that I think is a bit more idiomatic for Mathematica (and which includes some input-checking as well as the state-mutating aspect of your example definition):

ClearAll@diag1;
SetAttributes[diag1, HoldFirst];
diag1[m_Symbol /; MatrixQ@m, r_, c_] /;
(1 <= r <= #1 && 1 <= c <= #2 & @@ Dimensions@m) :=
m += SparseArray[Band[{r, c} - Min[r, c] + 1] -> 1, Dimensions@m]

board = ConstantArray[0, {10, 6}];
diag1[board, 8, 2];
diag1[board, 6, 5];
diag1[board, 1, 5];
board // MatrixForm

-
Can you please explain why the choice of ands instead of ors? I do not need both conditions to be true, I just want whichever becomes true first. Wouldn't that be an or? Also I tried modifying my statement to your first one and it does not work as intended. Instead I am getting the same issue. – ibayibay1 Jul 12 '14 at 3:47
@ibayibay1 You want && because you want to 'back up' x and y as long as neither x nor y equal 1. As soon as one of them equals 1, you're at a top-left edge and you want to stop the loop. Likewise for the second loop, but for the bottom-right edge. I think your intuition toward || was originally pointing you to the equivalent !(x == 1 || y == 1) (via De Morgan) for the first loop. Re it not working as intended, I've tested it again and it works correctly. If you're still stuck, show me your input (including diag1 definition) and your output. – billisphere Jul 12 '14 at 18:23
I got it working. I was using while instead of While. Simple mistake. Thank you though. – ibayibay1 Jul 13 '14 at 7:38
@ibayibay1 That's alright, I've been bitten by casing bugs when using other languages, too. But, I should definitely offer an apology to you here: I edited while in your original question to While and failed to mention this change to you, as I incorrectly assumed it was just a typo during the question write-up and not a typo from your actual definition (and thus an integral part of the question). Sorry for the oversight. (and from this I learn to be more careful in future edits) – billisphere Jul 13 '14 at 17:33
No problem man. Out of curiosity, why does while have a font change to blue, but While does not? That originally made me think while was correct. – ibayibay1 Jul 14 '14 at 17:53

Update: Setting only the major diagonal to 1 (original post set both diagonals to 1):

 ClearAll[diagsF2, saF2];
diagsF2 = Module[{ind = {#, #2}},(Band[ind, Automatic, # {1, 1}] ->1) & /@ {1, -1}] &;
saF2 = SparseArray[diagsF2[#1, #2], {#3, #4}] &;

saF2[2, 3, 5, 5] // Normal
(* {{0,1,0,0,0},{0,0,1,0,0},{0,0,0,1,0},{0,0,0,0,1},{0,0,0,0,0}} *)
saF2[3, 5, 5, 5] // Normal
(* {{0,0,1,0,0},{0,0,0,1,0},{0,0,0,0,1},{0,0,0,0,0},{0,0,0,0,0}} *)

Row[MatrixForm /@ {saF2[2, 3, 5, 5], saF2[3, 5, 5, 5],  saF2[4, 2, 5, 5]}]


board = ConstantArray[0, {10, 6}]; (* @billisphere's example *)
Fold[Composition[Unitize, Plus], board,
saF2[##, 10, 6] & @@@ {{8, 2}, {6, 5}, {1, 5}}] // MatrixForm


Original post:

ClearAll[diagsF, saF];
diagsF = Module[{ind = {#, #2}}, (Band[ind, Automatic, #] -> 1) & /@Tuples[{1, -1}, 2]] &;
saF = SparseArray[diagsF[#1, #2], {#3, #4}] &;

saF[2, 3, 5, 5] // Normal
(* {{0,1,0,1,0},{0,0,1,0,0},{0,1,0,1,0},{1,0,0,0,1},{0,0,0,0,0}} *)

saF[1, 5, 5, 5] // Normal
(* {{0,0,0,0,1},{0,0,0,1,0},{0,0,1,0,0},{0,1,0,0,0},{1,0,0,0,0}} *)

Row[MatrixForm /@ {saF[2, 3, 5, 5], saF[1, 5, 5, 5], saF[3, 5, 5, 5]}]


-
+1 Another nice example: Normal@saF[6, 1, 11] /. (1) :> Style[1, Red] contrasted with saF[6, 11, 11]. – eldo Jul 11 '14 at 21:31
@eldo, thank you... Highlighting the initial entry may be a good variation too. – kglr Jul 11 '14 at 21:40
n = 10;
board = ConstantArray[0, {n, n}];
diag1[x0_, y0_] :=
Module[{x = x0, y = y0, satis},
satis = Select[ Plus[{x, y}, #] & /@ Range[-(n - 1), n - 1],
Max[#] <= n \[And] Min[#] >= 1 &];
MapAt[# + 1 &, board, satis]]

-

May be something like this also will help:

dig[x_, y_, n_] := SparseArray[{Band[{x, y} - (Min[x, y] - 1)] -> 1}, {n, n}] // MatrixForm

dig[3,2,5]


-
This is a near-duplicate of the second part of the answer I provided (~9 hours beforehand). – billisphere Jul 12 '14 at 18:30
@billisphere I just focused on your answer now. yes they are almost similar. – Algohi Jul 12 '14 at 19:05