Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ jobs:
- version: '1.6'
os: ubuntu-latest
arch: x64
- version: '1.10'
os: ubuntu-latest
arch: x64
- version: '1'
os: ubuntu-latest
arch: x86
Expand All @@ -28,7 +31,7 @@ jobs:
arch: x64
steps:
- uses: actions/checkout@v4
- uses: julia-actions/setup-julia@v1
- uses: julia-actions/setup-julia@v2
with:
version: ${{ matrix.version }}
arch: ${{ matrix.arch }}
Expand Down
1 change: 1 addition & 0 deletions docs/src/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ powers
constant_monomial
map_exponents
multiplication_preserves_monomial_order
promote_variables
```

### Ordering
Expand Down
99 changes: 92 additions & 7 deletions src/comparison.jl
Original file line number Diff line number Diff line change
Expand Up @@ -249,12 +249,27 @@
same_degree_ordering::O
end

_deg(exponents) = sum(exponents)
_deg(mono::AbstractMonomial) = degree(mono)

function compare(a, b, ::Type{Graded{O}}) where {O}
deg_a = _deg(a)
deg_b = _deg(b)
function compare(
a::_TupleOrVector,
b::_TupleOrVector,
::Type{Graded{O}},
) where {O}
deg_a = sum(a)
deg_b = sum(b)
if deg_a == deg_b
return compare(a, b, O)
else
return deg_a - deg_b
end
end
# TODO Backward compat, remove
function compare(
a::AbstractMonomial,
b::AbstractMonomial,
::Type{Graded{O}},
) where {O}
deg_a = degree(a)
deg_b = degree(b)
if deg_a == deg_b
return compare(a, b, O)
else
Expand Down Expand Up @@ -284,7 +299,21 @@
reverse_ordering::O
end

compare(a, b, ::Type{Reverse{O}}) where {O} = compare(b, a, O)
function compare(
a::_TupleOrVector,
b::_TupleOrVector,
::Type{Reverse{O}},
) where {O}
return compare(b, a, O)
end
# TODO Backward compat, remove
function compare(
a::AbstractMonomial,
b::AbstractMonomial,
::Type{Reverse{O}},
) where {O}
return compare(b, a, O)
end

"""
ordering(p::AbstractPolynomialLike)
Expand All @@ -293,6 +322,62 @@
"""
function ordering end

ordering(::Type{<:AbstractMonomial}) = Graded{LexOrder}
ordering(::Type{P}) where {P} = ordering(monomial_type(P))
ordering(p::AbstractPolynomialLike) = ordering(typeof(p))

# We reverse the order of comparisons here so that the result
# of x < y is equal to the result of Monomial(x) < Monomial(y)
# Without `Base.@pure`, TypedPolynomials allocates on Julia v1.6
# with `promote(x * y, x)`
Base.@pure function compare(
v1::AbstractVariable,
v2::AbstractVariable,
::Type{<:AbstractMonomialOrdering},
)
return -cmp(name(v1), name(v2))
end

function compare(

Check warning on line 341 in src/comparison.jl

View check run for this annotation

Codecov / codecov/patch

src/comparison.jl#L341

Added line #L341 was not covered by tests
m1::AbstractMonomial,
m2::AbstractMonomial,
::Type{O},
) where {O<:AbstractMonomialOrdering}
s1, s2 = promote_variables(m1, m2)
return compare(exponents(s1), exponents(s2), O)

Check warning on line 347 in src/comparison.jl

View check run for this annotation

Codecov / codecov/patch

src/comparison.jl#L346-L347

Added lines #L346 - L347 were not covered by tests
end

# Implement this to make coefficients be compared with terms.
function _cmp_coefficient(a::Real, b::Real)
return cmp(a, b)
end
function _cmp_coefficient(a::Number, b::Number)
return cmp(abs(a), abs(b))
end
# By default, coefficients are not comparable so `a` is not strictly
# less than `b`, they are considered sort of equal.
_cmp_coefficient(a, b) = 0

function compare(
t1::AbstractTermLike,
t2::AbstractTermLike,
::Type{O},
) where {O<:AbstractMonomialOrdering}
Δ = compare(monomial(t1), monomial(t2), O)
if iszero(Δ)
return _cmp_coefficient(coefficient(t1), coefficient(t2))
end
return Δ
end

function Base.cmp(t1::AbstractTermLike, t2::AbstractTermLike)
return compare(t1, t2, ordering(t1))
end
# TODO for backward compat, remove in next breaking release
compare(t1::AbstractTermLike, t2::AbstractTermLike) = cmp(t1, t2)

Check warning on line 377 in src/comparison.jl

View check run for this annotation

Codecov / codecov/patch

src/comparison.jl#L377

Added line #L377 was not covered by tests

Base.isless(t1::AbstractTermLike, t2::AbstractTermLike) = cmp(t1, t2) < 0

_last_lex_index(n, ::Type{LexOrder}) = n
_prev_lex_index(i, ::Type{LexOrder}) = i - 1
_not_first_indices(n, ::Type{LexOrder}) = n:-1:2
Expand Down
2 changes: 1 addition & 1 deletion src/default_polynomial.jl
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ Base.one(p::Polynomial) = one(typeof(p))
Base.zero(::Type{Polynomial{C,T,A}}) where {C,T,A} = Polynomial{C,T,A}(A())
Base.zero(t::Polynomial) = zero(typeof(t))

compare_monomials(a, b) = compare(monomial(a), monomial(b))
compare_monomials(a, b) = cmp(monomial(a), monomial(b))

function join_terms(
terms1::AbstractArray{<:Term},
Expand Down
30 changes: 0 additions & 30 deletions src/operators.jl
Original file line number Diff line number Diff line change
@@ -1,33 +1,3 @@
# We reverse the order of comparisons here so that the result
# of x < y is equal to the result of Monomial(x) < Monomial(y)
Base.@pure function Base.isless(v1::AbstractVariable, v2::AbstractVariable)
return name(v1) > name(v2)
end
function Base.isless(m1::AbstractTermLike, m2::AbstractTermLike)
return isless(promote(m1, m2)...)
end

# Implement this to make coefficients be compared with terms.
function isless_coefficient(a::Real, b::Real)
return a < b
end
function isless_coefficient(a::Number, b::Number)
return abs(a) < abs(b)
end
# By default, coefficients are not comparable so `a` is not strictly
# less than `b`, they are considered sort of equal.
isless_coefficient(a, b) = false

function Base.isless(t1::AbstractTerm, t2::AbstractTerm)
if monomial(t1) < monomial(t2)
return true
elseif monomial(t1) == monomial(t2)
return isless_coefficient(coefficient(t1), coefficient(t2))
else
return false
end
end

# promoting multiplication is not a good idea
# For example a polynomial of Float64 * a polynomial of JuMP affine expression
# is a polynomial of JuMP affine expression but if we promote it would be a
Expand Down
7 changes: 7 additions & 0 deletions src/promote.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
"""
promote_variables(p::AbstractPolynomialLike, q::AbstractPolynomialLike)

Return two polynomials over the same variables.
"""
function promote_variables end

# MonomialLike
Base.promote_rule(::Type{M}, ::Type{M}) where {M<:AbstractMonomialLike} = M
function Base.promote_rule(
Expand Down
34 changes: 12 additions & 22 deletions test/commutative/comparison.jl
Original file line number Diff line number Diff line change
Expand Up @@ -146,31 +146,21 @@
grlex = Graded{lex}
rinvlex = Reverse{InverseLexOrder}
grevlex = Graded{rinvlex}
@test MP.compare([1, 0, 1], [1, 1, 0], grlex) == -1
@test MP.compare([1, 1, 0], [1, 0, 1], grlex) == 1
Mod.@polyvar x y z
# [CLO13, p. 58]
@test MP.compare(1:3, [3, 2, 0], lex) < 0
@test MP.compare(1:3, [3, 2, 0], grlex) > 0
@test MP.compare(1:3, [3, 2, 0], rinvlex) < 0
@test MP.compare(1:3, [3, 2, 0], grevlex) > 0
@test MP.compare([1, 2, 4], [1, 1, 5], lex) > 0
@test MP.compare([1, 2, 4], [1, 1, 5], grlex) > 0
@test MP.compare([1, 2, 4], [1, 1, 5], rinvlex) > 0
@test MP.compare([1, 2, 4], [1, 1, 5], grevlex) > 0
@test MP.compare(x * y^2 * z^3, x^3 * y^2, lex) < 0
@test MP.compare(x * y^2 * z^3, x^3 * y^2, grlex) > 0
@test MP.compare(x * y^2 * z^3, x^3 * y^2, rinvlex) < 0
@test MP.compare(x * y^2 * z^3, x^3 * y^2, grevlex) > 0
@test MP.compare(x * y^2 * z^4, x * y * z^5, lex) > 0
@test MP.compare(x * y^2 * z^4, x * y * z^5, grlex) > 0
@test MP.compare(x * y^2 * z^4, x * y * z^5, rinvlex) > 0
@test MP.compare(x * y^2 * z^4, x * y * z^5, grevlex) > 0
@test compare(x * y^2 * z^3, x^3 * y^2, lex) < 0
@test compare(x * y^2 * z^3, x^3 * y^2, grlex) > 0
@test compare(x * y^2 * z^3, x^3 * y^2, rinvlex) < 0
@test compare(x * y^2 * z^3, x^3 * y^2, grevlex) > 0
@test compare(x * y^2 * z^4, x * y * z^5, lex) > 0
@test compare(x * y^2 * z^4, x * y * z^5, grlex) > 0
@test compare(x * y^2 * z^4, x * y * z^5, rinvlex) > 0
@test compare(x * y^2 * z^4, x * y * z^5, grevlex) > 0
# [CLO13, p. 59]
@test MP.compare(x^5 * y * z, x^4 * y * z^2, lex) > 0
@test MP.compare(x^5 * y * z, x^4 * y * z^2, grlex) > 0
@test MP.compare(x^5 * y * z, x^4 * y * z^2, rinvlex) > 0
@test MP.compare(x^5 * y * z, x^4 * y * z^2, grevlex) > 0
@test compare(x^5 * y * z, x^4 * y * z^2, lex) > 0
@test compare(x^5 * y * z, x^4 * y * z^2, grlex) > 0
@test compare(x^5 * y * z, x^4 * y * z^2, rinvlex) > 0
@test compare(x^5 * y * z, x^4 * y * z^2, grevlex) > 0
# [CLO13] Cox, D., Little, J., & OShea, D.
# *Ideals, varieties, and algorithms: an introduction to computational algebraic geometry and commutative algebra*.
# Springer Science & Business Media, **2013**.
Expand Down
Loading