Skip to content

Commit 9ff469a

Browse files
author
Release Manager
committed
gh-35375: Fix minimal kernel basis corner cases Fixes the issues in #35258 and add relevant tests/examples - fix the case of the zero matrix (test `d is -1` replaced by `d == -1`) - fix the case of matrices having zero columns or zero rows - fix the construction of the approximation order in the corner case where it may have a zero entry (e.g. constant matrix having a zero column or row), by adding `1` to this entry in such cases (the approximation order of this column/row does not matter anyway since the column/row is zero). URL: #35375 Reported by: Vincent Neiger Reviewer(s): Travis Scrimshaw
2 parents 55ebb79 + 7b655f1 commit 9ff469a

File tree

1 file changed

+61
-13
lines changed

1 file changed

+61
-13
lines changed

src/sage/matrix/matrix_polynomial_dense.pyx

+61-13
Original file line numberDiff line numberDiff line change
@@ -3938,10 +3938,32 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense):
39383938
[ 6*x 6*x^2]
39393939
[ 1 0]
39403940
[ 0 1]
3941+
3942+
Some particular cases (matrix is zero, dimension is zero, column is zero)::
3943+
3944+
sage: Matrix(pR, 2, 1).minimal_kernel_basis()
3945+
[1 0]
3946+
[0 1]
3947+
3948+
sage: Matrix(pR, 2, 0).minimal_kernel_basis()
3949+
[1 0]
3950+
[0 1]
3951+
3952+
sage: Matrix(pR, 0, 2).minimal_kernel_basis()
3953+
[]
3954+
3955+
sage: Matrix(pR, 3, 2, [[1,0],[1,0],[1,0]]).minimal_kernel_basis()
3956+
[6 1 0]
3957+
[6 0 1]
3958+
3959+
sage: Matrix(pR, 3, 2, [[x,0],[1,0],[x+1,0]]).minimal_kernel_basis()
3960+
[6 x 0]
3961+
[6 6 1]
39413962
"""
3963+
from sage.matrix.constructor import matrix
3964+
39423965
m = self.nrows()
39433966
n = self.ncols()
3944-
d = self.degree()
39453967

39463968
# set default shifts / check shifts dimension
39473969
if shifts is None:
@@ -3953,15 +3975,17 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense):
39533975

39543976
# compute kernel basis
39553977
if row_wise:
3956-
if d is -1: # matrix is zero
3957-
from sage.matrix.constructor import matrix
3958-
return matrix.identity(self.base_ring(), m, m)
3959-
39603978
if m <= n and self.constant_matrix().rank() == m:
3961-
# early exit: kernel is empty
3962-
from sage.matrix.constructor import matrix
3979+
# early exit: kernel is empty; note: this covers the case m==0
39633980
return matrix(self.base_ring(), 0, m)
39643981

3982+
if n == 0: # early exit: kernel is identity
3983+
return matrix.identity(self.base_ring(), m, m)
3984+
3985+
d = self.degree() # well defined since m > 0 and n > 0
3986+
if d == -1: # matrix is zero: kernel is identity
3987+
return matrix.identity(self.base_ring(), m, m)
3988+
39653989
# degree bounds on the kernel basis
39663990
degree_bound = min(m,n)*d+max(shifts)
39673991
degree_bounds = [degree_bound - shifts[i] for i in range(m)]
@@ -3970,6 +3994,17 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense):
39703994
orders = self.column_degrees(degree_bounds)
39713995
for i in range(n): orders[i] = orders[i]+1
39723996

3997+
# note: minimal_approximant_basis requires orders[i] > 0
3998+
# -> if d>0, then degree_bounds > 0 entry-wise and this tuple
3999+
# `orders` already has all entries strictly positive
4000+
# -> if d==0, then `orders[i]` is zero exactly when the column i
4001+
# of self is zero; we may as well take orders[i] == 1 for such
4002+
# columns which do not influence the left kernel
4003+
if d == 0:
4004+
for i in range(n):
4005+
if orders[i] == 0:
4006+
orders[i] = 1
4007+
39734008
# compute approximant basis and retrieve kernel rows
39744009
P = self.minimal_approximant_basis(orders,shifts,True,normal_form)
39754010
row_indices = []
@@ -3979,15 +4014,17 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense):
39794014
return P[row_indices,:]
39804015

39814016
else:
3982-
if d is -1: # matrix is zero
3983-
from sage.matrix.constructor import matrix
3984-
return matrix.identity(self.base_ring(), n, n)
3985-
39864017
if n <= m and self.constant_matrix().rank() == n:
3987-
# early exit: kernel is empty
3988-
from sage.matrix.constructor import matrix
4018+
# early exit: kernel is empty; this covers the case n==0
39894019
return matrix(self.base_ring(), n, 0)
39904020

4021+
if m == 0: # early exit: kernel is identity
4022+
return matrix.identity(self.base_ring(), n, n)
4023+
4024+
d = self.degree() # well defined since m > 0 and n > 0
4025+
if d == -1: # matrix is zero
4026+
return matrix.identity(self.base_ring(), n, n)
4027+
39914028
# degree bounds on the kernel basis
39924029
degree_bound = min(m,n)*d+max(shifts)
39934030
degree_bounds = [degree_bound - shifts[i] for i in range(n)]
@@ -3996,6 +4033,17 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense):
39964033
orders = self.row_degrees(degree_bounds)
39974034
for i in range(m): orders[i] = orders[i]+1
39984035

4036+
# note: minimal_approximant_basis requires orders[i] > 0
4037+
# -> if d>0, then degree_bounds > 0 entry-wise and this tuple
4038+
# `orders` already has all entries strictly positive
4039+
# -> if d==0, then `orders[i]` is zero exactly when the row i
4040+
# of self is zero; we may as well take orders[i] == 1 for such
4041+
# rows which do not influence the right kernel
4042+
if d == 0:
4043+
for i in range(m):
4044+
if orders[i] == 0:
4045+
orders[i] = 1
4046+
39994047
# compute approximant basis and retrieve kernel columns
40004048
P = self.minimal_approximant_basis(orders,shifts,False,normal_form)
40014049
column_indices = []

0 commit comments

Comments
 (0)