Repository: qutip/qutip

Issue:
wrong logic detecting BLAS support discrepant from numpy
### Bug Description

qutip has functions to detect the available of BLAS libraries.  For instance on my system (debian unstable), `python3 -c "import qutip; qutip.about()"` reports
```
BLAS Info:          OPENBLAS
```

However, I think the logic behind BLAS Info is not robust.

For context, debian builds packages against generic libblas.so (libblas-dev package). The various optimised BLAS implementations are supposed to be binary compatible, such that the system administrator can install the preferred implementation for use at runtime (the identity of libblas.so is controlled using debian's alternatives mechanism).

On my system, OpenBLAS is indeed installed.  But taking a closer look, I'm not sure it was detected for the right reason.
The blas configuration is identified by the `_blas_info()` function in qutip/utilities.py.  It uses the local numpy configuration (`np.__config`), testing the availability of various attributes in the numpy config,  in the form of 
```
if hasattr(config,'mkl_info') ...
elif hasattr(config,'openblas_info')
```

MKL was not used to build debian's numpy package, and I don't have it installed.  So mkl_info is not detected.  OpenBLAS was not used to to build numpy either, but it is installed, so I want look closer at the logic.

config (i.e. `np.__config__`) does indeed have an openblas_info.  But it is empty (`{}`). Nevertheless `hasattr(config,'openblas_info')`returns True, since the empty dict is there.

As far as MKL goes, mkl_info is indeed not there, so qutip does not detect MKL BLAS. But there is a `blas_mkl_info` attribute, and `hasattr(config,'blas_mkl_info')` returns True, same as with openblas_info

numpy provides a summary of its configuration in `np.show_config()`:
```
numpy.show_config()
blas_armpl_info:
  NOT AVAILABLE
blas_mkl_info:
  NOT AVAILABLE
blis_info:
  NOT AVAILABLE
openblas_info:
  NOT AVAILABLE
accelerate_info:
  NOT AVAILABLE
atlas_3_10_blas_threads_info:
  NOT AVAILABLE
atlas_3_10_blas_info:
  NOT AVAILABLE
atlas_blas_threads_info:
  NOT AVAILABLE
atlas_blas_info:
  NOT AVAILABLE
blas_info:
    libraries = ['blas', 'blas']
    library_dirs = ['/usr/lib/x86_64-linux-gnu']
    include_dirs = ['/usr/local/include', '/usr/include']
    language = c
    define_macros = [('HAVE_CBLAS', None)]
blas_opt_info:
    define_macros = [('NO_ATLAS_INFO', 1), ('HAVE_CBLAS', None)]
    libraries = ['blas', 'blas']
    library_dirs = ['/usr/lib/x86_64-linux-gnu']
    include_dirs = ['/usr/local/include', '/usr/include']
    language = c
lapack_armpl_info:
  NOT AVAILABLE
lapack_mkl_info:
  NOT AVAILABLE
openblas_lapack_info:
  NOT AVAILABLE
openblas_clapack_info:
  NOT AVAILABLE
flame_info:
  NOT AVAILABLE
atlas_3_10_threads_info:
  NOT AVAILABLE
atlas_3_10_info:
  NOT AVAILABLE
atlas_threads_info:
  NOT AVAILABLE
atlas_info:
  NOT AVAILABLE
lapack_info:
    libraries = ['lapack', 'lapack']
    library_dirs = ['/usr/lib/x86_64-linux-gnu']
    language = f77
lapack_opt_info:
    libraries = ['lapack', 'lapack', 'blas', 'blas']
    library_dirs = ['/usr/lib/x86_64-linux-gnu']
    language = c
    define_macros = [('NO_ATLAS_INFO', 1), ('HAVE_CBLAS', None)]
    include_dirs = ['/usr/local/include', '/usr/include']
Supported SIMD extensions in this NumPy install:
    baseline = SSE,SSE2,SSE3
    found = SSSE3,SSE41,POPCNT,SSE42,AVX,F16C,FMA3,AVX2
    not found = AVX512F,AVX512CD,AVX512_SKX,AVX512_CLX,AVX512_CNL,AVX512_ICL
```
So numpy itself marks openblas_info as NOT AVAILABLE  (evidently using a build-time test, not runtime, which arguably is a pity).

It seems to me that `hasattr` in qutip's BLAS support tests is returning false positives and false negatives.  It indicates if the attribute was defined, even though it might be empty.

Would it be better to replace
```
hasattr(config,'openblas_info')
```
in qutip/utilities.py with
```
hasattr(config,'openblas_info') and config.openblas_info
```
likewise for blas_mkl_info (not mkl_info) ?

This would be similar to numpy's own usage in `np.show_config()` (i.e. `np.__config__.py.show()`), which [uses](https://github.com/numpy/numpy/blob/3b7672ebd16982b661b8fbcabac80158662a8784/numpy/__config__.py.in#L116) `if not info_dict` to print "NOT AVAILABLE".

### Code to Reproduce the Bug

```shell
import numpy
numpy.show_config()

import qutip
qutip.about()
```


### Code Output

```shell
$ python3
Python 3.10.9 (main, Dec  7 2022, 13:47:07) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy
>>> numpy.show_config()
...
blas_mkl_info:
  NOT AVAILABLE
...
openblas_info:
  NOT AVAILABLE
accelerate_info:
  NOT AVAILABLE
...
blas_info:
    libraries = ['blas', 'blas']
    library_dirs = ['/usr/lib/x86_64-linux-gnu']
    include_dirs = ['/usr/local/include', '/usr/include']
    language = c
    define_macros = [('HAVE_CBLAS', None)]
blas_opt_info:
    define_macros = [('NO_ATLAS_INFO', 1), ('HAVE_CBLAS', None)]
    libraries = ['blas', 'blas']
    library_dirs = ['/usr/lib/x86_64-linux-gnu']
    include_dirs = ['/usr/local/include', '/usr/include']
    language = c
>>> 
>>> import qutip
>>> qutip.about()
...
BLAS Info:          OPENBLAS
```


### Expected Behaviour

The qutip declaration of BLAS support should match the numpy declaration.

If numpy says OpenBLAS is not available, then qutip should probably not say that it is available (even if it is installed).

### Your Environment

```shell
$ python3 -c "import qutip; qutip.about()"

QuTiP: Quantum Toolbox in Python
================================
Copyright (c) QuTiP team 2011 and later.
Current admin team: Alexander Pitchford, Nathan Shammah, Shahnawaz Ahmed, Neill Lambert, Eric Giguère, Boxi Li, Jake Lishman, Simon Cross and Asier Galicia.
Board members: Daniel Burgarth, Robert Johansson, Anton F. Kockum, Franco Nori and Will Zeng.
Original developers: R. J. Johansson & P. D. Nation.
Previous lead developers: Chris Granade & A. Grimsmo.
Currently developed through wide collaboration. See https://github.com/qutip for details.

QuTiP Version:      4.7.1
Numpy Version:      1.24.1
Scipy Version:      1.8.1
Cython Version:     0.29.32
Matplotlib Version: 3.6.2
Python Version:     3.10.9
Number of CPUs:     8
BLAS Info:          OPENBLAS
OPENMP Installed:   True
INTEL MKL Ext:      False
Platform Info:      Linux (x86_64)
Installation path:  /usr/lib/python3/dist-packages/qutip
================================================================================
Please cite QuTiP in your publication.
================================================================================
For your convenience a bibtex reference can be easily generated using `qutip.cite()`
```


### Additional Context

_No response_


Discussion:

Resolving patch:
diff --git a/qutip/settings.py b/qutip/settings.py
--- a/qutip/settings.py
+++ b/qutip/settings.py
@@ -18,15 +18,15 @@ def _blas_info():
         blas_info = config.blas_opt_info
     else:
         blas_info = {}
-    _has_lib_key = 'libraries' in blas_info.keys()
-    blas = None
-    if hasattr(config,'mkl_info') or \
-            (_has_lib_key and any('mkl' in lib for lib in blas_info['libraries'])):
+
+    def _in_libaries(name):
+        return any(name in lib for lib in blas_info.get('libraries', []))
+
+    if getattr(config, 'mkl_info', False) or _in_libaries("mkl"):
         blas = 'INTEL MKL'
-    elif hasattr(config,'openblas_info') or \
-            (_has_lib_key and any('openblas' in lib for lib in blas_info['libraries'])):
+    elif getattr(config, 'openblas_info', False) or _in_libaries('openblas'):
         blas = 'OPENBLAS'
-    elif 'extra_link_args' in blas_info.keys() and ('-Wl,Accelerate' in blas_info['extra_link_args']):
+    elif '-Wl,Accelerate' in blas_info.get('extra_link_args', []):
         blas = 'Accelerate'
     else:
         blas = 'Generic'


Test patch: