basnijholt / pfapack

Efficient numerical computation of the Pfaffian for dense and banded skew-symmetric matrices
https://arxiv.org/abs/1102.3440
Other
15 stars 6 forks source link

RuntimeWarning: overflow encountered in cdouble_scalars #3

Open quaeritis opened 3 years ago

quaeritis commented 3 years ago

Hello,

I have the problem that an overflow occurs in pfapack when the matrix exceeds a certain size.

Code and file to reproduce the error: skew_h_pi.npy.gz

import gzip
import numpy as np
from pfapack.ctypes import pfaffian as cpf
from pfapack.pfaffian import pfaffian as pf

with gzip.open('skew_h_pi.npy.gz', 'rb') as f:
    skew_h_pi = np.load(f)

print(pf(1j * skew_h_pi))
print(cpf(1j * skew_h_pi, avoid_overflow=True))

Error message:

.conda/envs/latest/lib/python3.9/site-packages/pfapack/pfaffian.py:299: RuntimeWarning: overflow encountered in cdouble_scalars
  pfaffian_val *= A[k, k + 1]
.conda/envs/latest/lib/python3.9/site-packages/pfapack/pfaffian.py:292: RuntimeWarning: invalid value encountered in cdouble_scalars
  pfaffian_val *= -1

Output:

(nan+nanj)
(inf-infj)

Some questions:

Best regards quaeritis

basnijholt commented 3 years ago

Hi @quaeritis,

Thanks for reporting!

The C-code is generated via https://github.com/basnijholt/pfapack/blob/master/pfapack/ctypes.py and downloaded from @michaelwimmer's website https://michaelwimmer.org/pfapack.tgz (see conda-forge recipe).

I am no C expert, perhaps @michaelwimmer knows what is going on?

akhmerov commented 3 years ago

This isn't a bug: a 110MB matrix is very unlikely to get a Pfaffian which fits into a float. By comparison, determinant also fails.

image

@quaeritis if you want to compute something like a topological invariant, you're better off using alternative approaches that work with sparse matrices.

michaelwimmer commented 3 years ago

The error happens in pfapack.py, so in the python part. The problem is that for a large matrix the pfaffian becomes an exponentially large number: you are multiplying many doubles together, and eventually you get an overflow, that's normal (same happens for determinants).

For a very large matrix it is better to compute the sign and logarithm of the pfaffian. In the Fortran code of ZSKPF10 this is done fore example, the output is

PFAFF   (output) DOUBLE COMPLEX array, dimension 2
*          The value of the Pfaffian in the form
*          PFAFF(1)*10**PFAFF(2) with PFAFF(2) purely real.
*
michaelwimmer commented 3 years ago

Just looked into ctypes.py: if avoid_overflow=True, indeed the ZSKPF10 code is called, but the number is converted back to a normal scalar, or in case of overflow becomes np.inf (times the number in front of 10^...). Maybe it would be better to return for avoid_overflow=True the prefactor a and the exponent b of the number a*10^b directly?