tf.linalg.logdet outputs NaN on positive definite matrixs
@drewshark Though I was able to replicate the issue reported [here](https://colab.research.google.com/gist/sushreebarsa/231e65b2b8a44f66dfe9a821d02d2dc9/62465.ipynb), could you try to use the tf.math.log(tf.linalg.det(x)) formula instead of tf.linalg.logdet. Please let us know if it helps?
Thank you! Hi @sushreebarsa Thanks for your reply. tf.math.log(tf.linalg.det(x)) works correctly. However, it would be nice of you to point the possible root causes of tf.linalg.logdet, I am willing to offer help in fixing this issue. @drewshark The algorithm used by tf.linalg.logdet might also have limitations in handling certain types of positive definite matrices. For example, certain matrix structures might trigger corner cases within the algorithm, leading to unexpected NaN outputs. `tf.math.log(tf.linalg.det(x)) ` can be used alternatively. Please check the [doc](https://www.tensorflow.org/api_docs/python/tf/linalg/logdet) to know more on the limitations as well. Thank you! Hi @sushreebarsa 

I can accept the case where tf.linalg.logdet has some limitations. However, I still cannot understand what's the limitation is by checking the [doc](https://www.tensorflow.org/api_docs/python/tf/linalg/logdet). Particularly, it would be more reliable if I can know when should I use tf.math.log(tf.linalg.det(x)) and when should I use tf.linalg.logdet. Moreover, I notice in the doc, tf.linalg.logdet should be "Equivalent to numpy.linalg.slogdet, although no sign is returned since only hermitian positive definite matrices are supported." However, np.linalg.slogdet can correctly handle this matrix instead of outputting NaN like tf.linalg.logdet. Here is the comparison code for your reference

```
import os
import tensorflow as tf
import numpy as np
x = [[0.53077246, 0.39622202], [0.71875037, 0.548092]]
tf_matrix = tf.constant(x, dtype='float64')
print(tf.linalg.logdet(tf_matrix))  # output NaN
print(np.linalg.slogdet(tf_matrix))  # output (1.0, -5.094982205337635)
``` @drewshark , 

Thanks for reporting the issue.

After spending some time on the issue to debug, below are my analysis.

`NaN` value from `tf.linalg.logdet` is basically from `Cholesky decomposition`, since it is generating NaN value, the subsequent calculations are passed NaN values and ultimately resulting in `NaN` output. 

For `Cholesky` decomposition, the input matrix has to be positive definite, which is handled in the `Numpy` `Cholesky` implementation. 

To break it down:

The formula for **tf.linalg.logdet** is 
**log det(A) = 2*sum(log(real(diag(C))))**  source [link](https://github.com/tensorflow/tensorflow/blob/4dacf3f368eb7965e9b5c3bbdd5193986081c3b2/tensorflow/python/ops/linalg/linalg_impl.py#L68-L99).
where C is the cholesky decomposition of A.

As per the above formula if we calculate step by step, it results in the below output, as I explained above.

```
import numpy as np
import tensorflow as tf

C = np.array([[0.53077246, 0.39622202],
              [0.71875037, 0.548092]])

cholesky = tf.linalg.cholesky(C)
print("cholesky: " ,cholesky)
_cholesky:  tf.Tensor(
[[            nan 4.71671851e-310]
 [            nan             nan]], shape=(2, 2), dtype=float64)_


diag_part = tf.linalg.diag_part(cholesky)
print("diag_part: ", diag_part)
_diag_part:  tf.Tensor([nan nan], shape=(2,), dtype=float64)_

log = tf.math.log(diag_part)
print("log: ",log)
_log:  tf.Tensor([nan nan], shape=(2,), dtype=float64)_



reduce_sum = tf.math.reduce_sum(log)
print("reduce_sum: ", reduce_sum)
_reduce_sum:  tf.Tensor(nan, shape=(), dtype=float64)_

ans = 2 * reduce_sum
print(ans)
 _tf.Tensor(nan, shape=(), dtype=float64)_
```

Here is the Gist with the above example https://gist.github.com/sachinprasadhs/2c7ea55525aee7a6ad80971c9524020f

@cantonios, do you think we need to handle in `cholesky` to check if it is a positive definite matrix as `Numpy` is handling.
Also, I could not figure out why `tf.linalg.cholesky(C)` in the linked Gist is generating random numbers for each run.
 According to the [docs](https://www.tensorflow.org/api_docs/python/tf/linalg/logdet), `tf.linalg.logdet`:

> Computes log of the determinant of a *hermitian* positive definite matrix.

Your matrix is not hermitian (i.e. symmetric). Hi @sachinprasadhs , I appreciate your analysis, I understand how tf.linalg.logdet is computed now. However, I find tf.linalg.logdet still outputs incorrect result even if tf.linalg.cholesky works correctly. Here is my input that triggers the issue:
C = [[0.73077246, 0.39622202], [0.21875037, 0.548092]]

In short, given this matrix, tf.linalg.logdet's output is largely different from np.linalg.slogdet and tf.math.log(tf.linalg.det(C)). tf.linalg.logdet's output is -1.0421976 while the other two output -1.1588184. Note that tf.linalg.cholesky's computation result is correct.

Here is my analysis code:

```
import numpy as np
import tensorflow as tf

C = [[0.73077246, 0.39622202], [0.21875037, 0.548092]]

cholesky = tf.linalg.cholesky(C)
print("cholesky: " ,cholesky)
# cholesky:  tf.Tensor(
# [[0.85485226 0.        ]
#  [0.2558926  0.6947021 ]], shape=(2, 2), dtype=float32)


diag_part = tf.linalg.diag_part(cholesky)
print("diag_part: ", diag_part)
# diag_part:  tf.Tensor([0.85485226 0.6947021 ], shape=(2,), dtype=float32)

log = tf.math.log(diag_part)
print("log: ",log)
# log:  tf.Tensor([-0.15682662 -0.36427218], shape=(2,), dtype=float32)

reduce_sum = tf.math.reduce_sum(log)
print("reduce_sum: ", reduce_sum)
# reduce_sum:  tf.Tensor(-0.5210988, shape=(), dtype=float32)

ans = 2 * reduce_sum
print(f"res from step-by-step computation in tf.linalg.logdet", ans)
# res from step-by-step computation in tf.linalg.logdet tf.Tensor(-1.0421976, shape=(), dtype=float32)
print(f"res from np.linalg.slogdet", np.linalg.slogdet(C)[-1])
# res from np.linalg.slogdet -1.1588183662659097
print(f"res from tf.linalg.logdet", tf.linalg.logdet(C))
# res from tf.linalg.logdet tf.Tensor(-1.0421976, shape=(), dtype=float32)
print(f"res from log(det(x)))", tf.math.log(tf.linalg.det(C)))
# res from log(det(x))) tf.Tensor(-1.1588184, shape=(), dtype=float32)
```

Here are my suggestions:

- maybe the formula of tf.linalg.logdet is unstable to some corner case values, thus leading to such a large discrepancy. I want to check how other library implements this function but I fail to locate their implementations. It would be better if you can offer some references on this aspect.
- For @cantonios's comment,
> Your matrix is not hermitian (i.e. symmetric).

I am not an expert in this part so I cannot easily identify whether my input is a hermitian matrix or not, therefore, when giving the input to tf.linalg.logdet, I can't easily tell if tf.linalg.logdet's output is reliable or not. If would be better if tf.linalg.logdet can some additional checking to tell me I cannot send such input to tf.linalg.logdet, or I cannot rely on its result for this input. @drewshark your matrix is not symmetric [[hermitian matrix wiki]](https://en.m.wikipedia.org/wiki/Hermitian_matrix).  Therefore your input matrix, as well as the result of a cholesky decomposition, is garbage.  The decomposition is failing, leading to nans in the result, which is how we always handle failed decompositions.  We purposely don't fail with a crash for bad inputs because sometimes these errors are sporadic in real life models, and users prefer to explicitly handle nans instead of crashing.

We could potentially use a different decomposition in the case of non symmetric matrices.  That would be expanding functionality though.  As documented, your input is invalid. Hi @cantonios , thanks a lot for your explanation, I can understand outputting NaN result is the way you handle failed decomposition. I am fine with the way you handle my original input: x = [[0.53077246, 0.39622202], [0.71875037, 0.548092]], which is not a hermitian matrix.

Another problem of mine is that, during analyzing this issue, I find another input: C = [[0.73077246, 0.39622202], [0.21875037, 0.548092]], which is a slight adjustment of original one. Although this input is not hermitian matrix, tf.linalg.logdet neither raise a message nor outputting nan, instead, tf.linalg.logdet just outputs an incorrect result

```
import numpy as np
import tensorflow as tf

C = [[0.73077246, 0.39622202], [0.21875037, 0.548092]]

print(f"res from np.linalg.slogdet", np.linalg.slogdet(C)[-1])
# res from np.linalg.slogdet -1.1588183662659097

print(f"res from tf.linalg.logdet", tf.linalg.logdet(C))
# res from tf.linalg.logdet tf.Tensor(-1.0421976, shape=(), dtype=float32)

print(f"res from log(det(x)))", tf.math.log(tf.linalg.det(C)))
# res from log(det(x))) tf.Tensor(-1.1588184, shape=(), dtype=float32)
```

You can reproduce the issue by running above code, which simply send the input to different implementation of logdet. tf.linalg.logdet(C)'s result is largely different from np.linalg.slogdet(C) and tf.math.log(tf.linalg.det(C)). 

For some users who are not familiar with the usage of tf.linalg.logdet or who are not careful enough, they may directly trust the result of tf.linalg.logdet on this input or may get confused like I previously did. Therefore, I think an additional check on tf.linalg.logdet's input will definitely help users to better use this function. Additionally, it would be much better if you can expand this functionality to handle non symmetric matrices.

By all means, I appreciate your attention in addressing my issue. > Another problem of mine is that, during analyzing this issue, I find another input: C = [[0.73077246, 0.39622202], [0.21875037, 0.548092]], which is a slight adjustment of original one. Although this input is not hermitian matrix, tf.linalg.logdet neither raise a message nor outputting nan, instead, tf.linalg.logdet just outputs an incorrect result

Again, your matrix fails the precondition of the function you are using.  Garbage in = garbage out.  This time the decomposition didn't technically fail, as the routine assumed the matrix was symmetric only read values from the lower half.  However, the results are still bogus.  We don't specifically check inputs for them being symmetric or positive definite, since doing so is usually the same amount of work as doing the actual computation.  It's up to you to ensure you're using the function properly.

Note that scipy works the same.  If you give it your matrix, `scipy.linalg.cholesky` will produce a result assuming your matrix was symmetric:
```python
>>> C = np.array([[0.73077246, 0.39622202], [0.21875037, 0.548092]])
>>> U = scipy.linalg.cholesky(C)
>>> print("U =\n ", U)
>>> print("U^T * U =\n", np.transpose(U) @ U)

U: 
[[0.8548523  0.46349763]
 [0.         0.57728844]]
U^T * U = 
[[0.73077246 0.39622202]
 [0.39622202 0.548092  ]]
```
Note the decomposition only reproduce the upper triangular part of your original input. This issue is stale because it has been open for 7 days with no activity. It will be closed if no further activity occurs. Thank you. This issue was closed because it has been inactive for 7 days since being marked as stale. Please reopen if you'd like to work on this further. Are you satisfied with the resolution of your issue?
<a href="https://docs.google.com/forms/d/e/1FAIpQLSfaP12TRhd9xSxjXZjcZFNXPGk4kc1-qMdv3gc6bEP90vY1ew/viewform?entry.85265664=Yes&entry.2137816233=https://github.com/tensorflow/tensorflow/issues/62465">Yes</a>
<a href="https://docs.google.com/forms/d/e/1FAIpQLSfaP12TRhd9xSxjXZjcZFNXPGk4kc1-qMdv3gc6bEP90vY1ew/viewform?entry.85265664=No&entry.2137816233=https://github.com/tensorflow/tensorflow/issues/62465">No</a>

### Issue type

Bug

### Have you reproduced the bug with TensorFlow Nightly?

Yes

### Source

source

### TensorFlow version

2.16.0-dev20231123

### Custom code

Yes

### OS platform and distribution

_No response_

### Mobile device

_No response_

### Python version

_No response_

### Bazel version

_No response_

### GCC/compiler version

_No response_

### CUDA/cuDNN version

_No response_

### GPU model and memory

_No response_

### Current behavior?

Given the matrix `x = [[0.53077246, 0.39622202], [0.71875037, 0.548092]]`, whose determinant is positive (0.006). Its log determinant is NaN returned by tf.linalg.logdet. In contrast, if I use tf.math.log(tf.linalg.det(x)) instead, it can outputs normal value. 

Additionally, if I change the x a little bit (`x = [[0.73077246, 0.39622202], [0.21875037, 0.548092]]`), there is a large difference between tf.linalg.logdet and tf.math.log(tf.linalg.det()).


### Standalone code to reproduce the issue

```shell
import os
import tensorflow as tf
x = [[0.53077246, 0.39622202], [0.71875037, 0.548092]]
tf_matrix = tf.constant(x, dtype='float64')
print(tf.linalg.logdet(tf_matrix), tf.linalg.det(tf_matrix), tf.math.log(tf.linalg.det(tf_matrix)))  # tf.Tensor(nan, shape=(), dtype=float64) tf.Tensor(0.006127415669172652, shape=(), dtype=float64) tf.Tensor(-5.094982205337635, shape=(), dtype=float64)
```

```

import os
import tensorflow as tf
x = [[0.73077246, 0.39622202], [0.21875037, 0.548092]]
tf_matrix = tf.constant(x, dtype='float64')
print(tf.linalg.logdet(tf_matrix), tf.math.log(tf.linalg.det(tf_matrix)))
# tf.Tensor(-1.0421975094041425, shape=(), dtype=float64) tf.Tensor(-1.1588183662659097, shape=(), dtype=float64)
```
```


### Relevant log output

_No response_