11# ##############################################################################
22#
3- # Ideal constructor
3+ # Ideal.jl : Generic functionality for two-sided ideals
4+ #
5+ #
6+ # A the very least, an implementation of an Ideal subtype should provide the
7+ # following methods:
8+ # - ideal_type(::Type{MyRingType}) = MyIdealType
9+ # - ideal(R::MyRingType, xs::Vector{MyRingElemType})::MyIdealType
10+ # - base_ring(I::MyIdealType)
11+ # - gen(I::MyIdealType, k::Int)
12+ # - gens(I::MyIdealType)
13+ # - ngens(I::MyIdealType)
14+ # - Base.in(v::MyRingElemType, I::MyIdealType)
15+ # - ...
16+ #
17+ # Many other functions are then automatically derived from these.
18+ # ##############################################################################
19+
20+ # ##############################################################################
21+ #
22+ # Type and parent functions
23+ #
24+ # ##############################################################################
25+
26+ # fundamental interface, to be documented
27+ ideal_type (x) = ideal_type (typeof (x))
28+ ideal_type (T:: DataType ) = throw (MethodError (ideal_type, (T,)))
29+
30+ #
31+ parent (I:: Ideal ) = DefaultIdealSet (base_ring (I))
32+
33+ parent_type (:: Type{<:Ideal{T}} ) where {T} = DefaultIdealSet{T}
34+
35+ #
36+ base_ring (S:: DefaultIdealSet ) = S. base_ring:: base_ring_type (S)
37+
38+ base_ring_type (:: Type{<:IdealSet{T}} ) where {T} = parent_type (T)
39+
40+ elem_type (:: Type{<:IdealSet{T}} ) where {T} = ideal_type (parent_type (T))
41+
42+ # ##############################################################################
43+ #
44+ # Ideal constructors
445#
546# ##############################################################################
647
7- # We assume that the function
8- # ideal(R::T, xs::Vector{U})
9- # with U === elem_type(T) is implemented by anyone implementing ideals
10- # for AbstractAlgebra rings.
11- # The functions in this file extend the interface for `ideal`.
48+ # All constructors ultimately delegate to a method
49+ # ideal(R::T, xs::Vector{U}) where T <: NCRing
50+ # and U === elem_type(T)
51+ ideal (R:: T , xs:: Vector{S} ) where {T <: NCRing , S <: NCRingElement } = ideal_type (T)(R, xs)
1252
1353# the following helper enables things like `ideal(R, [])` or `ideal(R, [1])`
1454# the type check ensures we don't run into an infinite recursion
@@ -21,6 +61,66 @@ function ideal(R::NCRing, x, y...; kw...)
2161 return ideal (R, elem_type (R)[R (z) for z in [x, y... ]]; kw... )
2262end
2363
64+ function ideal (x:: NCRingElement ; kw... )
65+ return ideal (parent (x), x; kw... )
66+ end
67+
68+ function ideal (xs:: AbstractVector{T} ; kw... ) where T<: NCRingElement
69+ @req ! is_empty (xs) " Empty collection, cannot determine parent ring. Try ideal(ring, xs) instead of ideal(xs)"
70+ return ideal (parent (xs[1 ]), xs; kw... )
71+ end
72+
73+ # ##############################################################################
74+ #
75+ # Basic predicates
76+ #
77+ # ##############################################################################
78+
79+ iszero (I:: Ideal ) = all (iszero, gens (I))
80+
81+ function is_subset (I:: T , J:: T ) where {T <: Ideal }
82+ I === J && return true
83+ check_base_ring (I, J)
84+ return all (x in J for x in gens (I))
85+ end
86+
87+ # ##############################################################################
88+ #
89+ # Comparison
90+ #
91+ # ##############################################################################
92+
93+ function Base.:(== )(I:: T , J:: T ) where {T <: Ideal }
94+ return is_subset (I, J) && is_subset (J, I)
95+ end
96+
97+ function Base.:hash (I:: T , h:: UInt ) where {T <: Ideal }
98+ h = hash (base_ring (I), h)
99+ return h
100+ end
101+
102+ # ##############################################################################
103+ #
104+ # Binary operations
105+ #
106+ # ##############################################################################
107+
108+ function Base.:+ (I:: T , J:: T ) where {T <: Ideal }
109+ check_base_ring (I, J)
110+ return ideal (base_ring (I), vcat (gens (I), gens (J)))
111+ end
112+
113+ function Base.:* (I:: T , J:: T ) where {T <: Ideal }
114+ check_base_ring (I, J)
115+ return ideal (base_ring (I), [x* y for x in gens (I) for y in gens (J)])
116+ end
117+
118+ # ##############################################################################
119+ #
120+ # Ad hoc binary operations
121+ #
122+ # ##############################################################################
123+
24124function * (R:: Ring , x:: RingElement )
25125 return ideal (R, x)
26126end
@@ -29,19 +129,22 @@ function *(x::RingElement, R::Ring)
29129 return ideal (R, x)
30130end
31131
32- function ideal (x:: NCRingElement ; kw... )
33- return ideal (parent (x), x; kw... )
132+ function * (I:: Ideal{T} , p:: T ) where T <: RingElement
133+ R = base_ring (I)
134+ iszero (p) && return ideal (R, T[])
135+ return ideal (R, [v* p for v in gens (I)])
34136end
35137
36- function ideal (xs:: AbstractVector{T} ; kw... ) where T<: NCRingElement
37- @req ! is_empty (xs) " Empty collection, cannot determine parent ring. Try ideal(ring, xs) instead of ideal(xs)"
38- return ideal (parent (xs[1 ]), xs; kw... )
138+ function * (p:: T , I:: Ideal{T} ) where T <: RingElement
139+ return I* p
39140end
40141
41- iszero (I:: Ideal ) = all (iszero, gens (I))
42-
43- base_ring_type (:: Type{<:IdealSet{T}} ) where T <: RingElement = parent_type (T)
142+ function * (I:: Ideal{T} , p:: S ) where {S <: RingElement , T <: RingElement }
143+ R = base_ring (I)
144+ iszero (p* one (R)) && return ideal (R, T[])
145+ return ideal (R, [v* p for v in gens (I)])
146+ end
44147
45- # fundamental interface, to be documented
46- ideal_type (x) = ideal_type ( typeof (x))
47- ideal_type (T :: DataType ) = throw ( MethodError (ideal_type, (T,)))
148+ function * (p :: S , I :: Ideal{T} ) where {S <: RingElement , T <: RingElement }
149+ return I * p
150+ end
0 commit comments