diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 915bcba..7939bb0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,26 +27,18 @@ jobs: os: ubuntu-latest arch: x64 steps: - - uses: actions/checkout@v3 - - uses: julia-actions/setup-julia@v1 + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@v2 with: version: ${{ matrix.version }} arch: ${{ matrix.arch }} - - uses: actions/cache@v1 - env: - cache-name: cache-artifacts - with: - path: ~/.julia/artifacts - key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }} - restore-keys: | - ${{ runner.os }}-test-${{ env.cache-name }}- - ${{ runner.os }}-test- - ${{ runner.os }}- + - uses: julia-actions/cache@v2 - uses: julia-actions/julia-buildpkg@v1 - uses: julia-actions/julia-runtest@v1 with: depwarn: error - uses: julia-actions/julia-processcoverage@v1 - - uses: codecov/codecov-action@v3 + - uses: codecov/codecov-action@v4 with: file: lcov.info + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/Project.toml b/Project.toml index 02c7d93..66db4d5 100644 --- a/Project.toml +++ b/Project.toml @@ -12,7 +12,7 @@ Reexport = "189a3867-3050-52da-a836-e630ba90ab69" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [compat] -MultivariatePolynomials = "0.5.6" +MultivariatePolynomials = "0.5.9" MutableArithmetics = "1" Reexport = "1" julia = "1" diff --git a/src/comp.jl b/src/comp.jl index a74c019..62ccfbb 100644 --- a/src/comp.jl +++ b/src/comp.jl @@ -2,7 +2,7 @@ import Base.== # TODO This should be in Base with T instead of Variable{V,M}. # See https://github.com/blegat/MultivariatePolynomials.jl/issues/3 -function (==)(x::Vector{Variable{V,M}}, y::Vector{Variable{V,M}}) where {V,M} +function Base.:(==)(x::Vector{Variable{V,M}}, y::Vector{Variable{V,M}}) where {V,M} if length(x) != length(y) false else @@ -20,119 +20,20 @@ end const AnyCommutative{O} = Union{Commutative{O},NonCommutative{O}} -function (==)( - x::Variable{<:AnyCommutative{CreationOrder}}, - y::Variable{<:AnyCommutative{CreationOrder}}, -) - return x.variable_order.order.id == y.variable_order.order.id && - x.kind == y.kind -end - -function Base.isless( +function Base.cmp( x::Variable{<:AnyCommutative{CreationOrder}}, y::Variable{<:AnyCommutative{CreationOrder}}, ) if x.variable_order.order.id == y.variable_order.order.id - return isless(y.kind, x.kind) + return cmp(y.kind, x.kind) else - return isless(y.variable_order.order.id, x.variable_order.order.id) - end -end - -# Comparison of Monomial - -function MP.compare(x::Monomial{V,M}, y::Monomial{V,M}) where {V,M} - return MP.compare(x, y, M) -end - -function MP.compare( - x::Monomial{V}, - y::Monomial{V}, - ::Type{MP.InverseLexOrder}, -) where {V} - i = MP.nvariables(x) - j = MP.nvariables(y) - @inbounds while i >= 1 && j >= 1 - if x.vars[i] < y.vars[j] - if x.z[i] == 0 - i -= 1 - else - return 1 - end - elseif x.vars[i] > y.vars[j] - if y.z[j] == 0 - j -= 1 - else - return -1 - end - elseif x.z[i] != y.z[j] - return x.z[i] - y.z[j] - else - i -= 1 - j -= 1 - end + return cmp(y.variable_order.order.id, x.variable_order.order.id) end - return 0 end -function MP.compare( - x::Monomial{V}, - y::Monomial{V}, - ::Type{MP.LexOrder}, -) where {V} - i = j = 1 - @inbounds while i <= nvariables(x) && j <= nvariables(y) - if x.vars[i] > y.vars[j] - if x.z[i] == 0 - i += 1 - else - return 1 - end - elseif x.vars[i] < y.vars[j] - if y.z[j] == 0 - j += 1 - else - return -1 - end - elseif x.z[i] != y.z[j] - return x.z[i] - y.z[j] - else - i += 1 - j += 1 - end - end - @inbounds while i <= nvariables(x) - if x.z[i] > 0 - return 1 - end - i += 1 - end - @inbounds while j <= nvariables(y) - if y.z[j] > 0 - return -1 - end - j += 1 - end - return 0 -end - -function (==)(x::Monomial{V,M}, y::Monomial{V,M}) where {V,M} - return MP.compare(x, y) == 0 -end -function (==)(x::Variable{V,M}, y::Monomial{V,M}) where {V,M} - return convert(Monomial{V,M}, x) == y -end - -# graded lex ordering -function Base.isless(x::Monomial{V,M}, y::Monomial{V,M}) where {V,M} - return MP.compare(x, y) < 0 -end -function Base.isless(x::Monomial{V,M}, y::Variable{V,M}) where {V,M} - return isless(x, convert(Monomial{V,M}, y)) -end -function Base.isless(x::Variable{V,M}, y::Monomial{V,M}) where {V,M} - return isless(convert(Monomial{V,M}, x), y) -end +# TODO remove +Base.:(==)(x::Variable, y::Variable) = iszero(cmp(x, y)) +Base.:(==)(x::Monomial, y::Monomial) = iszero(cmp(x, y)) # Comparison of MonomialVector function (==)(x::MonomialVector{V,M}, y::MonomialVector{V,M}) where {V,M} @@ -143,8 +44,8 @@ function (==)(x::MonomialVector{V,M}, y::MonomialVector{V,M}) where {V,M} # Should be sorted in the same order since the non-common # polyvar should have exponent 0 for (a, b) in zip(x.Z, y.Z) - A = zeros(length(allvars)) - B = zeros(length(allvars)) + A = zeros(Int, length(allvars)) + B = zeros(Int, length(allvars)) A[maps[1]] = a B[maps[2]] = b if A != B diff --git a/src/monomial_vector.jl b/src/monomial_vector.jl index b9d3e51..4f3520b 100644 --- a/src/monomial_vector.jl +++ b/src/monomial_vector.jl @@ -148,62 +148,6 @@ function _error_for_negative_degree(deg) end end -const _Lex = Union{MP.LexOrder,MP.InverseLexOrder} - -_last_lex_index(n, ::Type{MP.LexOrder}) = n -_prev_lex_index(i, ::Type{MP.LexOrder}) = i - 1 -_not_first_indices(n, ::Type{MP.LexOrder}) = n:-1:2 -_last_lex_index(_, ::Type{MP.InverseLexOrder}) = 1 -_prev_lex_index(i, ::Type{MP.InverseLexOrder}) = i + 1 -_not_first_indices(n, ::Type{MP.InverseLexOrder}) = 1:(n-1) - -function _fill_exponents!(Z, n, degs, ::Type{Commutative}, M::Type{<:_Lex}, filter::Function) - _error_for_negative_degree.(degs) - maxdeg = maximum(degs, init = 0) - I = _not_first_indices(n, M) - z = zeros(Int, n) - while true - deg = sum(z) - if deg in degs && filter(z) - push!(Z, z) - z = copy(z) - end - if deg == maxdeg - i = findfirst(i -> !iszero(z[i]), I) - if isnothing(i) - break - end - j = I[i] - z[j] = 0 - z[_prev_lex_index(j, M)] += 1 - else - z[_last_lex_index(n, M)] += 1 - end - end -end - -function _fill_exponents!(Z, n, deg, ::Type{Commutative}, M::Type{<:_Lex}, filter::Function, ::Int) - _error_for_negative_degree(deg) - I = _not_first_indices(n, M) - z = zeros(Int, n) - z[_last_lex_index(n, M)] = deg - while true - if filter(z) - push!(Z, z) - z = copy(z) - end - i = findfirst(i -> !iszero(z[i]), I) - if isnothing(i) - break - end - j = I[i] - p = z[j] - z[j] = 0 - z[_last_lex_index(n, M)] = p - 1 - z[_prev_lex_index(j, M)] += 1 - end -end - function _fill_noncomm_exponents_rec!(Z, z, i, n, deg, ::Type{MP.LexOrder}, filter::Function) if deg == 0 if filter(z) @@ -235,13 +179,6 @@ function _fill_exponents!( return reverse!(view(Z, start:length(Z))) end -function _fill_exponents!(Z, n, deg, ::Type{V}, ::Type{MP.Reverse{M}}, args...) where {V,M} - prev = lastindex(Z) - _fill_exponents!(Z, n, deg, V, M, args...) - reverse!(view(Z, (prev + 1):lastindex(Z))) - return -end - function _fill_exponents!( Z::Vector{Vector{Int}}, n, @@ -266,7 +203,7 @@ function _all_exponents( ::Type{M}, filter::Function, ) where {V,M} - Z = Vector{Vector{Int}}() + Z = Vector{Int}[] _fill_exponents!(Z, n, degs, V, M, filter) _isless = let M = M (a, b) -> MP.compare(a, b, M) < 0 @@ -275,28 +212,11 @@ function _all_exponents( return Z end -function MonomialVector( - vars::Vector{<:Variable{<:Commutative,M}}, - degs::AbstractVector{Int}, - filter::Function = x -> true, -) where {M} - vars = unique!(sort(vars, rev = true)) - return MonomialVector( - vars, - _all_exponents( - length(vars), - degs, - Commutative, - M, - z -> filter(Monomial(vars, z)), - ), - ) -end - function getvarsforlength(vars::Vector{<:Variable{<:NonCommutative}}, len::Int) n = length(vars) return map(i -> vars[((i-1)%n)+1], 1:len) end + function MonomialVector( vars::Vector{<:Variable{<:NonCommutative,M}}, degs::AbstractVector{Int}, @@ -313,6 +233,31 @@ function MonomialVector( v = isempty(Z) ? vars : getvarsforlength(vars, length(first(Z))) return MonomialVector(v, Z) end + +function MonomialVector( + vars::Vector{<:Variable{<:Commutative,M}}, + degs::AbstractVector{Int}, + filter::Function = x -> true, +) where {M} + vars = unique!(sort(vars, rev = true)) + if isempty(degs) + mindegree = 0 + maxdegree = -1 + else + mindegree = minimum(degs) + maxdegree = maximum(degs) + end + Z = Iterators.Filter(MP.ExponentsIterator{M}( + zeros(Int, length(vars)); + mindegree, + maxdegree, + )) do z + mono = Monomial(vars, z) + MP.degree(mono) in degs && filter(mono) + end + return MonomialVector(vars, collect(Z)) +end + function MonomialVector( vars::Vector{<:Variable}, degs::Int, @@ -324,6 +269,7 @@ end function MP.monomials(vars::AbstractVector{<:Variable}, args...) return MonomialVector(vars, args...) end + function MP.monomials(vars::Tuple{Vararg{Variable}}, args...) return monomials([vars...], args...) end @@ -390,7 +336,7 @@ end function MonomialVector{V,M}(X::DMonoVec{V,M}) where {V,M} allvars, Z = buildZvarsvec(Variable{V,M}, X) _isless = let M = M - (a, b) -> MP.compare(a, b, M) < 0 + (a, b) -> cmp(M(), a, b) < 0 end sort!(Z, lt = _isless) dups = findall(i -> Z[i] == Z[i-1], 2:length(Z)) diff --git a/src/operators.jl b/src/operators.jl index 1f999c8..e5d4e0c 100644 --- a/src/operators.jl +++ b/src/operators.jl @@ -109,7 +109,7 @@ function MA.operate!( end function _exponents_compare(q::Polynomial{V,M}, j, e) where {V,M} - return MP.compare(q.x.Z[j], e, M) + return cmp(M(), q.x.Z[j], e) end # TODO need to check that this also works for non-commutative diff --git a/src/poly.jl b/src/poly.jl index 8334416..119d608 100644 --- a/src/poly.jl +++ b/src/poly.jl @@ -219,7 +219,7 @@ function removedups_to!( ::Type{M}, ) where {T,M} _isless = let M = M - (a, b) -> MP.compare(a, b, M) < 0 + (a, b) -> cmp(M(), a, b) < 0 end σ = sortperm(Zdup, lt = _isless) i = 0 diff --git a/src/promote.jl b/src/promote.jl index 05eb398..ab07a94 100644 --- a/src/promote.jl +++ b/src/promote.jl @@ -1,3 +1,15 @@ +function MP.promote_variables(m1::Monomial, m2::Monomial) + if MP.variables(m1) == MP.variables(m2) + return m1, m2 + end + allvars, maps = mergevars([MP.variables(m1), MP.variables(m2)]) + z1 = zeros(Int, length(allvars)) + z1[maps[1]] = m1.z + z2 = zeros(Int, length(allvars)) + z2[maps[2]] = m2.z + return Monomial(allvars, z1), Monomial(allvars, z2) +end + function MP.promote_rule_constant( ::Type{T}, ::Type{<:DMonomialLike{V,M}}, diff --git a/test/comp.jl b/test/comp.jl index ff425c8..94c526b 100644 --- a/test/comp.jl +++ b/test/comp.jl @@ -13,8 +13,8 @@ end function _less(a, b) @test a < b @test b > a - @test compare(monomial(a), b) < 0 - @test compare(b, monomial(a)) > 0 + @test cmp(monomial(a), b) < 0 + @test cmp(b, monomial(a)) > 0 end @testset "Issue 152" begin @polyvar x y monomial_order=LexOrder @@ -76,24 +76,15 @@ end _test_monomials([x, y], 3, [x^3, x^2 * y, x * y^2, y^3]) end -@testset "Reverse{LexOrder}" begin - @polyvar x y monomial_order = Reverse{LexOrder} - _test_less(y^2, y) - _test_less(y, x^0) +@testset "Graded{Reverse{LexOrder}}" begin + @polyvar x y monomial_order = Graded{Reverse{LexOrder}} + _test_less(y, y^2) + _test_less(x^0, y) _test_less(x, y^2) _test_less(x^2, x * y^2) _test_monomials([x, y], 3, [x^3, x^2 * y, x * y^2, y^3]) -end - -@testset "Reverse{InverseLexOrder}" begin - @polyvar x y monomial_order = Reverse{InverseLexOrder} - _test_less(y^2, y) - _test_less(y, x^0) - _test_less(y^2, x) - _test_less(x * y^2, x^2) - _test_monomials([x, y], 3, [y^3, y^2 * x, y * x^2, x^3]) - _test_monomials([x, y], 1:2, [y^2, x * y, y, x^2, x]) - _test_monomials([x, y], [0, 1, 3], [y^3, x*y^2, x^2*y, y, x^3, x, 1]) + _test_monomials([x, y], 1:2, [x, y, x^2, x * y, y^2]) + _test_monomials([x, y], [0, 1, 3], [1, x, y, x^3, x^2 * y, x * y^2, y^3]) end @testset "Graded{Reverse{InverseLexOrder}}" begin