Skip to content

Commit 4678b41

Browse files
committed
Proof-of-concept: _implements trait
1 parent 1c605fb commit 4678b41

File tree

8 files changed

+73
-0
lines changed

8 files changed

+73
-0
lines changed

src/FreeAssociativeAlgebra.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ function is_unit(a::FreeAssociativeAlgebraElem{T}) where T
135135
end
136136
end
137137

138+
_implements(::Type{FreeAssociativeAlgebraElem{T}}, f::typeof(is_unit)) where T = is_domain_type(T) || _implements_directly(T, f)
139+
138140
###############################################################################
139141
#
140142
# Hashing

src/MPoly.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,8 @@ function is_unit(f::T) where {T <: MPolyRingElem}
445445
return constant_term_is_unit
446446
end
447447

448+
_implements(::Type{MPolyRingElem{T}}, ::typeof(is_unit)) where T = _implements(T, is_unit) && _implements(T, is_nilpotent)
449+
448450
function content(a::MPolyRingElem{T}) where T <: RingElement
449451
z = zero(coefficient_ring(a))
450452
for c in coefficients(a)
@@ -459,12 +461,16 @@ function is_nilpotent(f::T) where {T <: MPolyRingElem}
459461
return all(is_nilpotent, coefficients(f))
460462
end
461463

464+
_implements(::Type{MPolyRingElem{T}}, ::typeof(is_nilpotent)) where T = _implements(T, is_nilpotent)
465+
462466

463467
function is_zero_divisor(x::MPolyRingElem{T}) where T <: RingElement
464468
is_domain_type(T) && return is_zero(x)
465469
return is_zero_divisor(content(x))
466470
end
467471

472+
_implements(::Type{MPolyRingElem{T}}, ::typeof(is_zero_divisor)) where T = _implements(T, is_zero_divisor)
473+
468474
function is_zero_divisor_with_annihilator(a::MPolyRingElem{T}) where T <: RingElement
469475
f, b = is_zero_divisor_with_annihilator(content(a))
470476
return f, parent(a)(b)

src/NCPoly.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -814,3 +814,7 @@ function is_nilpotent(f::T) where {T <: PolynomialElem}
814814
is_domain_type(T) && return is_zero(f)
815815
return all(is_nilpotent, coefficients(f))
816816
end
817+
818+
_implements(::Type{PolynomialElem{T}}, ::typeof(is_unit)) where T = _implements(T, is_unit) && _implements(T, is_nilpotent)
819+
820+
_implements(::Type{PolynomialElem{T}}, ::typeof(is_nilpotent)) where T = _implements(T, is_nilpotent)

src/NCRings.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,8 @@ function is_nilpotent(a::T) where {T <: NCRingElement}
175175
throw(NotImplementedError(:is_nilpotent, a))
176176
end
177177

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

179181
###############################################################################
180182
#

src/algorithms/GenericFunctions.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,8 @@ function is_zero_divisor(a::T) where T <: RingElement
429429
return is_zero(a) && !is_zero(one(parent(a)))
430430
end
431431

432+
_implements(::Type{T}, f::typeof(is_zero_divisor)) where {T} = is_domain_type(T) || _implements_directly(T, f)
433+
432434
@doc raw"""
433435
is_zero_divisor_with_annihilator(a::T) where T <: RingElement
434436
@@ -456,6 +458,8 @@ function factor(a)
456458
throw(NotImplementedError(:factor, a))
457459
end
458460

461+
_implements(::Type{T}, f::typeof(factor)) where {T} = _implements_directly(T, f)
462+
459463
@doc raw"""
460464
factor_squarefree(a::T) where T <: RingElement -> Fac{T}
461465
@@ -466,6 +470,8 @@ function factor_squarefree(a)
466470
throw(NotImplementedError(:factor_squarefree, a))
467471
end
468472

473+
_implements(::Type{T}, f::typeof(factor_squarefree)) where {T} = _implements_directly(T, f)
474+
469475
@doc raw"""
470476
is_irreducible(a::RingElement)
471477
@@ -479,6 +485,8 @@ function is_irreducible(a)
479485
return length(af) == 1 && all(isone, values(af.fac))
480486
end
481487

488+
_implements(::Type{T}, ::typeof(is_irreducible)) where {T} = _implements(T, is_unit) && _implements(T, factor)
489+
482490
@doc raw"""
483491
is_squarefree(a::RingElement)
484492
@@ -493,3 +501,4 @@ function is_squarefree(a)
493501
return all(isone, values(af.fac))
494502
end
495503

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

src/algorithms/LaurentPoly.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,10 @@ function is_nilpotent(f::T) where {T <: LaurentPolyRingElem}
159159
return is_nilpotent(f.poly);
160160
end
161161

162+
_implements(::Type{LaurentPolyRingElem{T}}, ::typeof(is_unit)) where T = _implements(T, is_unit) && _implements(T, is_nilpotent)
163+
164+
_implements(::Type{LaurentPolyRingElem{T}}, ::typeof(is_nilpotent)) where T = _implements(T, is_nilpotent)
165+
162166

163167
###############################################################################
164168
#

src/fundamental_interface.jl

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,3 +439,45 @@ function _number_of_direct_product_factors end
439439
Return the homomorphism from the domain `D` into the codomain `C` defined by the data.
440440
"""
441441
function hom end
442+
443+
###############################################################################
444+
#
445+
#
446+
#
447+
###############################################################################
448+
449+
# Calling `_implements(T, f)` checks whether a "sensible" method for the unary
450+
# function `f` is implemented for inputs of type `T`. The argument order is
451+
# meant to be similar to e.g. `isa`, and thus indicates `T implements f`.
452+
#
453+
# For example, `_implements(MyRingElem, is_unit)` should return true if
454+
# invoking `is_unit` on elements of type `MyRingElem` is supported.
455+
#
456+
# The generic fallback uses `hasmethod`. However, this may return `true` in
457+
# cases where it shouldn't, as we often provide generic methods for that rely
458+
# on other methods being implemented -- either for the same type, or for types
459+
# derived from it. For example the `is_nilpotent(::PolyElem{T})` method needs
460+
# `is_nilpotent(::T)` in order to work.
461+
#
462+
# To reflect this, additional `_implements` methods need to be provided.
463+
# We currently do this for at least the following functions:
464+
# - factor
465+
# - is_irreducible
466+
# - is_nilpotent
467+
# - is_squarefree
468+
# - is_unit
469+
# - is_zero_divisor
470+
#
471+
_implements(::Type{T}, f::Any) where {T} = hasmethod(f, Tuple{T})
472+
473+
# helper for `_implements` which checks if `f` has a method explicitly for
474+
# a concrete type `T` (i.e. not a generic method that can be specialized to `T`
475+
# but really one that is implement for `T` and `T` only).
476+
function _implements_directly(::Type{T}, f::Any) where {T}
477+
isconcretetype(T) || return false # TODO: drop this?
478+
meth = methods(f, Tuple{T})
479+
# TODO: deal with type parameters: if `T` is `FreeAssociativeAlgebraElem{ZZRingElem}`
480+
# and `f` has a method for `FreeAssociativeAlgebraElem` then we should still consider
481+
# this a match.
482+
return any(m -> m.sig == Tuple{typeof(f), T}, meth)
483+
end

src/generic/LaurentMPoly.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ function is_nilpotent(f::T) where {T <: LaurentMPolyRingElem}
130130
return is_nilpotent(f.mpoly);
131131
end
132132

133+
_implements(::Type{LaurentMPolyRingElem{T}}, ::typeof(is_unit)) where T = _implements(T, is_unit) && _implements(T, is_nilpotent)
134+
135+
_implements(::Type{LaurentMPolyRingElem{T}}, ::typeof(is_nilpotent)) where T = _implements(T, is_nilpotent)
136+
133137

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

0 commit comments

Comments
 (0)