Project

General

Profile

Bug #1280

Determinant & Inverse of matrix over non integral domain

Added by John Abbott almost 5 years ago. Updated 3 months ago.

Status:
In Progress
Priority:
High
Assignee:
Category:
Improving
Target version:
Start date:
03 May 2019
Due date:
% Done:

40%

Estimated time:
Spent time:

Description

CoCoA gives unnecessary errors when computing det or inverse of a matrix over a non-integral domain.

Rectify!


Related issues

Related to CoCoALib - Bug #15: Adjoint of a non-invertible matrixClosed2011-10-28

Related to CoCoALib - Design #1279: Tidy up code for matrix determinantClosed2019-05-03

History

#1 Updated by John Abbott almost 5 years ago

Here is a simple failing case:

ZZ6 ::= ZZ/(6);
M := IdentityMat(ZZ6,6);
det(M);  --> ERROR (not sparse poly ring !??!)
M^(-1);  --> ERROR (not int.dom.)

Inverse always fails, but det succeeds up to size 5x5 because small matrices are handled specially.

#2 Updated by John Abbott almost 5 years ago

  • Related to Bug #15: Adjoint of a non-invertible matrix added

#3 Updated by John Abbott almost 5 years ago

  • Related to Design #1279: Tidy up code for matrix determinant added

#4 Updated by John Abbott almost 5 years ago

  • Status changed from New to In Progress
  • % Done changed from 0 to 10

Some thoughts about computing the determinant.

There is special case code for:
  • small matrices (up to 5x5 incl.)
  • certain special matrices (e.g. ZeroMat, IdentityMat)
  • matrix over a field (i.e. gaussian reduction)
  • matrix over ZZ

The code is confusing because some special cases are handled "automatically" by C++ inheritance mechanism (e.g. ZeroMat and IdentityMat, perhaps also DiagMat),
while other special cases have to be handled separately.

It is also not entirely clear to me what the "general case" should be. The most general is DetDirect (expansion by minors), but it is likely to be very slow for matrices larger than 6x6, say. Fraction-free Bareiss is probably faster whenever it can be used, but there could be problems with zero-divisors. Perhaps the general case should try Bareiss, and if that fails then resort to expansion by minors...

#5 Updated by John Abbott almost 5 years ago

  • Assignee set to John Abbott

I'd like to rewrite ConstMatrixViewBase::myDet so that it calls the "fast" impls for small matrices. How to do this cleanly?

Presumably the final code should look something like this:

  if (IsSmallMatrix(M)) return DetOfSmallMatrix(M);

The complications are:
  • (A) the matrix is actually a *ConstMatrixViewBase (via this)
  • (B) there is no IsSmallMatrix test
  • (C) there is no function DetOfSmallMatrix

Part (C) can easily be resolved, but somehow (B) and (C) should be solved together. Part (A) can be resolved by wrapping the pointer into a ConstMatrixView object (this is a bit "clunky" but should be safe and efficient).

The fictitious IsSmallMatrix function actually depends on the operation to be performed (in this case det), so this should somehow be apparent in the call.

#6 Updated by John Abbott almost 5 years ago

I'm now wondering what is the difference between ConstMatrixViewBase::myDet and DenseMatImpl::myDet...

#7 Updated by John Abbott over 4 years ago

  • Target version changed from CoCoALib-0.99700 to CoCoALib-0.99800

#8 Updated by John Abbott over 3 years ago

Now det of a matrix over ZZ/(6) work also for larger matrices, but it is horribly slow :-(

ZZ6 ::= ZZ/(6);
M := IdentityMat(ZZ6,11);
det(M); --> takes 22s

Why does it not recognise that M is an identity matrix?
In this case we could "speculatively" try gauss (it will work), or alternatively compute det over ZZ and then reduce mod 6...

#9 Updated by John Abbott over 3 years ago

  • Target version changed from CoCoALib-0.99800 to CoCoALib-0.99850
  • % Done changed from 10 to 40

This question clearly needs more work -- postponing.

#10 Updated by John Abbott over 2 years ago

Here are some more examples which should work, but which do not:

/**/ ZZ15 ::= ZZ/(15);
/**/ M := mat(ZZ15, [[5,3],[3,5]]);
/**/ inverse(M);
--> ERROR: Ring is not an integral domain
--> [CoCoALib] InverseByGauss(Mat)  over non-integral domain
--> inverse(M);
--> ^^^^^^^^^^
/**/ det(M);
1
/**/ M := mat(ZZ15, [[5,3,3],[3,5,3],[3,3,5]]);
/**/ det(M);
-1
/**/ inverse(M);
--> ERROR: Ring is not an integral domain

Note that det works here but inverse does not. As observed earlier, it could be tricky deciding how to compute the inverse since all entries are zero-divisors.

#11 Updated by John Abbott over 2 years ago

Here is a way of making test cases for computing determinant:
take a unimodular matrix, and multiply it by a nzzd (which is not nilpotent).
So every entry is a zero-divisor, and all linear combinations of rows/cols contain only zero-divisors.

One possible approach is to represent the determinant as a sum of two other determinants,
by representing the [1,1]-element as a sum of two non-zero-divisors; compute recursively
the dets of the two matrices obtained by substituting the two summands in posn [1,1].
A problem is that we would have to repeat this process for each row/col; there would
have to be about 2^n low-level det computations.

I wonder if there is some clever "fraction-free" method.

Another (daft?) idea: if all entries are zero-divisors then try multiplying the matrix
by a random unimodular one. Maybe we will be lucky and get a matrix some of whose entries
are "nice" (i.e. not zero-divisors).

Two concrete examples:

UniMod := matrix(ZZ, [[1, 1, 3],  [2, 1, 4],  [1, 1, 2]]);
M := 3*matrix(ZZ15, UniMod); // all entries are nzzds

Here is a "lucky" multiplication by a unimodular mat:

N := mat(ZZ15, [[5,3,3],[3,5,3],[3,3,5]]);
N*mat(ZZ15, UniMod); // UniMod from example above
matrix( ZZ15, 
 [[-1, -4, 3],
  [1, -4, 5],
  [-1, -4, 1]])

I wonder how often we are lucky?

#12 Updated by John Abbott 3 months ago

  • Target version changed from CoCoALib-0.99850 to CoCoALib-0.99880

Also available in: Atom PDF