8

I want to create a n by n Identity matrix and replace the ones with n π^2. NOS is three here (it is a number). The code I have written for this doesn't work.

Kin = IdentityMatrix[NOS]

n = 1; m = 1; While[n == m && n < NOS &&  m < NOS, 
 Kin[[n, m]] -> n π^2; n++; m++]

I want

Kin[[1, 1]]== π^2
Kin[[2, 2]]==2 π^2

and so on. Could anyone help me with this please?

kglr
  • 394,356
  • 18
  • 477
  • 896

3 Answers3

9

It is far faster to make the multiplication by a vector and then convert to a diagonal matrix, rather than building a full matrix and multiplying after:

DiagonalMatrix[π^2 Range[3]]

$\left( \begin{array}{ccc} \pi ^2 & 0 & 0 \\ 0 & 2 \pi ^2 & 0 \\ 0 & 0 & 3 \pi ^2 \\ \end{array} \right)$

Even faster is to build a sparse array, which is done by applying SparseArray before (inside) DiagonalMatrix. With this formulation multiplicaiton after is fast because only specified elements (the diagonal) are actually multiplied.

π^2 DiagonalMatrix[Range[1000]];                // RepeatedTiming // First
DiagonalMatrix[π^2 Range[1000]];                // RepeatedTiming // First
π^2 DiagonalMatrix[SparseArray @ Range[1000]];  // RepeatedTiming // First
0.434

0.01

0.000647

The examples above preserve the diagonals in Symbolic form. If machine reals(1) are OK:

π^2` DiagonalMatrix[Range[1000]];                // RepeatedTiming // First
DiagonalMatrix[π^2` Range[1000]];                // RepeatedTiming // First
π^2` DiagonalMatrix[SparseArray @ Range[1000]];  // RepeatedTiming // First
0.0040

0.00174

0.0000231

Reference:

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
  • Can you explain why the SparseArray[] solution is faster? – Anjan Kumar Jun 14 '17 at 04:03
  • @AnjanKumar It is a much smaller expression being created, here about 1/144 the size of the dense array. Because of the use of exact π^2 the array cannot be packed (in the plain case), so fast library operations cannot be used. π^2` DiagonalMatrix[Range[1000]]; (note the backtick) takes only 0.00371 on my machine because everything remains packed and fast library functions are used. – Mr.Wizard Jun 14 '17 at 09:58
  • I should add the note that there is an undocumented syntax for directly producing a sparse diagonal matrix: DiagonalMatrix[π^2 Range[3], 0, 3, SparseArray] – J. M.'s missing motivation Mar 29 '19 at 10:33
6
NOS = 3; 

π^2 DiagonalMatrix[Range[NOS]] 
π^2 Range[NOS] IdentityMatrix[NOS]
MapIndexed[π^2 #2[[1]] # &, IdentityMatrix[NOS], {2}]
ReplacePart[IdentityMatrix[NOS], {i_, i_} :> (i π^2)]
Block[{i = 1}, IdentityMatrix[NOS] /. 1 :> (π^2 i++)]

all give

{{π^2, 0, 0}, {0, 2 π^2, 0}, {0, 0, 3 π^2}}

kglr
  • 394,356
  • 18
  • 477
  • 896
4

here is another way using Unitize

π^2 Table[i (1 - Unitize[Range[1000] - i]), {i, 1000}]; // AbsoluteTiming 
  (* {0.552622, Null} *)

and with SparseArray alone:

π^2 SparseArray[{i_, i_} :> i , {1000, 1000}];//AbsoluteTiming
  (* {0.00134081, Null} *)

Borrowing the backtick from @Mr.Wizard significantly improves the answer

π^2` Table[i (1 - Unitize[Range[1000] - i]), {i, 1000}]; // AbsoluteTiming
(* {0.0230811, Null} *)


π^2` SparseArray[{i_, i_} :> i, {1000, 1000}]; // AbsoluteTiming
(* {0.000165618, Null} *)
Ali Hashmi
  • 8,950
  • 4
  • 22
  • 42
  • Which version are you using? For the first line I get 0.43793 and for the second 0.000658. What timings do you get for the six lines in my answer, please? – Mr.Wizard Jun 14 '17 at 10:06
  • @Mr.Wizard thanks for picking it out. I think for the first one i used the timing from Range[100] rather than 1000. I just updated it – Ali Hashmi Jun 14 '17 at 10:18
  • 1
    Table just seems unnecessarily baroque and honestly I'd leave it out if I were you, but +1 for the concise SparseArray form. It's not quite as fast as DiagonalMatrix with a sparse argument but I doubt it matters. FWIW SparseArray[{i_, i_} :> i Pi^2, {1000, 1000}] also works. – Mr.Wizard Jun 14 '17 at 12:04