Repository: numpy/numpy

Issue:
triu generates nan when called on matrices with infinite values
In numpy 1.8.1, I've just found some strange behaviour.

Summary: when calling np.triu on a matrix, inf entries in the discarded region get converted to nan.  This broke my code unexpectedly.

```
import numpy as np
a = np.zeros((4, 4))
a[1:, 2] = np.inf
a
>>>array([[  0.,   0.,   0.,   0.],
          [ inf,   0.,   0.,   0.],
          [ inf,   0.,   0.,   0.],
          [ inf,   0.,   0.,   0.]])

np.triu(a)
>>>array([[  0.,   0.,   0.,   0.],
          [ nan,   0.,   0.,   0.],
          [ nan,   0.,   0.,   0.],
          [ nan,   0.,   0.,   0.]])
```

Also posted on stackexchange: https://stackoverflow.com/questions/24678932/numpy-triu-generates-nan-when-called-on-matrices-with-infinite-values



Discussion:

Resolving patch:
diff --git a/numpy/lib/twodim_base.py b/numpy/lib/twodim_base.py
--- a/numpy/lib/twodim_base.py
+++ b/numpy/lib/twodim_base.py
@@ -387,7 +387,6 @@ def tri(N, M=None, k=0, dtype=float):
     dtype : dtype, optional
         Data type of the returned array.  The default is float.
 
-
     Returns
     -------
     tri : ndarray of shape (N, M)
@@ -452,7 +451,9 @@ def tril(m, k=0):
 
     """
     m = asanyarray(m)
-    return multiply(tri(*m.shape[-2:], k=k, dtype=bool), m, dtype=m.dtype)
+    mask = tri(*m.shape[-2:], k=k, dtype=bool)
+
+    return where(mask, m, 0)
 
 
 def triu(m, k=0):
@@ -478,7 +479,9 @@ def triu(m, k=0):
 
     """
     m = asanyarray(m)
-    return multiply(~tri(*m.shape[-2:], k=k-1, dtype=bool), m, dtype=m.dtype)
+    mask = tri(*m.shape[-2:], k=k-1, dtype=bool)
+
+    return where(mask, 0, m)
 
 
 # Originally borrowed from John Hunter and matplotlib


Test patch:
diff --git a/numpy/core/tests/test_scalarmath.py b/numpy/core/tests/test_scalarmath.py
--- a/numpy/core/tests/test_scalarmath.py
+++ b/numpy/core/tests/test_scalarmath.py
@@ -83,6 +83,18 @@ def test_blocked(self):
                 np.add(1, inp2, out=out)
                 assert_almost_equal(out, exp1, err_msg=msg)
 
+    def test_lower_align(self):
+        # check data that is not aligned to element size
+        # i.e doubles are aligned to 4 bytes on i386
+        d = np.zeros(23 * 8, dtype=np.int8)[4:-4].view(np.float64)
+        o = np.zeros(23 * 8, dtype=np.int8)[4:-4].view(np.float64)
+        assert_almost_equal(d + d, d * 2)
+        np.add(d, d, out=o)
+        np.add(np.ones_like(d), d, out=o)
+        np.add(d, np.ones_like(d), out=o)
+        np.add(np.ones_like(d), d)
+        np.add(d, np.ones_like(d))
+
 
 class TestPower(TestCase):
     def test_small_types(self):
diff --git a/numpy/core/tests/test_umath.py b/numpy/core/tests/test_umath.py
--- a/numpy/core/tests/test_umath.py
+++ b/numpy/core/tests/test_umath.py
@@ -753,6 +753,13 @@ def test_minmax_blocked(self):
                     inp[i] = -1e10
                     assert_equal(inp.min(), -1e10, err_msg=msg)
 
+    def test_lower_align(self):
+        # check data that is not aligned to element size
+        # i.e doubles are aligned to 4 bytes on i386
+        d = np.zeros(23 * 8, dtype=np.int8)[4:-4].view(np.float64)
+        assert_equal(d.max(), d[0])
+        assert_equal(d.min(), d[0])
+
 
 class TestAbsoluteNegative(TestCase):
     def test_abs_neg_blocked(self):
@@ -785,6 +792,17 @@ def test_abs_neg_blocked(self):
                             np.negative(inp, out=out)
                             assert_array_equal(out, -1*inp, err_msg=msg)
 
+    def test_lower_align(self):
+        # check data that is not aligned to element size
+        # i.e doubles are aligned to 4 bytes on i386
+        d = np.zeros(23 * 8, dtype=np.int8)[4:-4].view(np.float64)
+        assert_equal(np.abs(d), d)
+        assert_equal(np.negative(d), -d)
+        np.negative(d, out=d)
+        np.negative(np.ones_like(d), out=d)
+        np.abs(d, out=d)
+        np.abs(np.ones_like(d), out=d)
+
 
 class TestSpecialMethods(TestCase):
     def test_wrap(self):
diff --git a/numpy/lib/tests/test_twodim_base.py b/numpy/lib/tests/test_twodim_base.py
--- a/numpy/lib/tests/test_twodim_base.py
+++ b/numpy/lib/tests/test_twodim_base.py
@@ -311,6 +311,18 @@ def test_tril_triu_ndim3():
         yield assert_equal, a_triu_observed.dtype, a.dtype
         yield assert_equal, a_tril_observed.dtype, a.dtype
 
+def test_tril_triu_with_inf():
+    # Issue 4859
+    arr = np.array([[1, 1, np.inf],
+                    [1, 1, 1],
+                    [np.inf, 1, 1]])
+    out_tril = np.array([[1, 0, 0],
+                         [1, 1, 0],
+                         [np.inf, 1, 1]])
+    out_triu = out_tril.T
+    assert_array_equal(np.triu(arr), out_triu)
+    assert_array_equal(np.tril(arr), out_tril)
+
 
 def test_mask_indices():
     # simple test without offset