Sparse matrix processing: flip sign of top-left entries of the matrix

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}$$

$$\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];


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?

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.:

• This is great, much faster than my solution when applied to large matrices! – Fraccalo Aug 8 '19 at 14:10
• Thanks Fraccolo! Can you please unaccept the post for a few hours? I missed the 66666 rep just by 5 points. =D – Henrik Schumacher Aug 8 '19 at 14:16
• done :) I hope you can take the screenshot now :D – Fraccalo Aug 8 '19 at 14:44
• Yeah! It worked! Thank you! – Henrik Schumacher Aug 8 '19 at 15:02

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.

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])



$$\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)$$