/
PBWAlgebraQuo.jl
316 lines (243 loc) · 10.4 KB
/
PBWAlgebraQuo.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
export PBWAlgQuo, PBWAlgQuoElem
# DEVELOPER DOC (code revised 2023-03-early)
# The revised code allows 2 slightly different implementations:
# (1) original impl where PBWAlgQuoElem is just a PBWAlgElem with a
# simple (almost transparent) wrapper -- all arithmetic is
# delegated to the PBWAlg (hence values are not automatic reduced
# after multiplication).
#
# (2) modified impl, currently just for the case of exterior algebra.
# Arithmetic is delegated to the Singular impl of exterior algebra
# (which does automatically reduced after multiplication). To
# achieve this a "new" pointer to the Singular ring is needed;
# this pointer is a new data field (sring) in PBQAlgQuo.
#
# To preserve the original behavior the new field "sdata" in PBWAlgQuo
# is set to the same value as the field "sdata" in PBWAlg (unless
# created by constructor for exterior_algebra.
#
# NOTE ABOUT PBWAlgQuoElem
# Values of type PBWAlgQuoElem are "wrapped" many times: the situation is
# an internal Singular value: a NC-polynomial & pointer to "quotient ring"
# (which contains the overlying PBWAlg in Singular
# & the reducing ideal)
# The NC-polynomial has a data repr which is compatible with the overlying
# Singular PBWAlg, so may be operated upon also by that ring (inside Singular).
# The Singular repr is then "wrapped" into an Oscar PBWAlgElem (which also
# contains a "parent" reference to the Oscar object representing the PBWAlg).
# This PBWAlgElem is "wrapped" once again into PBWAlgQuoElem (which also
# contains a "parent" reference to the Oscar object representing the PBWAlgQuo).
# EXERCISE: sit down and draw a box-and-arrow diagram of values and references!!
###### @attributes ### DID NOT WORK -- alternative solution found (via have_special_impl, see ExteriorAlgebra.jl)
mutable struct PBWAlgQuo{T, S} <: NCRing
I::PBWAlgIdeal{0, T, S}
sring::Singular.PluralRing{S} # For ExtAlg this is the Singular impl; o/w same as I.basering.sring
end
# For backward compatibility: ctor with 1 arg:
# uses "default" arith impl -- namely that from basering!
function PBWAlgQuo(I::PBWAlgIdeal{0, T, S}) where {T, S}
return PBWAlgQuo{T, S}(I, I.basering.sring)
end
function have_special_impl(Q::PBWAlgQuo)
return (Q.sring != Q.I.basering.sring)
end
mutable struct PBWAlgQuoElem{T, S} <: NCRingElem
parent::PBWAlgQuo{T, S}
data::PBWAlgElem{T, S}
end
function is_domain_type(::Type{U}) where {U <: PBWAlgQuoElem}
return false
end
function is_exact_type(a::Type{U}) where {T, U <: PBWAlgQuoElem{T}}
return is_exact_type(T)
end
elem_type(::Type{PBWAlgQuo{T, S}}) where {T, S} = PBWAlgQuoElem{T, S}
parent_type(::Type{PBWAlgQuoElem{T, S}}) where {T, S} = PBWAlgQuo{T, S}
parent(a::PBWAlgQuoElem) = a.parent
symbols(Q::PBWAlgQuo) = symbols(Q.I.basering) # EQUIV symbols(Q.sring) ???
coefficient_ring(Q::PBWAlgQuo) = coefficient_ring(Q.I.basering) # EQUIV coefficient_ring(Q.sring) ???
coefficient_ring(a::PBWAlgQuoElem) = coefficient_ring(parent(a))
modulus(Q::PBWAlgQuo) = Q.I
base_ring(Q::PBWAlgQuo) = Q.I.basering
base_ring(a::PBWAlgQuoElem) = base_ring(parent(a))
function Base.deepcopy_internal(a::PBWAlgQuoElem, dict::IdDict)
return PBWAlgQuoElem(parent(a), deepcopy_internal(a.data, dict))
end
function expressify(a::PBWAlgQuoElem; context = nothing)
return expressify(a.data; context=context)
end
@enable_all_show_via_expressify PBWAlgQuoElem
function expressify(Q::PBWAlgQuo; context = nothing) # what about new sring data-field ???
## special printing if Q is an exterior algebra
###### if get_attribute(Q, :is_exterior_algebra) === :true
if have_special_impl(Q)
a = Q.I.basering
x = symbols(a)
n = length(x)
return Expr(:sequence, Expr(:text, "Exterior algebra over "),
expressify(coefficient_ring(a); context=context),
Expr(:text, " in ("),
Expr(:series, x...),
Expr(:text, ")"))
end
# General case (not exterior algebra)
return Expr(:call, :/, expressify(Q.I.basering; context = nothing),
expressify(Q.I; context = nothing))
end
@enable_all_show_via_expressify PBWAlgQuo
####
function number_of_generators(Q::PBWAlgQuo)
return number_of_generators(base_ring(Q)) # EQUIV number_of_generators(Q.sring) ???
end
function gens(Q::PBWAlgQuo)
return elem_type(Q)[PBWAlgQuoElem(Q, PBWAlgElem(Q.I.basering,x)) for x in gens(Q.sring)]
end
function gen(Q::PBWAlgQuo, i::Int)
return PBWAlgQuoElem(Q, PBWAlgElem(Q.I.basering, gen(Q.sring, i)))
end
function zero(Q::PBWAlgQuo)
return PBWAlgQuoElem(Q, PBWAlgElem(Q.I.basering, zero(Q.sring)))
end
function one(Q::PBWAlgQuo)
return PBWAlgQuoElem(Q, PBWAlgElem(Q.I.basering, one(Q.sring)))
end
function simplify(a::PBWAlgQuoElem)
if have_special_impl(parent(a))
return a # short-cut for impls with reducing arithmetic (e.g. exterior algebras)
end
I = parent(a).I
groebner_assure!(I)
a.data.sdata = Singular.reduce(a.data.sdata, I.gb)
return a
end
function Base.hash(a::PBWAlgQuoElem, h::UInt)
simplify(a)
return hash(a.data, h)
end
function is_zero(a::PBWAlgQuoElem)
if !have_special_impl(parent(a)) # must reduce if not exterior algebras
simplify(a) # see GitHub discussion #2014 -- is_zero can modify repr of its arg!
end
return is_zero(a.data.sdata) # EQUIV is_zero(a.data)
end
function is_unit(a::PBWAlgQuoElem)
is_unit(a.data) && return true
is_zero(a.data) && return false
throw(NotImplementedError(:is_unit, a))
end
function Base.:(==)(a::PBWAlgQuoElem, b::PBWAlgQuoElem)
return is_zero(a - b)
end
function Base.:+(a::PBWAlgQuoElem, b::PBWAlgQuoElem)
@assert parent(a) == parent(b)
return PBWAlgQuoElem(parent(a), a.data + b.data)
end
function Base.:-(a::PBWAlgQuoElem, b::PBWAlgQuoElem)
@assert parent(a) == parent(b)
return PBWAlgQuoElem(parent(a), a.data - b.data)
end
function Base.:-(a::PBWAlgQuoElem)
return PBWAlgQuoElem(parent(a), -a.data)
end
function Base.:*(a::PBWAlgQuoElem, b::PBWAlgQuoElem)
return PBWAlgQuoElem(parent(a), a.data*b.data)
end
function Base.:^(a::PBWAlgQuoElem, b::Int)
return PBWAlgQuoElem(parent(a), a.data^b)
end
function divexact_left(a::PBWAlgQuoElem, b::PBWAlgQuoElem; check::Bool = true)
throw(NotImplementedError(:divexact_left, a, b))
end
function divexact_right(a::PBWAlgQuoElem, b::PBWAlgQuoElem; check::Bool = true)
throw(NotImplementedError(:divexact_right, a, b))
end
####
@doc raw"""
quo(A::PBWAlgRing, I::PBWAlgIdeal)
Given a two-sided ideal `I` of `A`, create the quotient algebra $A/I$ and
return the new algebra together with the quotient map $A\to A/I$.
# Examples
```jldoctest
julia> R, (x, y, z) = QQ["x", "y", "z"];
julia> L = [-x*y, -x*z, -y*z];
julia> REL = strictly_upper_triangular_matrix(L);
julia> A, (x, y, z) = pbw_algebra(R, REL, deglex(gens(R)))
(PBW-algebra over Rational field in x, y, z with relations y*x = -x*y, z*x = -x*z, z*y = -y*z, PBWAlgElem{QQFieldElem, Singular.n_Q}[x, y, z])
julia> I = two_sided_ideal(A, [x^2, y^2, z^2])
two_sided_ideal(x^2, y^2, z^2)
julia> Q, q = quo(A, I);
julia> Q
(PBW-algebra over Rational field in x, y, z with relations y*x = -x*y, z*x = -x*z, z*y = -y*z)/two_sided_ideal(x^2, y^2, z^2)
julia> q
Map defined by a julia-function with inverse
from pBW-algebra over Rational field in x, y, z with relations y*x = -x*y, z*x = -x*z, z*y = -y*z
to (PBW-algebra over Rational field in x, y, z with relations y*x = -x*y, z*x = -x*z, z*y = -y*z)/two_sided_ideal(x^2, y^2, z^2)
```
!!! note
The example above, shows one way of constructing the exterior algebra on the variables `x`, `y`, `z` over $\mathbb Q$.
For reasons of efficiency, it is recommended to use the built-in constructor `exterior_algebra` when working with
exterior algebras in OSCAR.
"""
function quo(Q::PBWAlgRing, I::PBWAlgIdeal; SpecialImpl::Union{Nothing, Singular.PluralRing} = nothing)
@assert (Q == base_ring(I));
### No idea how to check whether SpecialImpl is sane!
#??? Check if I is ideal of squares of gens then produce ExtAlg???
##??if isnothing(SpecialImpl) SpecialImpl = I.basering.sring; end;
if isnothing(SpecialImpl)
q = PBWAlgQuo(I)
else
q = PBWAlgQuo(I, SpecialImpl)
end
function im(a::PBWAlgElem)
@assert parent(a) == Q
return PBWAlgQuoElem(q, a)
end
function pr(a::PBWAlgQuoElem)
return a.data
end
return q, MapFromFunc(Q, q, im, pr)
end
# For some reason we need to specify a promote_rule when both types are the same (why?)
# Doc might be in packages/AbstractAlgebra/*/docs/src/ring_interface.md (near line 580)
function AbstractAlgebra.promote_rule(::Type{PBWAlgQuoElem{T, S}}, ::Type{PBWAlgQuoElem{T, S}}) where {T, S}
return PBWAlgQuoElem{T, S}
end
function AbstractAlgebra.promote_rule(::Type{PBWAlgQuoElem{T, S}}, ::Type{U}) where {T, S, U}
a = AbstractAlgebra.promote_rule(T, U)
return a == T ? PBWAlgQuoElem{T, S} : Union{}
end
function lift(a::PBWAlgQuoElem)
return a.data
end
function (Q::PBWAlgQuo)(a::PBWAlgElem)
return PBWAlgQuoElem(Q, base_ring(Q)(a))
end
function (Q::PBWAlgQuo)()
return PBWAlgQuoElem(Q, PBWAlgElem(base_ring(Q), Q.sring(0)))
end
function (Q::PBWAlgQuo{T, S})(c::T) where {T, S}
return PBWAlgQuoElem(Q, PBWAlgElem(base_ring(Q), Q.sring(c)))
end
function (Q::PBWAlgQuo)(c::IntegerUnion)
return PBWAlgQuoElem(Q, PBWAlgElem(base_ring(Q), Q.sring(c)))
end
function (Q::PBWAlgQuo)(a::PBWAlgQuoElem)
@req parent(a) == Q "coercion between different PBWAlg quotients not possible"
return a
end
#############################################
##### Exterior algebras
#############################################
#---------------------------------------------------------
# SEE FILE experimental/ExteriorAlgebra/ExteriorAlgebra.jl
#---------------------------------------------------------
# 2023-03-09 JAA commented out placeholder code below -- should be replaced by code from ExteriorAlgebra.jl
# @doc raw"""
# exterior_algebra(K::Ring, xs::AbstractVector{<:VarName})
# Given a field `K` and a vector `xs` of, say, $n$ Strings, Symbols, or Characters, return the $n$-th exterior algebra over `K`.
# The generators of the returned algebra print according to the entries of `xs`. See the example below.
# # Examples
# """
# function exterior_algebra(K::Ring, xs::AbstractVector{<:VarName})
# throw(NotImplementedError(:exterior_algebra, K, xs))
# end