5

I have a 12k X 12k sparse array (~1% density) and I need to:

  • take the square root of all the elements

  • flip the sign of all the elements in the top-left half of the matrix

For example, say that the matrix looks like:

$\begin{bmatrix}a&b&c\\d&e&f\\g&h&i \end{bmatrix}$

the output should read:

$\begin{bmatrix}-\sqrt{a}&-\sqrt{b}&\sqrt{c}\\-\sqrt{d}&\sqrt{e}&\sqrt{f}\\\sqrt{g}&\sqrt{h}&\sqrt{i} \end{bmatrix}$

For a small matrix, I would create a "mask" and multiply it to the sqare root of the matrix, as in the example below for a 10x10 random matrix:

negMask = 
  Join[ConstantArray[-1, 10 - #], ConstantArray[1, #]] & /@ Range[10];
negMask*Sqrt[RandomInteger[2, {10, 10}]]

However, this is too slow for a 12k X 12k matrix, and doesn't exploit the sparsity of the matrix I need to process (and intuitively I'd say that it should be possible to use the sparsity to speed up the computation).

Any suggestion on how to process the matrix quickly?

Fraccalo
  • 6,057
  • 13
  • 28

3 Answers3

7
f[A_?MatrixQ] := 
 With[{B = Reverse[Sqrt[A]]}, 
  Reverse[UpperTriangularize[B] - LowerTriangularize[B, -1]]
  ]

Usage example:

m = 12000;
n = 120000;
A = SparseArray[RandomInteger[{1, m}, {n, 2}] -> RandomReal[{0, 1}, n], {m, m}];

Anew =f[A]; // AbsoluteTiming // First

0.005143

Test:

(A = Partition[Alphabet[][[1 ;; 9]], 3])// MatrixForm
f[A] // MatrixForm

$$\left( \begin{array}{ccc} \text{a} & \text{b} & \text{c} \\ \text{d} & \text{e} & \text{f} \\ \text{g} & \text{h} & \text{i} \\ \end{array} \right)$$

$$\left( \begin{array}{ccc} -\sqrt{\text{a}} & -\sqrt{\text{b}} & \sqrt{\text{c}} \\ -\sqrt{\text{d}} & \sqrt{\text{e}} & \sqrt{\text{f}} \\ \sqrt{\text{g}} & \sqrt{\text{h}} & \sqrt{\text{i}} \\ \end{array} \right)$$

Btw.:

enter image description here

Henrik Schumacher
  • 106,770
  • 7
  • 179
  • 309
3

While trying to solve the problem, I found the following solution:

SparseArray[
   Replace[ArrayRules[Sqrt[sparseArray]], 
      x_ /; x[[1, 1]] - x[[1, 2]] > 0 :> x[[1]] -> -x[[2]]
   , {1}]
]

Not incredibly fast, but not too slow either.

Fraccalo
  • 6,057
  • 13
  • 28
3
nn = 4;
sa = SparseArray[Partition[Symbol /@ CharacterRange["a", "z"][[;; nn^2]], nn]];

TeXForm @ MatrixForm @ sa

$\left( \begin{array}{cccc} a & b & c & d \\ e & f & g & h \\ i & j & k & l \\ m & n & o & p \\ \end{array} \right)$

mask = HankelMatrix @@ ({MapAt[-# &, -#, {-1}], #} & @ ConstantArray[1, nn])

TeXForm @ MatrixForm @ mask

$\left( \begin{array}{cccc} -1 & -1 & -1 & 1 \\ -1 & -1 & 1 & 1 \\ -1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 \\ \end{array} \right)$

sa2 = mask Sqrt[sa]

SparseArray[<16>,{4,4}]

TeXForm @ MatrixForm @ sa2

$\left( \begin{array}{cccc} -\sqrt{a} & -\sqrt{b} & -\sqrt{c} & \sqrt{d} \\ -\sqrt{e} & -\sqrt{f} & \sqrt{g} & \sqrt{h} \\ -\sqrt{i} & \sqrt{j} & \sqrt{k} & \sqrt{l} \\ \sqrt{m} & \sqrt{n} & \sqrt{o} & \sqrt{p} \\ \end{array} \right)$

Alternatively, you can use a combination of MapIndexed and MapAt:

sa3 = MapIndexed[MapAt[-# &, #, {;; nn - #2[[1]]}] &, Sqrt[sa]];
TeXForm @ MatrixForm @ sa3

$\left( \begin{array}{cccc} -\sqrt{a} & -\sqrt{b} & -\sqrt{c} & \sqrt{d} \\ -\sqrt{e} & -\sqrt{f} & \sqrt{g} & \sqrt{h} \\ -\sqrt{i} & \sqrt{j} & \sqrt{k} & \sqrt{l} \\ \sqrt{m} & \sqrt{n} & \sqrt{o} & \sqrt{p} \\ \end{array} \right)$

kglr
  • 394,356
  • 18
  • 477
  • 896