Repository: scipy/scipy

Issue:
BUG: `eigh_tridiagonal` with `select="i"` fails for 1x1 matrices
### Describe your issue.

`eigh_tridiagonal` fails in the "smallest" case with `select="i"`.

### Reproducing Code Example

```python
import numpy as np
from scipy.linalg import eigh_tridiagonal

a = np.array([1.0])
b = np.array([])

x, V = eigh_tridiagonal(
    a,
    b,
    select="i",
    select_range=(0, 0),
)
```


### Error message

```shell
Traceback (most recent call last):
  File "/tmp/d.py", line 7, in <module>
    x, V = eigh_tridiagonal(
           ^^^^^^^^^^^^^^^^^
  File "/home/nschloe/venv/lib/python3.11/site-packages/scipy/linalg/_decomp.py", line 1337, in eigh_tridiagonal
    m, w, iblock, isplit, info = stebz(d, e, select, vl, vu, il, iu, tol,
                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: failed in converting 2nd argument `e' of _flapack.dstebz to C/Fortran array
❯ black d.py
```


### SciPy/NumPy/Python version and system information

```shell
1.12.0 1.26.4 sys.version_info(major=3, minor=11, micro=7, releaselevel='final', serial=0)
Build Dependencies:
  blas:
    detection method: pkgconfig
    found: true
    include directory: /usr/local/include
    lib directory: /usr/local/lib
    name: openblas
    openblas configuration: USE_64BITINT= DYNAMIC_ARCH=1 DYNAMIC_OLDER= NO_CBLAS=
      NO_LAPACK= NO_LAPACKE= NO_AFFINITY=1 USE_OPENMP= HASWELL MAX_THREADS=2
    pc file directory: /usr/local/lib/pkgconfig
    version: 0.3.21.dev
  lapack:
    detection method: pkgconfig
    found: true
    include directory: /usr/local/include
    lib directory: /usr/local/lib
    name: openblas
    openblas configuration: USE_64BITINT= DYNAMIC_ARCH=1 DYNAMIC_OLDER= NO_CBLAS=
      NO_LAPACK= NO_LAPACKE= NO_AFFINITY=1 USE_OPENMP= HASWELL MAX_THREADS=2
    pc file directory: /usr/local/lib/pkgconfig
    version: 0.3.21.dev
  pybind11:
    detection method: config-tool
    include directory: unknown
    name: pybind11
    version: 2.11.1
Compilers:
  c:
    commands: cc
    linker: ld.bfd
    name: gcc
    version: 10.2.1
  c++:
    commands: c++
    linker: ld.bfd
    name: gcc
    version: 10.2.1
  cython:
    commands: cython
    linker: cython
    name: cython
    version: 3.0.8
  fortran:
    commands: gfortran
    linker: ld.bfd
    name: gcc
    version: 10.2.1
  pythran:
    include directory: ../../tmp/pip-build-env-wkrrblds/overlay/lib/python3.11/site-packages/pythran
    version: 0.15.0
Machine Information:
  build:
    cpu: x86_64
    endian: little
    family: x86_64
    system: linux
  cross-compiled: false
  host:
    cpu: x86_64
    endian: little
    family: x86_64
    system: linux
Python Information:
  path: /opt/python/cp311-cp311/bin/python
  version: '3.11'
```



Discussion:
I get a different error message:

```
File ~/programming/scipy/build-install/lib/python3.10/site-packages/scipy/linalg/_decomp.py:1337, in eigh_tridiagonal(d, e, eigvals_only, select, select_range, check_finite, tol, lapack_driver)
   1334     # If getting eigenvectors, needs to be block-ordered (B) instead of
   1335     # matrix-ordered (E), and we will reorder later
   1336     order = 'E' if eigvals_only else 'B'
-> 1337     m, w, iblock, isplit, info = stebz(d, e, select, vl, vu, il, iu, tol,
   1338                                        order)
   1339 else:   # 'stemr'
   1340     # ?STEMR annoyingly requires size N instead of N-1
   1341     e_ = empty(e.size+1, e.dtype)

ValueError: unexpected array size: new_size=1, got array with arr_size=0
```
~~@lucascolley The alg chooses a different `lapack_driver` on your machine. Yours: `stebz`; mine: `stemr` (complex vs real).~~
are you sure? your error message says `stebz` too, no?
I'd seriously consider handling 1x1 inputs early, without sending them to lapack. 
@lucascolley Right, removed the comment.

Let me fix this right away. 

Resolving patch:
diff --git a/scipy/linalg/_decomp.py b/scipy/linalg/_decomp.py
--- a/scipy/linalg/_decomp.py
+++ b/scipy/linalg/_decomp.py
@@ -1309,9 +1309,25 @@ def eigh_tridiagonal(d, e, eigvals_only=False, select='a', select_range=None,
         raise TypeError('lapack_driver must be str')
     drivers = ('auto', 'stemr', 'sterf', 'stebz', 'stev')
     if lapack_driver not in drivers:
-        raise ValueError(f'lapack_driver must be one of {drivers}, got {lapack_driver}')
+        raise ValueError(f'lapack_driver must be one of {drivers}, '
+                         f'got {lapack_driver}')
     if lapack_driver == 'auto':
         lapack_driver = 'stemr' if select == 0 else 'stebz'
+
+    # Quick exit for 1x1 case
+    if len(d) == 1:
+        if select == 1 and (not (vl < d[0] <= vu)):  # request by value
+            w = array([])
+            v = empty([1, 0], dtype=d.dtype)
+        else:  # all and request by index
+            w = array([d[0]], dtype=d.dtype)
+            v = array([[1.]], dtype=d.dtype)
+
+        if eigvals_only:
+            return w
+        else:
+            return w, v
+
     func, = get_lapack_funcs((lapack_driver,), (d, e))
     compute_v = not eigvals_only
     if lapack_driver == 'sterf':
@@ -1578,7 +1594,7 @@ def cdf2rdf(w, v):
     stack_ind = ()
     for i in idx_stack:
         # should never happen, assuming nonzero orders by the last axis
-        assert (i[0::2] == i[1::2]).all(),\
+        assert (i[0::2] == i[1::2]).all(), \
                 "Conjugate pair spanned different arrays!"
         stack_ind += (i[0::2],)
 


Test patch:
diff --git a/scipy/linalg/tests/test_decomp.py b/scipy/linalg/tests/test_decomp.py
--- a/scipy/linalg/tests/test_decomp.py
+++ b/scipy/linalg/tests/test_decomp.py
@@ -742,6 +742,24 @@ def test_eigh_tridiagonal(self):
             assert_array_almost_equal(abs(evec),
                                       abs(self.evec[:, ind1:ind2+1]))
 
+    def test_eigh_tridiagonal_1x1(self):
+        """See gh-20075"""
+        a = np.array([-2.0])
+        b = np.array([])
+        x = eigh_tridiagonal(a, b, eigvals_only=True)
+        assert x.ndim == 1
+        assert_allclose(x, a)
+        x, V = eigh_tridiagonal(a, b, select="i", select_range=(0, 0))
+        assert x.ndim == 1
+        assert V.ndim == 2
+        assert_allclose(x, a)
+        assert_allclose(V, array([[1.]]))
+
+        x, V = eigh_tridiagonal(a, b, select="v", select_range=(-2, 0))
+        assert x.size == 0
+        assert x.shape == (0,)
+        assert V.shape == (1, 0)
+
 
 class TestEigh:
     def setup_class(self):