Repository: google/jax

Issue:
`slogdet` sign is incorrect
In the following, numpy disagrees with JAX
```python
mat = np.array([[[-0.01]],
             [[-0.01]]])
print(np.linalg.slogdet(mat))
print(jnp.linalg.slogdet(jnp.array(mat)))
```
=>
```
(array([-1., -1.]), array([-4.60517019, -4.60517019]))
(DeviceArray([1., 1.]), DeviceArray([-4.60517019, -4.60517019]))
```


Discussion:
Not sure if relevant, but I was running with `from jax import config; config.update('jax_enable_x64',True)`
Seems to be something to do with the even/odd-ness of the matrix rank:
```python
mat = np.array([np.diag(np.ones([5]))*(-.01)] * 2)
for n in range(1, 6):
  print(n)
  print(onp.linalg.slogdet(mat[...,:n,:n]))
  print(np.linalg.slogdet(np.array(mat[...,:n,:n])))
```
=>
```
1
(array([-1., -1.], dtype=float32), array([-4.6051702, -4.6051702], dtype=float32))
(DeviceArray([1., 1.], dtype=float32), DeviceArray([-4.60517025, -4.60517025], dtype=float32))
2
(array([1., 1.], dtype=float32), array([-9.2103405, -9.2103405], dtype=float32))
(DeviceArray([1., 1.], dtype=float32), DeviceArray([-9.2103405, -9.2103405], dtype=float32))
3
(array([-1., -1.], dtype=float32), array([-13.815511, -13.815511], dtype=float32))
(DeviceArray([1., 1.], dtype=float32), DeviceArray([-13.81551075, -13.81551075], dtype=float32))
4
(array([1., 1.], dtype=float32), array([-18.420681, -18.420681], dtype=float32))
(DeviceArray([1., 1.], dtype=float32), DeviceArray([-18.420681, -18.420681], dtype=float32))
5
(array([-1., -1.], dtype=float32), array([-23.02585, -23.02585], dtype=float32))
(DeviceArray([1., 1.], dtype=float32), DeviceArray([-23.0258522, -23.0258522], dtype=float32))
```

Resolving patch:
diff --git a/jax/numpy/linalg.py b/jax/numpy/linalg.py
--- a/jax/numpy/linalg.py
+++ b/jax/numpy/linalg.py
@@ -60,6 +60,7 @@ def svd(a, full_matrices=True, compute_uv=True):
 
 
 @_wraps(onp.linalg.slogdet)
+@jit
 def slogdet(a):
   a = _promote_arg_dtypes(np.asarray(a))
   dtype = lax.dtype(a)
@@ -72,10 +73,10 @@ def slogdet(a):
   is_zero = np.any(diag == np.array(0, dtype=dtype), axis=-1)
   parity = np.count_nonzero(pivot != np.arange(a_shape[-1]), axis=-1)
   if np.iscomplexobj(a):
-    sign = np.prod(diag / np.abs(diag))
+    sign = np.prod(diag / np.abs(diag), axis=-1)
   else:
     sign = np.array(1, dtype=dtype)
-    parity = parity + np.count_nonzero(diag < 0)
+    parity = parity + np.count_nonzero(diag < 0, axis=-1)
   sign = np.where(is_zero,
                   np.array(0, dtype=dtype),
                   sign * np.array(-2 * (parity % 2) + 1, dtype=dtype))


Test patch:
diff --git a/tests/linalg_test.py b/tests/linalg_test.py
--- a/tests/linalg_test.py
+++ b/tests/linalg_test.py
@@ -99,19 +99,27 @@ def testDet(self, n, dtype, rng):
 
   @parameterized.named_parameters(jtu.cases_from_list(
       {"testcase_name":
-       "_n={}".format(jtu.format_shape_dtype_string((n,n), dtype)),
-       "n": n, "dtype": dtype, "rng": rng}
-      for n in [0, 4, 10, 200]
+       "_shape={}".format(jtu.format_shape_dtype_string(shape, dtype)),
+       "shape": shape, "dtype": dtype, "rng": rng}
+      for shape in [(0, 0), (1, 1), (3, 3), (4, 4), (10, 10), (200, 200),
+                    (2, 2, 2), (2, 3, 3), (3, 2, 2)]
       for dtype in float_types + complex_types
       for rng in [jtu.rand_default()]))
-  def testSlogdet(self, n, dtype, rng):
+  def testSlogdet(self, shape, dtype, rng):
     _skip_if_unsupported_type(dtype)
-    args_maker = lambda: [rng((n, n), dtype)]
+    args_maker = lambda: [rng(shape, dtype)]
 
     self._CheckAgainstNumpy(onp.linalg.slogdet, np.linalg.slogdet, args_maker,
                             check_dtypes=True, tol=1e-3)
     self._CompileAndCheck(np.linalg.slogdet, args_maker, check_dtypes=True)
 
+  def testIssue1213(self):
+    for n in range(5):
+      mat = np.array([onp.diag(onp.ones([5], dtype=onp.float32))*(-.01)] * 2)
+      args_maker = lambda: [mat]
+      self._CheckAgainstNumpy(onp.linalg.slogdet, np.linalg.slogdet, args_maker,
+                              check_dtypes=True, tol=1e-3)
+
   @parameterized.named_parameters(jtu.cases_from_list(
       {"testcase_name": "_shape={}".format(
            jtu.format_shape_dtype_string(shape, dtype)),