Skip to content

Commit

Permalink
Rework linear independence
Browse files Browse the repository at this point in the history
  • Loading branch information
lgoettgens committed Feb 23, 2024
1 parent d186672 commit 60bb235
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 54 deletions.
4 changes: 2 additions & 2 deletions src/DeformationBases/ArcDiagDeformBasis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ struct ArcDiagDeformBasis{C <: RingElem} <: DeformBasis{C}
if !no_normalize
iter = unique(Iterators.filter(b -> !iszero(b), iter))
collected = Vector{DeformationMap{C}}(collect(iter))
_, rels = is_linearly_independent_with_relations(coefficient_ring(sp), reverse(collected))
inds = [1 + ncols(rels) - (findfirst(!iszero, vec(rels[i, :]))::Int) for i in nrows(rels):-1:1]
_, rels = is_linearly_independent_with_relations(coefficient_ring(sp), collected)
inds = [findlast(!iszero, vec(rels[i, :]))::Int for i in 1:nrows(rels)]
deleteat!(collected, inds)
return new{C}(length(collected), collected, extra_data, normalize)
end
Expand Down
133 changes: 81 additions & 52 deletions src/LinearIndependence.jl
Original file line number Diff line number Diff line change
@@ -1,71 +1,100 @@
function is_linearly_independent(F::Field, V::Vector{T}) where {T}
return is_linearly_independent_with_relations(F, V)[1]
const _linear_independence_rref_cutoff = 0

function column_rref!(mat::MatElem{T}) where {T <: FieldElem}
rk = rref!(AbstractAlgebra.Solve.lazy_transpose(mat))
return view(mat, :, 1:rk)

Check warning on line 5 in src/LinearIndependence.jl

View check run for this annotation

Codecov / codecov/patch

src/LinearIndependence.jl#L3-L5

Added lines #L3 - L5 were not covered by tests
end

function column_rref!(mat::Nemo._MatTypes) # change to Nemo._FieldMatTypes
trmat = transpose!(mat)
rk = rref!(trmat)
return view(transpose!(trmat), :, 1:rk)
end

function is_linearly_independent(V::Vector{T}) where {T}
return is_linearly_independent_with_relations(V)[1]

Check warning on line 15 in src/LinearIndependence.jl

View check run for this annotation

Codecov / codecov/patch

src/LinearIndependence.jl#L14-L15

Added lines #L14 - L15 were not covered by tests
end

function is_linearly_independent_with_relations(F::Field, V::Vector{<:FieldElem})
n, M = kernel(matrix(F, length(V), 1, V); side=:left)
return n == 0, M
function is_linearly_independent(F::Field, V::Vector{T}) where {T}
return is_linearly_independent_with_relations(F, V)[1]

Check warning on line 19 in src/LinearIndependence.jl

View check run for this annotation

Codecov / codecov/patch

src/LinearIndependence.jl#L18-L19

Added lines #L18 - L19 were not covered by tests
end

function is_linearly_independent_with_relations(F::Field, V::Vector{<:PolyRingElem})
n = length(V)
if n == 0
return false, zero_matrix(F, 0, 0)
end
rels = identity_matrix(F, n)
maxdeg = maximum(degree, V)
for i in 1:maxdeg
rels = basis_intersection(rels, is_linearly_independent_with_relations(F, [coeff(v, i) for v in V])[2])
iszero(rels) && return true, rels
end
return false, rels
function is_linearly_independent_with_relations(V::Vector{T}) where {T}
M = kernel(_linear_independence_coeff_matrix(V); side=:left)
return nrows(M) == 0, M

Check warning on line 24 in src/LinearIndependence.jl

View check run for this annotation

Codecov / codecov/patch

src/LinearIndependence.jl#L22-L24

Added lines #L22 - L24 were not covered by tests
end

function is_linearly_independent_with_relations(F::Field, V::Vector{T}) where {T}
M = kernel(_linear_independence_coeff_matrix(F, V); side=:left)
return nrows(M) == 0, M
end

function is_linearly_independent_with_relations(F::Field, V::Vector{<:MatElem})
function _linear_independence_coeff_matrix(V::Vector{<:FieldElem})
@req length(V) > 0 "For empty vectors, the field needs to be specified"
return _linear_independence_coeff_matrix(parent(V[1]), V)

Check warning on line 34 in src/LinearIndependence.jl

View check run for this annotation

Codecov / codecov/patch

src/LinearIndependence.jl#L32-L34

Added lines #L32 - L34 were not covered by tests
end

function _linear_independence_coeff_matrix(F::Field, V::Vector{<:FieldElem})
return matrix(F, length(V), 1, V)
end

function _linear_independence_coeff_matrix(F::Field, V::Vector{<:PolyRingElem})
@req isempty(V) || all(v -> parent(v) === parent(V[1]), V) "Incompatible polynomial rings"
return reduce(

Check warning on line 43 in src/LinearIndependence.jl

View check run for this annotation

Codecov / codecov/patch

src/LinearIndependence.jl#L41-L43

Added lines #L41 - L43 were not covered by tests
hcat,
begin
mat = _linear_independence_coeff_matrix(F, [coeff(v, i) for v in V])
if ncols(mat) > _linear_independence_rref_cutoff * nrows(mat)
column_rref!(mat)

Check warning on line 48 in src/LinearIndependence.jl

View check run for this annotation

Codecov / codecov/patch

src/LinearIndependence.jl#L46-L48

Added lines #L46 - L48 were not covered by tests
else
mat

Check warning on line 50 in src/LinearIndependence.jl

View check run for this annotation

Codecov / codecov/patch

src/LinearIndependence.jl#L50

Added line #L50 was not covered by tests
end
end for i in 0:maximum(degree, V; init=-1);
init=zero_matrix(F, length(V), 0),
)
end

function _linear_independence_coeff_matrix(F::Field, V::Vector{<:MatElem})
n = length(V)
if n == 0
return false, zero_matrix(F, 0, 0)
end
@req all(size(v) == size(V[1]) for v in V) "Size mismatch"
rels = identity_matrix(F, n)
for i in eachindex(V[1])
rels = basis_intersection(rels, is_linearly_independent_with_relations(F, [v[i] for v in V])[2])
iszero(rels) && return true, rels
return zero_matrix(F, n, 0)
end
return false, rels
@req all(v -> parent(v) === parent(V[1]), V) "Incompatible matrix spaces"
return reduce(
hcat,
begin
mat = _linear_independence_coeff_matrix(F, [v[i] for v in V])
if ncols(mat) > _linear_independence_rref_cutoff * nrows(mat)
column_rref!(mat)
else
mat
end
end for i in eachindex(V[1]);
init=zero_matrix(F, n, 0),
)
end

function is_linearly_independent_with_relations(F::Field, V::Vector{<:FreeAssAlgElem})
coeff_maps = [Dict{Vector{Int}, elem_type(F)}(zip(exponent_words(v), coefficients(v))) for v in V]
words = reduce(union, keys.(coeff_maps))
function _linear_independence_coeff_matrix(F::Field, V::Vector{<:FreeAssAlgElem})
n = length(V)
rels = identity_matrix(F, n)
for word in words
rels = basis_intersection(
rels,
is_linearly_independent_with_relations(F, [get(coeff_map, word, zero(F)) for coeff_map in coeff_maps])[2],
)
iszero(rels) && return true, rels
if n == 0
return zero_matrix(F, n, 0)

Check warning on line 80 in src/LinearIndependence.jl

View check run for this annotation

Codecov / codecov/patch

src/LinearIndependence.jl#L80

Added line #L80 was not covered by tests
end
return false, rels
R = parent(V[1])
C = base_ring(R)
@req all(v -> parent(v) === R, V) "Incompatible algebras"
coeff_maps = [Dict{Vector{Int}, elem_type(F)}(zip(exponent_words(v), coefficients(v))) for v in V]
support_words = reduce(union, keys.(coeff_maps))
return reduce(
hcat,
begin
mat = _linear_independence_coeff_matrix(F, [get(coeff_map, word, zero(C)) for coeff_map in coeff_maps])
if ncols(mat) > _linear_independence_rref_cutoff * nrows(mat)
column_rref!(mat)
else
mat

Check warning on line 94 in src/LinearIndependence.jl

View check run for this annotation

Codecov / codecov/patch

src/LinearIndependence.jl#L94

Added line #L94 was not covered by tests
end
end for word in support_words;
init=zero_matrix(F, n, 0),
)
end

function basis_intersection(V::MatElem{T}, W::MatElem{T}) where {T <: FieldElem}
# using Zassenhaus
@req base_ring(V) == base_ring(W) "Incompatible base rings"
@req ncols(V) == ncols(W) "Size mismatch"
if nrows(V) == 0 || nrows(W) == 0
return zero(V, 0, ncols(V))
end
if V == W
return V
end
block_mat = vcat(hcat(V, V), hcat(W, zero(W)))
s = rref!(block_mat)
r = rank(block_mat[:, 1:ncols(V)])
return block_mat[r+1:s, ncols(V)+1:end]
end

0 comments on commit 60bb235

Please sign in to comment.