Skip to content

Commit

Permalink
Clean up _cansolve
Browse files Browse the repository at this point in the history
  • Loading branch information
joschmitt committed Feb 23, 2024
1 parent 351fc6d commit 05dd769
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 103 deletions.
105 changes: 22 additions & 83 deletions src/flint/fmpz_mat.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1250,18 +1250,16 @@ end
#
###############################################################################

@doc raw"""
_cansolve(a::ZZMatrix, b::ZZMatrix) -> Bool, ZZMatrix
function Solve._can_solve_internal_no_check(A::ZZMatrix, b::ZZMatrix, task::Symbol; side::Symbol = :left)
if side === :left
fl, sol, K = Solve._can_solve_internal_no_check(transpose(A), transpose(b), task, side = :right)
return fl, transpose(sol), transpose(K)
end

Return true and a matrix $x$ such that $ax = b$, or false and some matrix
in case $x$ does not exist.
"""
function _cansolve(a::ZZMatrix, b::ZZMatrix)
nrows(b) != nrows(a) && error("Incompatible dimensions in _cansolve")
H, T = hnf_with_transform(transpose(a))
H, T = hnf_with_transform(transpose(A))
b = deepcopy(b)
z = similar(a, ncols(b), ncols(a))
l = min(nrows(a), ncols(a))
z = similar(A, ncols(b), ncols(A))
l = min(nrows(A), ncols(A))
t = ZZRingElem() # temp. variable

for i = 1:ncols(b)
Expand All @@ -1275,41 +1273,38 @@ function _cansolve(a::ZZMatrix, b::ZZMatrix)
end
q, r = divrem(b[k, i], H[j, k])
if !iszero(r)
return false, b
return false, b, zero(A, 0, 0)

Check warning on line 1276 in src/flint/fmpz_mat.jl

View check run for this annotation

Codecov / codecov/patch

src/flint/fmpz_mat.jl#L1276

Added line #L1276 was not covered by tests
end
if !iszero(q)
# b[h, i] -= q*H[j, h]
GC.@preserve b H q t begin
H_ptr = mat_entry_ptr(H, j, k)
for h = k:ncols(H)
b_ptr = mat_entry_ptr(b, h, i)
ccall((:fmpz_mul, libflint), Cvoid, (Ref{ZZRingElem}, Ref{ZZRingElem}, Ptr{ZZRingElem}), t, q, H_ptr)
ccall((:fmpz_sub, libflint), Cvoid, (Ptr{ZZRingElem}, Ptr{ZZRingElem}, Ref{ZZRingElem}), b_ptr, b_ptr, t)
H_ptr += sizeof(ZZRingElem)

# b[h, i] -= q*H[j, h]
end
end
end
end
z[i, j] = q
end
end
if !iszero(b)
return false, b
end
return true, transpose(z*T)
end

function Solve._can_solve_internal_no_check(A::ZZMatrix, b::ZZMatrix, task::Symbol; side::Symbol = :left)
if side === :left
fl, sol, K = Solve._can_solve_internal_no_check(transpose(A), transpose(b), task, side = :right)
return fl, transpose(sol), transpose(K)
fl = is_zero(b)
if !fl
return false, zero(A, 0, 0), zero(A, 0, 0)
end
if task === :only_check
return true, zero(A, 0, 0), zero(A, 0, 0)

Check warning on line 1299 in src/flint/fmpz_mat.jl

View check run for this annotation

Codecov / codecov/patch

src/flint/fmpz_mat.jl#L1299

Added line #L1299 was not covered by tests
end

fl, sol = Nemo._cansolve(A, b)
if task === :only_check || task === :with_solution
return fl, sol, zero(A, 0, 0)
sol = transpose(z*T)
if task === :with_solution
return true, sol, zero(A, 0, 0)
end
return fl, sol, kernel(A, side = :right)
_, K = Solve._kernel_of_hnf(A, H, T)
return fl, sol, K
end

# Overwrite some solve context functionality so that it uses `transpose` and not
Expand Down Expand Up @@ -1428,62 +1423,6 @@ function AbstractAlgebra._hcat(A::AbstractVector{ZZMatrix})
return M
end

@doc raw"""
_cansolve_with_nullspace(a::ZZMatrix, b::ZZMatrix) -> Bool, ZZMatrix, ZZMatrix
Return true, a matrix $x$ and a matrix $k$ such that $ax = b$ and the columns
of $k$ form a basis for the nullspace of $a$. In case $x$ does not exist, false
and two arbitrary matrices are returned.
"""
function _cansolve_with_nullspace(a::ZZMatrix, b::ZZMatrix)
nrows(b) != nrows(a) && error("Incompatible dimensions in _cansolve_with_nullspace")
H, T = hnf_with_transform(transpose(a))
b = deepcopy(b)
z = similar(a, ncols(b), ncols(a))
l = min(nrows(a), ncols(a))
for i=1:ncols(b)
for j=1:l
k = 1
while k <= ncols(H) && is_zero_entry(H, j, k)
k += 1
end
if k > ncols(H)
continue
end
q, r = divrem(b[k, i], H[j, k])
if !iszero(r)
return false, b, b
end
if !iszero(q)
for h=k:ncols(H)
b[h, i] -= q*H[j, h]
end
end
z[i, k] = q
end
end
if !iszero(b)
return false, b, b
end

for i = nrows(H):-1:1
for j = 1:ncols(H)
if !is_zero_entry(H, i, j)
N = similar(a, ncols(a), nrows(H) - i)
for k = 1:nrows(N)
for l = 1:ncols(N)
N[k,l] = T[nrows(T) - l + 1, k]
end
end
return true, transpose(z*T), N
end
end
end
N = similar(a, ncols(a), 0)

return true, (z*T), N
end

@doc raw"""
_solve_rational(a::ZZMatrix, b::ZZMatrix)
Expand Down
20 changes: 0 additions & 20 deletions test/flint/fmpz_mat-test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -655,24 +655,6 @@ end
end

@testset "ZZMatrix.solve" begin
S = matrix_space(FlintZZ, 3, 3)

A = S([ZZRingElem(2) 3 5; 1 4 7; 9 2 2])

T = matrix_space(FlintZZ, 3, 1)

B = T([ZZRingElem(4), 5, 7])

A = matrix(ZZ, 2, 2, [1, 0, 0, 0])
B = matrix(ZZ, 2, 2, [0, 0, 0, 1])
fl, X = Nemo._cansolve_with_nullspace(A, B)
@test !fl

A = matrix(ZZ, 2, 2, [1, 0, 0, 0])
B = matrix(ZZ, 2, 2, [0, 1, 0, 0])
fl, X, Z = Nemo._cansolve_with_nullspace(A, B)
@test fl && A*X == B && iszero(A * Z)

A = matrix(ZZ, 2, 2, [1,2,3,4])
b = matrix(ZZ, 1, 2, [1, 6])
@test Nemo._solve_triu_left(A, b) == matrix(ZZ, 1, 2, [1, 1])
Expand All @@ -682,9 +664,7 @@ end
c = similar(b)
AbstractAlgebra._solve_tril!(c, A, b)
@test c == matrix(ZZ, 2, 1, [1, 1])
end

@testset "ZZMatrix.Solve.solve" begin
S = matrix_space(FlintZZ, 3, 3)

A = S([ZZRingElem(2) 3 5; 1 4 7; 9 2 2])
Expand Down

0 comments on commit 05dd769

Please sign in to comment.