9

Problem:

When I multiply together two sparse matrices that should give back the 0 matrix, where at least one element among the two is complex and at least one is not an exact number, the kernel crashes unexpectedly with no messages generated.

4 workarounds are given at the bottom.

Minimal working example:

test1 = SparseArray[DiagonalMatrix[{1., 0}]]
test2 = SparseArray[DiagonalMatrix[{0, I}]]
test1.test2 (* Crashes kernel with no messages generated *)

Note that at least one element must be complex, at least one must not be an exact number and the final result must have no non-zero elements.

Can anyone reproduce this behavior? Even better, anyone have a workaround? This problem shows up for me deep inside a complex differential equation of $64\times64$ very sparse matrices. Using non-sparse operations gives a $\sim 20$x slowdown.

I'll report to Wolfram as well, thanks!

System:

Version: 12.0.0 for Linux x86 (64-bit) (April 7, 2019). See comments for some other systems affected by this.

Workarounds:

For those who stumble upon this in the future:

test1 = SparseArray[DiagonalMatrix[SetPrecision[{1., 0}, $MachinePrecision]]]
test2 = SparseArray[DiagonalMatrix[{0, I}]]
test1.test2

Gives the desired result of an empty SparseArray. Other workarounds include:

test1 = SparseArray[DiagonalMatrix[{1., 0}]]
test2 = SparseArray[DiagonalMatrix[{0, I}]]
test1.test2

Avoids the crash but gives 2 "specified elements" in the result so it's less sparse than desired.

test1 = SparseArray[DiagonalMatrix[{1., 0} + $MinMachineNumber]]
test2 = SparseArray[DiagonalMatrix[{0, I}]]
test1.test2

Also avoids the crash but does give 1 non-zero element in the result so is technically wrong, albeit by the tiniest possible amount.

test1 = DiagonalMatrix[{1., 0}, 0, 2, SparseArray]; 
test2 = DiagonalMatrix[{0, I}, 0, 2, SparseArray];
test1.test2

Also avoids the crash and also gives 2 "specified elements" in the result.

bRost03
  • 2,072
  • 8
  • 14
  • 1
    It also crashes for me on Windows 10 v12.1. – flinty May 27 '20 at 22:07
  • 1
    macos version 12.0 crashes, too. Weird. – Henrik Schumacher May 27 '20 at 22:39
  • 1
    Please report this to support. – Henrik Schumacher May 27 '20 at 23:04
  • 1
    @HenrikSchumacher reported! – bRost03 May 27 '20 at 23:18
  • 2
    If you're using DiagonalMatrix[], perhaps just have it generate a SparseArray[] directly: test1 = DiagonalMatrix[{1., 0}, 0, 2, SparseArray]; test2 = DiagonalMatrix[{0, I}, 0, 2, SparseArray];. – J. M.'s missing motivation May 28 '20 at 01:14
  • @J.M.'stechnicaldifficulties this is very interesting. Mathematica highlights SparseArray in red and warns "Too many arguments given for DiagonalMatrix". And yet it still runs fine. However the result is a sparse matrix with 2 elements specified when it really should be 0. But then again so does the accepted answer. Thanks for responding! – bRost03 May 28 '20 at 15:00
  • 1
    "the result is a sparse matrix with 2 elements specified when it really should be 0." - yes, that's known behavior. – J. M.'s missing motivation May 28 '20 at 15:04
  • 2
    I'll ensure this is reported internally. – ktm May 28 '20 at 15:09
  • @J.M. thanks for sharing! Somehow this solution gives back a truly empty SpareArray. test1 = SparseArray[DiagonalMatrix[SetPrecision[{1., 0},$MachinePrecision]]];test2 = SparseArray[DiagonalMatrix[{0, I}]];test1.test2. Makes sense adding or subtracting would produce those results since adding or subtracting doesn't mix indices but matrix multiplication does. Either way thanks for the comments! – bRost03 May 28 '20 at 15:09

3 Answers3

5

This seemed to work for me...

test1 = DiagonalMatrix[SparseArray[{1. + 0. I, 0. I}]];
test2 = DiagonalMatrix[SparseArray[{0. I, 1. I}]];
test1.test2
Henrik Schumacher
  • 106,770
  • 7
  • 179
  • 309
  • 1
    This is better. It still works for me even if I leave the exact {1., 0} and {0, I} in place. – flinty May 27 '20 at 22:45
4

Using N[...] didn't work for me either. If you can tolerate the really tiny error on the order of $10^{-308}$ then here's a workaround which adds the $MinMachineNumber to the first matrix elements:

test1 = SparseArray[DiagonalMatrix[{1., 0} + $MinMachineNumber]]
test2 = SparseArray[DiagonalMatrix[{0, I}]]
test1.test2
flinty
  • 25,147
  • 2
  • 20
  • 86
3

This seems to work, and returns an empty SparseArray as desired

test1 = SparseArray[DiagonalMatrix[SetPrecision[{1., 0}, $MachinePrecision]]]
test2 = SparseArray[DiagonalMatrix[{0, I}]]
test1.test2
bRost03
  • 2,072
  • 8
  • 14