Skip to content

Commit

Permalink
Proof-of-concept: _implements trait
Browse files Browse the repository at this point in the history
  • Loading branch information
fingolfin committed Jan 15, 2025
1 parent 1c605fb commit 4678b41
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/FreeAssociativeAlgebra.jl
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ function is_unit(a::FreeAssociativeAlgebraElem{T}) where T
end
end

_implements(::Type{FreeAssociativeAlgebraElem{T}}, f::typeof(is_unit)) where T = is_domain_type(T) || _implements_directly(T, f)

Check warning on line 138 in src/FreeAssociativeAlgebra.jl

View check run for this annotation

Codecov / codecov/patch

src/FreeAssociativeAlgebra.jl#L138

Added line #L138 was not covered by tests

###############################################################################
#
# Hashing
Expand Down
6 changes: 6 additions & 0 deletions src/MPoly.jl
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,8 @@ function is_unit(f::T) where {T <: MPolyRingElem}
return constant_term_is_unit
end

_implements(::Type{MPolyRingElem{T}}, ::typeof(is_unit)) where T = _implements(T, is_unit) && _implements(T, is_nilpotent)

Check warning on line 448 in src/MPoly.jl

View check run for this annotation

Codecov / codecov/patch

src/MPoly.jl#L448

Added line #L448 was not covered by tests

function content(a::MPolyRingElem{T}) where T <: RingElement
z = zero(coefficient_ring(a))
for c in coefficients(a)
Expand All @@ -459,12 +461,16 @@ function is_nilpotent(f::T) where {T <: MPolyRingElem}
return all(is_nilpotent, coefficients(f))
end

_implements(::Type{MPolyRingElem{T}}, ::typeof(is_nilpotent)) where T = _implements(T, is_nilpotent)

Check warning on line 464 in src/MPoly.jl

View check run for this annotation

Codecov / codecov/patch

src/MPoly.jl#L464

Added line #L464 was not covered by tests


function is_zero_divisor(x::MPolyRingElem{T}) where T <: RingElement
is_domain_type(T) && return is_zero(x)
return is_zero_divisor(content(x))
end

_implements(::Type{MPolyRingElem{T}}, ::typeof(is_zero_divisor)) where T = _implements(T, is_zero_divisor)

Check warning on line 472 in src/MPoly.jl

View check run for this annotation

Codecov / codecov/patch

src/MPoly.jl#L472

Added line #L472 was not covered by tests

function is_zero_divisor_with_annihilator(a::MPolyRingElem{T}) where T <: RingElement
f, b = is_zero_divisor_with_annihilator(content(a))
return f, parent(a)(b)
Expand Down
4 changes: 4 additions & 0 deletions src/NCPoly.jl
Original file line number Diff line number Diff line change
Expand Up @@ -814,3 +814,7 @@ function is_nilpotent(f::T) where {T <: PolynomialElem}
is_domain_type(T) && return is_zero(f)
return all(is_nilpotent, coefficients(f))
end

_implements(::Type{PolynomialElem{T}}, ::typeof(is_unit)) where T = _implements(T, is_unit) && _implements(T, is_nilpotent)

Check warning on line 818 in src/NCPoly.jl

View check run for this annotation

Codecov / codecov/patch

src/NCPoly.jl#L818

Added line #L818 was not covered by tests

_implements(::Type{PolynomialElem{T}}, ::typeof(is_nilpotent)) where T = _implements(T, is_nilpotent)

Check warning on line 820 in src/NCPoly.jl

View check run for this annotation

Codecov / codecov/patch

src/NCPoly.jl#L820

Added line #L820 was not covered by tests
2 changes: 2 additions & 0 deletions src/NCRings.jl
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ function is_nilpotent(a::T) where {T <: NCRingElement}
throw(NotImplementedError(:is_nilpotent, a))
end

_implements(::Type{T}, f::typeof(is_nilpotent)) where {T <: NCRingElement} = is_domain_type(T) || _implements_directly(T, f)

Check warning on line 178 in src/NCRings.jl

View check run for this annotation

Codecov / codecov/patch

src/NCRings.jl#L178

Added line #L178 was not covered by tests


###############################################################################
#
Expand Down
9 changes: 9 additions & 0 deletions src/algorithms/GenericFunctions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,8 @@ function is_zero_divisor(a::T) where T <: RingElement
return is_zero(a) && !is_zero(one(parent(a)))
end

_implements(::Type{T}, f::typeof(is_zero_divisor)) where {T} = is_domain_type(T) || _implements_directly(T, f)

Check warning on line 432 in src/algorithms/GenericFunctions.jl

View check run for this annotation

Codecov / codecov/patch

src/algorithms/GenericFunctions.jl#L432

Added line #L432 was not covered by tests

@doc raw"""
is_zero_divisor_with_annihilator(a::T) where T <: RingElement
Expand Down Expand Up @@ -456,6 +458,8 @@ function factor(a)
throw(NotImplementedError(:factor, a))
end

_implements(::Type{T}, f::typeof(factor)) where {T} = _implements_directly(T, f)

Check warning on line 461 in src/algorithms/GenericFunctions.jl

View check run for this annotation

Codecov / codecov/patch

src/algorithms/GenericFunctions.jl#L461

Added line #L461 was not covered by tests

@doc raw"""
factor_squarefree(a::T) where T <: RingElement -> Fac{T}
Expand All @@ -466,6 +470,8 @@ function factor_squarefree(a)
throw(NotImplementedError(:factor_squarefree, a))
end

_implements(::Type{T}, f::typeof(factor_squarefree)) where {T} = _implements_directly(T, f)

Check warning on line 473 in src/algorithms/GenericFunctions.jl

View check run for this annotation

Codecov / codecov/patch

src/algorithms/GenericFunctions.jl#L473

Added line #L473 was not covered by tests

@doc raw"""
is_irreducible(a::RingElement)
Expand All @@ -479,6 +485,8 @@ function is_irreducible(a)
return length(af) == 1 && all(isone, values(af.fac))
end

_implements(::Type{T}, ::typeof(is_irreducible)) where {T} = _implements(T, is_unit) && _implements(T, factor)

Check warning on line 488 in src/algorithms/GenericFunctions.jl

View check run for this annotation

Codecov / codecov/patch

src/algorithms/GenericFunctions.jl#L488

Added line #L488 was not covered by tests

@doc raw"""
is_squarefree(a::RingElement)
Expand All @@ -493,3 +501,4 @@ function is_squarefree(a)
return all(isone, values(af.fac))
end

_implements(::Type{T}, ::typeof(is_squarefree)) where {T} = _implements(T, is_unit) && _implements(T, factor_squarefree)

Check warning on line 504 in src/algorithms/GenericFunctions.jl

View check run for this annotation

Codecov / codecov/patch

src/algorithms/GenericFunctions.jl#L504

Added line #L504 was not covered by tests
4 changes: 4 additions & 0 deletions src/algorithms/LaurentPoly.jl
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ function is_nilpotent(f::T) where {T <: LaurentPolyRingElem}
return is_nilpotent(f.poly);
end

_implements(::Type{LaurentPolyRingElem{T}}, ::typeof(is_unit)) where T = _implements(T, is_unit) && _implements(T, is_nilpotent)

Check warning on line 162 in src/algorithms/LaurentPoly.jl

View check run for this annotation

Codecov / codecov/patch

src/algorithms/LaurentPoly.jl#L162

Added line #L162 was not covered by tests

_implements(::Type{LaurentPolyRingElem{T}}, ::typeof(is_nilpotent)) where T = _implements(T, is_nilpotent)

Check warning on line 164 in src/algorithms/LaurentPoly.jl

View check run for this annotation

Codecov / codecov/patch

src/algorithms/LaurentPoly.jl#L164

Added line #L164 was not covered by tests


###############################################################################
#
Expand Down
42 changes: 42 additions & 0 deletions src/fundamental_interface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -439,3 +439,45 @@ function _number_of_direct_product_factors end
Return the homomorphism from the domain `D` into the codomain `C` defined by the data.
"""
function hom end

###############################################################################
#
#
#
###############################################################################

# Calling `_implements(T, f)` checks whether a "sensible" method for the unary
# function `f` is implemented for inputs of type `T`. The argument order is
# meant to be similar to e.g. `isa`, and thus indicates `T implements f`.
#
# For example, `_implements(MyRingElem, is_unit)` should return true if
# invoking `is_unit` on elements of type `MyRingElem` is supported.
#
# The generic fallback uses `hasmethod`. However, this may return `true` in
# cases where it shouldn't, as we often provide generic methods for that rely
# on other methods being implemented -- either for the same type, or for types
# derived from it. For example the `is_nilpotent(::PolyElem{T})` method needs
# `is_nilpotent(::T)` in order to work.
#
# To reflect this, additional `_implements` methods need to be provided.
# We currently do this for at least the following functions:
# - factor
# - is_irreducible
# - is_nilpotent
# - is_squarefree
# - is_unit
# - is_zero_divisor
#
_implements(::Type{T}, f::Any) where {T} = hasmethod(f, Tuple{T})

Check warning on line 471 in src/fundamental_interface.jl

View check run for this annotation

Codecov / codecov/patch

src/fundamental_interface.jl#L471

Added line #L471 was not covered by tests

# helper for `_implements` which checks if `f` has a method explicitly for
# a concrete type `T` (i.e. not a generic method that can be specialized to `T`
# but really one that is implement for `T` and `T` only).
function _implements_directly(::Type{T}, f::Any) where {T}
isconcretetype(T) || return false # TODO: drop this?
meth = methods(f, Tuple{T})

Check warning on line 478 in src/fundamental_interface.jl

View check run for this annotation

Codecov / codecov/patch

src/fundamental_interface.jl#L476-L478

Added lines #L476 - L478 were not covered by tests
# TODO: deal with type parameters: if `T` is `FreeAssociativeAlgebraElem{ZZRingElem}`
# and `f` has a method for `FreeAssociativeAlgebraElem` then we should still consider
# this a match.
return any(m -> m.sig == Tuple{typeof(f), T}, meth)

Check warning on line 482 in src/fundamental_interface.jl

View check run for this annotation

Codecov / codecov/patch

src/fundamental_interface.jl#L482

Added line #L482 was not covered by tests
end
4 changes: 4 additions & 0 deletions src/generic/LaurentMPoly.jl
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ function is_nilpotent(f::T) where {T <: LaurentMPolyRingElem}
return is_nilpotent(f.mpoly);
end

_implements(::Type{LaurentMPolyRingElem{T}}, ::typeof(is_unit)) where T = _implements(T, is_unit) && _implements(T, is_nilpotent)

Check warning on line 133 in src/generic/LaurentMPoly.jl

View check run for this annotation

Codecov / codecov/patch

src/generic/LaurentMPoly.jl#L133

Added line #L133 was not covered by tests

_implements(::Type{LaurentMPolyRingElem{T}}, ::typeof(is_nilpotent)) where T = _implements(T, is_nilpotent)

Check warning on line 135 in src/generic/LaurentMPoly.jl

View check run for this annotation

Codecov / codecov/patch

src/generic/LaurentMPoly.jl#L135

Added line #L135 was not covered by tests


is_zero_divisor(p::LaurentMPolyWrap) = is_zero_divisor(p.mpoly)

Expand Down

0 comments on commit 4678b41

Please sign in to comment.