Repository: scipy/scipy

Issue:
scipy.linalg.decomp.schur error triggered by unrelated scipy.linalg.inv (Trac #1138)
_Original ticket http://projects.scipy.org/scipy/ticket/1138 on 2010-03-26 by trac user cstein06, assigned to unknown._

Hi,

I had the weirdest bug in my code yesterday and have been for a long time trying to fix it.

I minimized what happens to the following code, where:
1)call schur function to a matrix A and it goes well
2)invert some random unrelated matrix
3)call schur on the same matrix A, but now with error

It happens with other matrices too. I'm using numpy 1.3.0, scipy 0.7.1.

Thank you, I still have no idea how to deal with it.

Carlos
```
### code begins

from scipy.linalg.decomp import schur
# the matrix 'testshura' is described below.

A = loadtxt('testshura')
eps = finfo(float).eps.item()
i = 0+1j
A = A+eps_eps_i*A
schur(A)

pf = randn(6,6)
inv(pf)
schur(A)
### code ends
### matrix used as 'A':

1.000205026940321800e+00 -7.598985000864847600e-04 1.354417450803546800e-04 -2.834813945974936000e-04 1.027364241886627300e-03 -1.751132785374812400e-04
3.130666686080171800e-04 9.988396700866274400e-01 2.068132892990439500e-04 -4.328629968315468400e-04 1.568737748072513400e-03 -2.673898886398420300e-04
-3.465554450703910700e-05 1.284450533630210700e-04 9.999771063870075400e-01 4.791663998840244900e-05 -1.736545799960012900e-04 2.959926148517411600e-05
9.121991180573567400e-05 -3.380915408046700300e-04 6.026029565582238400e-05 9.998738743904914700e-01 4.570915187578423100e-04 -7.791082381298751800e-05
-3.176758536835378800e-05 1.177413096810050200e-04 -2.098581382829571800e-05 4.392359067179063300e-05 9.998408166204494400e-01 2.713265884217382100e-05
1.907558426423412900e-04 -7.070050329939212100e-04 1.260141919459730400e-04 -2.637493990536297400e-04 9.558535641900891800e-04 9.998370756498984300e-01
```


Discussion:
_@WarrenWeckesser wrote on 2010-03-28_

What is the error that you get?  Copy and paste the actual output, if you can.

What operating system you are using, and how did you install numpy and scipy?

Attachment added by @stefanv on 2010-03-29: [testshura](http://projects.scipy.org/scipy/attachment/ticket/1138/testshura)

Attachment added by @stefanv on 2010-03-29: [schur.py](http://projects.scipy.org/scipy/attachment/ticket/1138/schur.py)

_@stefanv wrote on 2010-03-29_

I cannot reproduce this bug on the latest versions of numpy and scipy.

Attachment added by trac user cstein06 on 2010-03-29: [bug_schur.py](http://projects.scipy.org/scipy/attachment/ticket/1138/bug_schur.py)

_trac user cstein06 wrote on 2010-03-29_

I attached the file I ran and here is the output:

C:\Python26>python.exe "D:/work/producao/pdc congresso baccala/bug_schur.py"
First schur ok.
Traceback (most recent call last):
  File "D:/work/producao/pdc congresso baccala/bug_schur.py", line 33, in <module>
    schur(A)
  File "C:\Python26\lib\site-packages\scipy\linalg\decomp.py", line 1412, in schur
    elif info>0: raise LinAlgError, "Schur form not found.  Possibly ill-conditioned."
numpy.linalg.linalg.LinAlgError: Schur form not found.  Possibly ill-conditioned.

The versions are python 2.6.3, numpy 1.3.0, scipy 0.7.1.

I figured that I can do it with schur(A,'complex'), instead of schur(A+eps_eps_i*A), to get the complex decomposition I wanted, so for me it is fine now. But the bug is still there...

_trac user cstein06 wrote on 2010-03-29_

I'm runing windows Vista, installed numpy and scipy with python(x,y) 2.6.3.0 package.

_@pv wrote on 2010-09-05_

This is likely a bug in LAPACK, and likely compiler etc. dependent.

No repro on newer versions, python 2.6 is not supported.

Resolving patch:
diff --git a/scipy/stats/_continuous_distns.py b/scipy/stats/_continuous_distns.py
--- a/scipy/stats/_continuous_distns.py
+++ b/scipy/stats/_continuous_distns.py
@@ -9244,6 +9244,22 @@ def _entropy(self, kappa):
         return (-kappa * sc.i1e(kappa) / sc.i0e(kappa) +
                 np.log(2 * np.pi * sc.i0e(kappa)) + kappa)
 
+    @extend_notes_in_docstring(rv_continuous, notes="""\
+        The default limits of integration are endpoints of the interval
+        of width ``2*pi`` centered at `loc` (e.g. ``[-pi, pi]`` when
+        ``loc=0``).\n\n""")
+    def expect(self, func=None, args=(), loc=0, scale=1, lb=None, ub=None,
+               conditional=False, **kwds):
+        _a, _b = -np.pi, np.pi
+
+        if lb is None:
+            lb = loc + _a
+        if ub is None:
+            ub = loc + _b
+
+        return super().expect(func, args, loc,
+                              scale, lb, ub, conditional, **kwds)
+
 
 vonmises = vonmises_gen(name='vonmises')
 vonmises_line = vonmises_gen(a=-np.pi, b=np.pi, name='vonmises_line')
diff --git a/scipy/stats/_distn_infrastructure.py b/scipy/stats/_distn_infrastructure.py
--- a/scipy/stats/_distn_infrastructure.py
+++ b/scipy/stats/_distn_infrastructure.py
@@ -2902,6 +2902,20 @@ def expect(self, func=None, args=(), loc=0, scale=1, lb=None, ub=None,
         1.0000000000000002
 
         The slight deviation from 1 is due to numerical integration.
+
+        The integrand can be treated as a complex-valued function
+        by passing ``complex_func=True`` to `scipy.integrate.quad` .
+
+        >>> import numpy as np
+        >>> from scipy.stats import vonmises
+        >>> res = vonmises(loc=2, kappa=1).expect(lambda x: np.exp(1j*x),
+        ...                                       complex_func=True)
+        >>> res
+        (-0.18576377217422957+0.40590124735052263j)
+
+        >>> np.angle(res)  # location of the (circular) distribution
+        2.0
+
         """
         lockwds = {'loc': loc,
                    'scale': scale}


Test patch:
diff --git a/scipy/stats/tests/test_distributions.py b/scipy/stats/tests/test_distributions.py
--- a/scipy/stats/tests/test_distributions.py
+++ b/scipy/stats/tests/test_distributions.py
@@ -181,6 +181,33 @@ def test_vonmises_logpdf(x, kappa, expected_logpdf):
     assert_allclose(logpdf, expected_logpdf, rtol=1e-15)
 
 
+def test_vonmises_expect():
+    """
+    Test that the vonmises expectation values are
+    computed correctly.  This test checks that the
+    numeric integration estimates the correct normalization
+    (1) and mean angle (loc).  These expectations are
+    independent of the chosen 2pi interval.
+    """
+    rng = np.random.default_rng(6762668991392531563)
+
+    loc, kappa, lb = rng.random(3) * 10
+    res = stats.vonmises(loc=loc, kappa=kappa).expect(lambda x: 1)
+    assert_allclose(res, 1)
+    assert np.issubdtype(res.dtype, np.floating)
+
+    bounds = lb, lb + 2 * np.pi
+    res = stats.vonmises(loc=loc, kappa=kappa).expect(lambda x: 1, *bounds)
+    assert_allclose(res, 1)
+    assert np.issubdtype(res.dtype, np.floating)
+
+    bounds = lb, lb + 2 * np.pi
+    res = stats.vonmises(loc=loc, kappa=kappa).expect(lambda x: np.exp(1j*x),
+                                                      *bounds, complex_func=1)
+    assert_allclose(np.angle(res), loc % (2*np.pi))
+    assert np.issubdtype(res.dtype, np.complexfloating)
+
+
 def _assert_less_or_close_loglike(dist, data, func, **kwds):
     """
     This utility function checks that the log-likelihood (computed by