-
Notifications
You must be signed in to change notification settings - Fork 68
Expand the common code for ideal implementations #2108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,14 +1,54 @@ | ||||||
############################################################################### | ||||||
# | ||||||
# Ideal constructor | ||||||
# Ideal.jl : Generic functionality for two-sided ideals | ||||||
# | ||||||
# | ||||||
# A the very least, an implementation of an Ideal subtype should provide the | ||||||
# following methods: | ||||||
# - ideal_type(::Type{MyRingType}) = MyIdealType | ||||||
# - ideal(R::MyRingType, xs::Vector{MyRingElemType})::MyIdealType | ||||||
# - base_ring(I::MyIdealType) | ||||||
# - gen(I::MyIdealType, k::Int) | ||||||
# - gens(I::MyIdealType) | ||||||
# - ngens(I::MyIdealType) | ||||||
# - Base.in(v::MyRingElemType, I::MyIdealType) | ||||||
# - ... | ||||||
# | ||||||
# Many other functions are then automatically derived from these. | ||||||
############################################################################### | ||||||
|
||||||
############################################################################### | ||||||
# | ||||||
# Type and parent functions | ||||||
# | ||||||
############################################################################### | ||||||
|
||||||
# fundamental interface, to be documented | ||||||
ideal_type(x) = ideal_type(typeof(x)) | ||||||
ideal_type(T::DataType) = throw(MethodError(ideal_type, (T,))) | ||||||
|
||||||
# | ||||||
parent(I::Ideal) = DefaultIdealSet(base_ring(I)) | ||||||
|
||||||
parent_type(::Type{<:Ideal{T}}) where {T} = DefaultIdealSet{T} | ||||||
|
||||||
# | ||||||
base_ring(S::DefaultIdealSet) = S.base_ring::base_ring_type(S) | ||||||
|
||||||
base_ring_type(::Type{<:IdealSet{T}}) where {T} = parent_type(T) | ||||||
|
||||||
elem_type(::Type{<:IdealSet{T}}) where {T} = ideal_type(parent_type(T)) | ||||||
|
||||||
############################################################################### | ||||||
# | ||||||
# Ideal constructors | ||||||
# | ||||||
############################################################################### | ||||||
|
||||||
# We assume that the function | ||||||
# ideal(R::T, xs::Vector{U}) | ||||||
# with U === elem_type(T) is implemented by anyone implementing ideals | ||||||
# for AbstractAlgebra rings. | ||||||
# The functions in this file extend the interface for `ideal`. | ||||||
# All constructors ultimately delegate to a method | ||||||
# ideal(R::T, xs::Vector{U}) where T <: NCRing | ||||||
# and U === elem_type(T) | ||||||
ideal(R::T, xs::Vector{S}) where {T <: NCRing, S <: NCRingElement} = ideal_type(T)(R, xs) | ||||||
|
||||||
# the following helper enables things like `ideal(R, [])` or `ideal(R, [1])` | ||||||
# the type check ensures we don't run into an infinite recursion | ||||||
|
@@ -21,6 +61,77 @@ function ideal(R::NCRing, x, y...; kw...) | |||||
return ideal(R, elem_type(R)[R(z) for z in [x, y...]]; kw...) | ||||||
end | ||||||
|
||||||
function ideal(x::NCRingElement; kw...) | ||||||
return ideal(parent(x), x; kw...) | ||||||
end | ||||||
|
||||||
function ideal(xs::AbstractVector{T}; kw...) where T<:NCRingElement | ||||||
@req !is_empty(xs) "Empty collection, cannot determine parent ring. Try ideal(ring, xs) instead of ideal(xs)" | ||||||
return ideal(parent(xs[1]), xs; kw...) | ||||||
end | ||||||
|
||||||
function Base.similar(I::T, xs::Vector) where {T <: Ideal} | ||||||
R = base_ring(I) | ||||||
@assert T === ideal_type(R) | ||||||
return ideal(R, xs) | ||||||
end | ||||||
|
||||||
############################################################################### | ||||||
# | ||||||
# Basic predicates | ||||||
# | ||||||
############################################################################### | ||||||
|
||||||
iszero(I::Ideal) = all(iszero, gens(I)) | ||||||
|
||||||
@doc raw""" | ||||||
Base.issubset(I::T, J::T) where {T <: Ideal} | ||||||
|
||||||
Return `true` if the ideal `I` is a subset of the ideal `J`. | ||||||
""" | ||||||
function Base.issubset(I::T, J::T) where {T <: Ideal} | ||||||
I === J && return true | ||||||
check_base_ring(I, J) | ||||||
return all(in(J), gens(I)) | ||||||
end | ||||||
|
||||||
############################################################################### | ||||||
# | ||||||
# Comparison | ||||||
# | ||||||
############################################################################### | ||||||
|
||||||
function Base.:(==)(I::T, J::T) where {T <: Ideal} | ||||||
return is_subset(I, J) && is_subset(J, I) | ||||||
end | ||||||
|
||||||
function Base.:hash(I::T, h::UInt) where {T <: Ideal} | ||||||
h = hash(base_ring(I), h) | ||||||
return h | ||||||
end | ||||||
|
||||||
############################################################################### | ||||||
# | ||||||
# Binary operations | ||||||
# | ||||||
############################################################################### | ||||||
|
||||||
function Base.:+(I::T, J::T) where {T <: Ideal} | ||||||
check_base_ring(I, J) | ||||||
return similar(I, vcat(gens(I), gens(J))) | ||||||
end | ||||||
|
||||||
function Base.:*(I::T, J::T) where {T <: Ideal} | ||||||
check_base_ring(I, J) | ||||||
return similar(I, [x*y for x in gens(I) for y in gens(J)]) | ||||||
end | ||||||
|
||||||
############################################################################### | ||||||
# | ||||||
# Ad hoc binary operations | ||||||
# | ||||||
############################################################################### | ||||||
|
||||||
function *(R::Ring, x::RingElement) | ||||||
return ideal(R, x) | ||||||
end | ||||||
|
@@ -29,19 +140,20 @@ function *(x::RingElement, R::Ring) | |||||
return ideal(R, x) | ||||||
end | ||||||
|
||||||
function ideal(x::NCRingElement; kw...) | ||||||
return ideal(parent(x), x; kw...) | ||||||
function *(I::Ideal{T}, p::T) where T <: RingElement | ||||||
iszero(p) && return similar(I, T[]) | ||||||
return similar(I, [v*p for v in gens(I)]) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. so here, if we assume
Suggested change
and indeed that's what I did before the second commit in this PR, and I'd be happy to back to it if we can agree on this scheme. |
||||||
end | ||||||
|
||||||
function ideal(xs::AbstractVector{T}; kw...) where T<:NCRingElement | ||||||
@req !is_empty(xs) "Empty collection, cannot determine parent ring. Try ideal(ring, xs) instead of ideal(xs)" | ||||||
return ideal(parent(xs[1]), xs; kw...) | ||||||
function *(p::T, I::Ideal{T}) where T <: RingElement | ||||||
return I*p | ||||||
end | ||||||
|
||||||
iszero(I::Ideal) = all(iszero, gens(I)) | ||||||
|
||||||
base_ring_type(::Type{<:IdealSet{T}}) where T <: RingElement = parent_type(T) | ||||||
function *(I::Ideal{T}, p::S) where {S <: RingElement, T <: RingElement} | ||||||
iszero(p*one(R)) && return similar(I, T[]) | ||||||
return similar(I, [v*p for v in gens(I)]) | ||||||
end | ||||||
|
||||||
# fundamental interface, to be documented | ||||||
ideal_type(x) = ideal_type(typeof(x)) | ||||||
ideal_type(T::DataType) = throw(MethodError(ideal_type, (T,))) | ||||||
function *(p::S, I::Ideal{T}) where {S <: RingElement, T <: RingElement} | ||||||
return I*p | ||||||
end |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is wrong for two-sided ideals of noncommutative rings.