Function Repository Resource:

NumPySignLogDet

Source Notebook

Compute the sign and natural logarithm of the determinant of an array in Python using the NumPy linear algebra package

Contributed by: Wolfram Staff

ResourceFunction["NumPySignLogDet"][array]

computes the sign and natural logarithm of the determinant of array in Python using the package NumPy.

ResourceFunction["NumPySignLogDet"][array,session]

uses the specified running ExternalSessionObject session.

Details and Options

ResourceFunction["NumPySignLogDet"] is a wrapper function that calls the Python function numpy.linalg.slogdet().
array must be a numeric square matrix or a tensor object representing a list of numeric square matrices.
If array is a square matrix, ResourceFunction["NumPySignLogDet"] returns the result in the form of {sign,ldet}; for tensors, the result is in the form of {{sign1,},{ldet1,}}.
For a real matrix, the returned value signi is -1, 0 or 1 depending on whether the determinant is negative, zero or positive; for a complex matrix, signi is a complex number with an absolute value of 1 (i.e., it is on the unit circle) or else 0.
The returned value ldeti is the natural logarithm of the absolute value of the determinant.
If the determinant is zero, then signi will be 0 and ldeti will be -Inf, the IEEE underflow.
In all cases, the determinant is supposed to be computed as signi*Exp[ldeti].
Since ResourceFunction["NumPySignLogDet"] computes ithe logarithm of the determinant rather than the determinant itself, it is more robust than the resource function NumPyDet when array has a very small or very large determinant, that is, when NumPyDet may return a result of overflow or underflow.
ResourceFunction["NumPySignLogDet"] accepts array in the form of a NumericArray object or an expression that can be converted to NumericArray.
ResourceFunction["NumPySignLogDet"][array,session] avoids the overhead of opening a new Python session for every successive call.

Examples

Basic Examples (3) 

Compute the sign and natural logarithm of the determinant of a matrix in NumPy:

In[1]:=
m = {{1, 2}, {3, 4}};
In[2]:=
{sign, logdet} = ResourceFunction["NumPySignLogDet"][m]
Out[2]=

The determinant:

In[3]:=
sign*Exp[logdet]
Out[3]=

Or using the built-in Wolfram Language function:

In[4]:=
Det[m]
Out[4]=

Scope (8) 

Compute the sign and natural logarithm of the determinant of a real-valued matrix:

In[5]:=
RandomReal[1, {3, 3}]
Out[5]=
In[6]:=
ResourceFunction["NumPySignLogDet"][%]
Out[6]=

Sparse array:

In[7]:=
ResourceFunction["NumPySignLogDet"][
 SparseArray[{{1, 1} -> 1, {2, 2} -> 2, {3, 3} -> 3, {1, 3} -> 4}]]
Out[7]=

NumericArray object:

In[8]:=
ResourceFunction["NumPySignLogDet"][
 NumericArray[RandomReal[1, {3, 3}], "Real64"]]
Out[8]=

Complex-valued array:

In[9]:=
ResourceFunction["NumPySignLogDet"][RandomComplex[1 + I, {3, 3}]]
Out[9]=

A tensor representing a list of matrices:

In[10]:=
t = RandomReal[1, {3, 2, 2}]
Out[10]=
In[11]:=
ResourceFunction["NumPySignLogDet"][%]
Out[11]=
In[12]:=
Normal[%]
Out[12]=
In[13]:=
%[[1]]*Exp[%[[2]]]
Out[13]=

Compare with the built-in Det:

In[14]:=
Det /@ t
Out[14]=

Use a singular matrix:

In[15]:=
m = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}} // N
Out[15]=
In[16]:=
ResourceFunction["NumPySignLogDet"][m]
Out[16]=
In[17]:=
%[[1]]*Exp[%[[2]]]
Out[17]=

Compare:

In[18]:=
Det[m]
Out[18]=

Large matrix:

In[19]:=
rr = RandomReal[1, {1000, 1000}];
In[20]:=
ResourceFunction["NumPySignLogDet"][rr]
Out[20]=
In[21]:=
%[[1]] Exp[%[[2]]]
Out[21]=

Compare:

In[22]:=
Det[rr]
Out[22]=

Make several calls to NumPySignLogDet in the same external session:

In[23]:=
session = StartExternalSession["Python"]
Out[23]=
In[24]:=
ResourceFunction["NumPySignLogDet"][RandomReal[1, {2, 2}], session]
Out[24]=
In[25]:=
ResourceFunction["NumPySignLogDet"][RandomReal[1, {3, 3}], session]
Out[25]=

End the session:

In[26]:=
DeleteObject[session]

Properties and Relations (4) 

For real matrices, NumPySignLogDet returns the signs as -1 or 1 depending on whether the determinant is negative or positive:

In[27]:=
ResourceFunction["NumPySignLogDet"][RandomReal[2, {10, 3, 3}]]
Out[27]=
In[28]:=
Normal[%[[1]]]
Out[28]=

The sign is zero if the determinant is 0:

In[29]:=
Join[{#[[1]]}, #] &@RandomReal[1, {2, 3}]
Out[29]=
In[30]:=
ResourceFunction["NumPySignLogDet"][%]
Out[30]=

For complex matrices, the signs are complex numbers with absolute values of 1:

In[31]:=
ResourceFunction["NumPySignLogDet"][RandomComplex[1 + I, {10, 5, 5}]]
Out[31]=
In[32]:=
Abs[Normal[%[[1]]]]
Out[32]=

Or complex zero for singular matrices:

In[33]:=
Join[{#[[1]]}, #] &@RandomComplex[1, {2, 3}]
Out[33]=
In[34]:=
ResourceFunction["NumPySignLogDet"][%]
Out[34]=

NumPySignLogDet can give more accurate results than the resource function NumPyDet for small determinants:

In[35]:=
m = IdentityMatrix[500]/10;
In[36]:=
ResourceFunction["NumPyDet"][N[m]]
Out[36]=
In[37]:=
ResourceFunction["NumPySignLogDet"][m // N]
Out[37]=
In[38]:=
{#[[1]] Exp[#[[2]]] &@SetPrecision[%, 20], N[Det[m], 20]}
Out[38]=

And determinants with large absolute values:

In[39]:=
m = RandomReal[10^200, {1000, 1000}];
In[40]:=
ResourceFunction["NumPyDet"][m]
Out[40]=
In[41]:=
ResourceFunction["NumPySignLogDet"][m]
Out[41]=
In[42]:=
{#[[1]] Exp[#[[2]]] &@SetPrecision[%, 20], N[Det[m], 20]}
Out[42]=

NumPySignLogDet may still give inaccurate results since it computes with machine precision:

In[43]:=
m = HilbertMatrix[30];
In[44]:=
ResourceFunction["NumPySignLogDet"][N[m]]
Out[44]=
In[45]:=
{#[[1]] Exp[#[[2]]] &@SetPrecision[%, 20], N[Det[m], 20]}
Out[45]=

Possible Issues (3) 

Automatic conversion of the input array to a NumericArray object can fail:

In[46]:=
a = SparseArray[{{i_, i_} -> -2., {i_, j_} /; Abs[i - j] == 1 -> 1.}, {10, 10}]
Out[46]=
In[47]:=
ResourceFunction["NumPySignLogDet"][a]
Out[47]=

Convert the array to a NumericArray before passing it to NumPySignLogDet:

In[48]:=
ResourceFunction["NumPySignLogDet"][NumericArray[a, "Real32"]]
Out[48]=

A call to NumPySignLogDet on an arbitrary precision array fails:

In[49]:=
m = N[{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, 20]
Out[49]=
In[50]:=
ResourceFunction["NumPySignLogDet"][m]
Out[50]=

Convert the array to a NumericArray before passing it to NumPySignLogDet:

In[51]:=
ResourceFunction["NumPySignLogDet"][NumericArray[m, "Real64"]]
Out[51]=

Or use the machine-precision array:

In[52]:=
ResourceFunction["NumPySignLogDet"][N[m]]
Out[52]=

The logarithm value returned by NumPySignLogDet may be too small to compute the determinant with machine precision:

In[53]:=
m = IdentityMatrix[200]/100;
In[54]:=
ResourceFunction["NumPySignLogDet"][m // N]
Out[54]=
In[55]:=
%[[1]]*Exp[%[[2]]]
Out[55]=

Raise precision to get an estimate of the determinant:

In[56]:=
SetPrecision[%%, 20]
Out[56]=
In[57]:=
%[[1]]*Exp[%[[2]]]
Out[57]=

Compare:

In[58]:=
N[Det[m], 20]
Out[58]=

Version History

  • 1.0.0 – 07 December 2020

Related Resources

License Information