diff --git a/src/DeformationBases/ArcDiagDeformBasis.jl b/src/DeformationBases/ArcDiagDeformBasis.jl index 2b9bf0d..841445a 100644 --- a/src/DeformationBases/ArcDiagDeformBasis.jl +++ b/src/DeformationBases/ArcDiagDeformBasis.jl @@ -101,7 +101,11 @@ struct ArcDiagDeformBasis{C <: RingElem} <: DeformBasis{C} iter = Iterators.flatten(iters) if !no_normalize iter = unique(Iterators.filter(b -> !iszero(b), iter)) - len = length(iter) + collected = Vector{DeformationMap{C}}(collect(iter)) + _, 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 return new{C}(len, iter, extra_data, normalize) end diff --git a/src/DeformationBases/PseudographDeformBasis.jl b/src/DeformationBases/PseudographDeformBasis.jl index 82db3b0..9d91bef 100644 --- a/src/DeformationBases/PseudographDeformBasis.jl +++ b/src/DeformationBases/PseudographDeformBasis.jl @@ -62,7 +62,11 @@ struct PseudographDeformBasis{C <: RingElem} <: DeformBasis{C} iter = Iterators.flatten(iters) if !no_normalize iter = unique(Iterators.filter(b -> !iszero(b), iter)) - len = length(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] + deleteat!(collected, inds) + return new{C}(length(collected), collected, extra_data, normalize) end return new{C}(len, iter, extra_data, normalize) end diff --git a/src/LinearIndependence.jl b/src/LinearIndependence.jl new file mode 100644 index 0000000..784a3c4 --- /dev/null +++ b/src/LinearIndependence.jl @@ -0,0 +1,100 @@ +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) +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] +end + +function is_linearly_independent(F::Field, V::Vector{T}) where {T} + return is_linearly_independent_with_relations(F, V)[1] +end + +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 +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 _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) +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( + 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) + else + mat + 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 zero_matrix(F, n, 0) + end + @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 _linear_independence_coeff_matrix(F::Field, V::Vector{<:FreeAssAlgElem}) + n = length(V) + if n == 0 + return zero_matrix(F, n, 0) + end + 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 + end + end for word in support_words; + init=zero_matrix(F, n, 0), + ) +end + diff --git a/src/PBWDeformations.jl b/src/PBWDeformations.jl index b7f5f28..5272a8e 100644 --- a/src/PBWDeformations.jl +++ b/src/PBWDeformations.jl @@ -81,6 +81,8 @@ export general_linear_lie_algebra export inneighbor export inneighbors export is_crossing_free +export is_linearly_independent +export is_linearly_independent_with_relations export is_pbwdeformation export isomorphic_module_with_simple_structure export lookup_data @@ -117,6 +119,7 @@ end include("OscarPatches.jl") +include("LinearIndependence.jl") include("ModuleSimpleStructure.jl") include("DeformationBases/DeformBasis.jl") diff --git a/test/DeformationBases-test.jl b/test/DeformationBases-test.jl index b595ad1..b036489 100644 --- a/test/DeformationBases-test.jl +++ b/test/DeformationBases-test.jl @@ -45,15 +45,12 @@ @test all_pbwdeformations(sp, b) == collect(b) b = ArcDiagDeformBasis{QQFieldElem}(sp, 0:3) - @test length(collect(b)) == 4 - @test all_pbwdeformations(sp, b; special_return=SMat)[1] == - matrix(QQ, 4, 3, [1, 0, 0, 0, -3 // 2, 1 // 2, 0, 1, 0, 0, 0, 1]) + @test length(collect(b)) == 3 + @test all_pbwdeformations(sp, b; special_return=SMat)[1] == matrix(QQ, [1 0; 0 -3//2; 0 1]) ms = all_pbwdeformations(sp, b) - @test length(ms) == 3 + @test length(ms) == 2 @test ms[1] == collect(b)[1] @test 2 * ms[2] == -3 * collect(b)[2] + 2 * collect(b)[3] - @test 2 * ms[3] == 1 * collect(b)[2] + 2 * collect(b)[4] - @test iszero(ms[2] + ms[3]) # TODO: Check result for linear independence end @testset "SO_5, ⋀²V" begin @@ -139,15 +136,12 @@ @test all_pbwdeformations(sp, b) == collect(b) b = PseudographDeformBasis{QQFieldElem}(sp, 0:3) - @test length(collect(b)) == 4 - @test all_pbwdeformations(sp, b; special_return=SMat)[1] == - matrix(QQ, 4, 3, [1, 0, 0, 0, -3 // 2, 1 // 2, 0, 1, 0, 0, 0, 1]) + @test length(collect(b)) == 3 + @test all_pbwdeformations(sp, b; special_return=SMat)[1] == matrix(QQ, [1 0; 0 -3//2; 0 1]) ms = all_pbwdeformations(sp, b) - @test length(ms) == 3 + @test length(ms) == 2 @test ms[1] == collect(b)[1] @test 2 * ms[2] == -3 * collect(b)[2] + 2 * collect(b)[3] - @test 2 * ms[3] == 1 * collect(b)[2] + 2 * collect(b)[4] - @test iszero(ms[2] + ms[3]) end @testset "SO_5, ⋀²V" begin