Message Boards Message Boards

0
|
6431 Views
|
6 Replies
|
18 Total Likes
View groups...
Share
Share this post:

[?] Add plus 1 to the {i_,i_} elements in a list?

Posted 7 years ago

I have a list of lists of numbers, for example:

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

The length of the list is the same length of each sublist. What I want to achieve is to add plus 1 to the {i,i} elements without using For cycle. Given the list above as an input, I need a result like this:

{{2,1,1,1}, {1,2,1,1},{1,1,2,1},{1,1,1,2}}
POSTED BY: Ana Reyna
6 Replies

Multi-linearity does not lie in the exercise

In[69]:= Clear[reynaAdd2]
reynaAdd2[m_?MatrixQ ] := Block[
  {x = Dimensions[m], x1 = Dimensions[m][[1]], x2 = Dimensions[m][[2]], x3 = Times @@ Dimensions[m]},
  ArrayReshape[
    Flatten[m] + SparseArray[Table[Rule[o, 1], {o, 1, If[x1 < x2, x3, x2^2], 1 + x2}], {x3}], x
  ]
]

In[71]:= reynaAdd2[ConstantArray[1, {4, 10}]]
Out[71]= {{2, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 2, 1, 1, 1, 1, 1, 1, 1, 1},
          {1, 1, 2, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 2, 1, 1, 1, 1, 1, 1}}

In[72]:= reynaAdd2[ConstantArray[1, {6, 6}]]
Out[72]= {{2, 1, 1, 1, 1, 1}, {1, 2, 1, 1, 1, 1}, {1, 1, 2, 1, 1, 1},
          {1, 1, 1, 2, 1, 1}, {1, 1, 1, 1, 2, 1}, {1, 1, 1, 1, 1, 2}}

In[73]:= reynaAdd2[ConstantArray[1, {10, 4}]]
Out[73]= {{2, 1, 1, 1}, {1, 2, 1, 1}, {1, 1, 2, 1}, {1, 1, 1, 2}, {1, 1, 1, 1},
          {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}

In[74]:= reynaAdd2[ConstantArray[1, {1, 1}]
Out[74]= {{2}}           

but looks good.

POSTED BY: Udo Krause

Here's an alternative for rectangular arrays:

mat = ConstantArray[1, {3, 4}]
mat + SparseArray[{i_, i_} -> 1, Dimensions@mat]
(*
  {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}
  {{2, 1, 1, 1}, {1, 2, 1, 1}, {1, 1, 2, 1}}
*)
POSTED BY: Michael Rogers

SparseArray, when used with a pattern syntax, will generally test all index-pairs of the matrix. That's pretty slow. Therefore I thought that your way of constructing a sparse identity matrix is also slow.

But in reality, the construct you use seems to be special-cased.

At first, I would have expected this to be the fastest way:

n = 1000;
DiagonalMatrix@SparseArray@ConstantArray[1, n]; // RepeatedTiming
(* {0.0000184, Null} *)

But yours is much faster:

SparseArray[{i_, i_} -> 1, {n, n}]; // RepeatedTiming
(* {6.5*10^-6, Null} *)

A slightly different pattern will in fact test all index-pairs, and it will be very slow:

SparseArray[{i_, j_} /; (i == j) -> 1, {n, n}]; // RepeatedTiming
(* {0.0023, Null} *)

Then it occurred to me: even if this were not special cased, we could use Band:

SparseArray[Band[{1, 1}] -> 1, {n, n}]; // RepeatedTiming
(* {0.00051, Null} *)

But very surprisingly, Band seems to perform pretty badly. A bug perhaps, or an oversight?

POSTED BY: Szabolcs Horvát

This seems fastest, for a square matrix, on my machine:

IdentityMatrix[1000, SparseArray]; // RepeatedTiming

And then this:

DiagonalMatrix@ConstantArray[1, 1000, SparseArray]; // RepeatedTiming
POSTED BY: Michael Rogers

Just for the records

In[23]:= Clear[reynaAdd]
reynaAdd[o_Integer?Positive] := 
 Block[{n = 0, p = Join[{1}, ConstantArray[0, o - 1]], x}, 
  Replace[ConstantArray[1, {o, o}], x_ :> x + RotateRight[p, n++], 1]
  ]

In[25]:= reynaAdd[1]
Out[25]= {{2}}

In[27]:= reynaAdd[6]
Out[27]= {{2, 1, 1, 1, 1, 1}, {1, 2, 1, 1, 1, 1}, {1, 1, 2, 1, 1, 
  1}, {1, 1, 1, 2, 1, 1}, {1, 1, 1, 1, 2, 1}, {1, 1, 1, 1, 1, 2}}
POSTED BY: Udo Krause

It sounds like you have a square matrix, and you want to add IdentityMatrix@Length[matrix] to it.

POSTED BY: Szabolcs Horvát
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract