Skip to content

Commit

Permalink
Trac #34818: Error when defining differentials over GCA's with relati…
Browse files Browse the repository at this point in the history
…ons.

The following code

{{{
sage: A.<a,b,x,u> = GradedCommutativeAlgebra(QQ,degrees=(2,2,3,3))
sage: A = A.quotient(A.ideal([a*u,b*u,x*u]))
sage: A.cdg_algebra({a:u,x:a*b})
}}}

Produces an error

{{{
...

File ~/sage/src/sage/algebras/commutative_dga.py:253, in
Differential.__init__(self, A, im_gens)
    251 for i in A.gens():
    252     if not self(self(i)).is_zero():
--> 253         raise ValueError("The given dictionary does not
determine a valid differential")

ValueError: The given dictionary does not determine a valid differential

}}}

which is wrong, because the differential is valid in the quotient
algebra.

It seems that the computations for the differential are done in the free
algebra instead of the quotient one.

URL: https://trac.sagemath.org/34818
Reported by: mmarco
Ticket author(s): Miguel Marco
Reviewer(s): Travis Scrimshaw
  • Loading branch information
Release Manager committed Jan 2, 2023
2 parents bb63c58 + 8ba265b commit 9a7b631
Showing 1 changed file with 71 additions and 51 deletions.
122 changes: 71 additions & 51 deletions src/sage/algebras/commutative_dga.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,44 +175,64 @@ def __classcall__(cls, A, im_gens):
sage: d2 = A.cdg_algebra({x: x*y, z: t, y: -x*y, t: 0}).differential()
sage: d1 is d2
True
Check that :trac:`34818` is solved::
sage: A.<a,b,x,u> = GradedCommutativeAlgebra(QQ,degrees=(2,2,3,3))
sage: A = A.quotient(A.ideal([a*u,b*u,x*u]))
sage: A.cdg_algebra({x:a*b,a:u})
Commutative Differential Graded Algebra with generators ('a', 'b', 'x', 'u') in degrees (2, 2, 3, 3) with relations [a*u, b*u, x*u] over Rational Field with differential:
a --> u
b --> 0
x --> a*b
u --> 0
sage: A.cdg_algebra({x:a*b,a:u,u:a^2})
Traceback (most recent call last):
...
ValueError: the differential does not preserve the ideal
"""
if isinstance(im_gens, (list, tuple)):
im_gens = {A.gen(i): x for i, x in enumerate(im_gens)}
im_gens = {A.gen(i): A(x) for i, x in enumerate(im_gens)}
else:
im_gens = {A(a): A(im_gens[a]) for a in im_gens}

R = A.cover_ring()
I = A.defining_ideal()
if A.base_ring().characteristic() != 2:
squares = R.ideal([R.gen(i)**2 for i, d in enumerate(A._degrees)
if is_odd(d)], side='twosided')
else:
squares = R.ideal(0, side='twosided')

if I != squares:
A_free = GCAlgebra(A.base(), names=A._names, degrees=A._degrees)
free_diff = {A_free(a): A_free(im_gens[a]) for a in im_gens}
B = A_free.cdg_algebra(free_diff)
IB = B.ideal([B(g) for g in I.gens()])
BQ = GCAlgebra.quotient(B, IB)
# We check that the differential respects the
# relations in the quotient method, but we also have
# to check this here, in case a GCAlgebra with
# relations is defined first, and then a differential
# imposed on it.
for g in IB.gens():
if not BQ(g.differential()).is_zero():
raise ValueError("The differential does not preserve the ideal")

im_gens = {A(a): A(im_gens[a]) for a in im_gens}

def image_monomial(exponent):
i = 0
cexp = list(exponent)
ell = len(cexp)
while i < ell:
if not cexp[i]:
i +=1
continue
a = A.gen(i)
try:
da = im_gens[a]
except KeyError:
da = A.zero()
cexp[i] -= 1
b = A.prod(A.gen(j) ** cexp[j] for j in range(len(cexp)))
db = image_monomial(cexp)
im = da * b + (-1)**A._degrees[i] * a * db
return A(im)
return A.zero()

for g in I.gens():
d = g.dict()
res = A.sum(d[ex] * image_monomial(ex) for ex in d)
if not res.is_zero():
raise ValueError("the differential does not preserve the ideal")

for i in im_gens:
x = im_gens[i]
if (not x.is_zero()
and (not x.is_homogeneous()
or total_degree(x.degree())
!= total_degree(i.degree()) + 1)):
raise ValueError("The given dictionary does not determine a degree 1 map")
raise ValueError("the given dictionary does not determine a degree 1 map")

im_gens = tuple(im_gens.get(x, A.zero()) for x in A.gens())
im_gens = tuple([im_gens.get(x, A.zero()) for x in A.gens()])
return super().__classcall__(cls, A, im_gens)

def __init__(self, A, im_gens):
Expand Down Expand Up @@ -245,14 +265,14 @@ def __init__(self, A, im_gens):
sage: A.cdg_algebra({a:b, b:c})
Traceback (most recent call last):
...
ValueError: The given dictionary does not determine a valid differential
ValueError: the given dictionary does not determine a valid differential
"""
self._dic_ = {A.gen(i): x for i, x in enumerate(im_gens)}
Morphism.__init__(self, Hom(A, A, category=Modules(A.base_ring())))

for i in A.gens():
if not self(self(i)).is_zero():
raise ValueError("The given dictionary does not determine a valid differential")
raise ValueError("the given dictionary does not determine a valid differential")

def _call_(self, x):
r"""
Expand Down Expand Up @@ -602,7 +622,7 @@ def __init__(self, A, im_gens):
if y != 0:
diff_deg.append(y.degree() - x.degree())
if len(set(diff_deg)) > 1:
raise ValueError("The differential does not have a well-defined degree")
raise ValueError("the differential does not have a well-defined degree")
self._degree_of_differential = diff_deg[0]

@cached_method
Expand Down Expand Up @@ -943,7 +963,7 @@ def __classcall__(cls, base, names=None, degrees=None, R=None, I=None, category=
"""
if names is None:
if degrees is None:
raise ValueError("You must specify names or degrees")
raise ValueError("you must specify names or degrees")
else:
n = len(degrees)
names = tuple('x{}'.format(i) for i in range(n))
Expand Down Expand Up @@ -1198,7 +1218,7 @@ def quotient(self, I, check=True):
[x^2*z, y^2*z, z*t]
"""
if check and any(not i.is_homogeneous() for i in I.gens()):
raise ValueError("The ideal must be homogeneous")
raise ValueError("the ideal must be homogeneous")
NCR = self.cover_ring()
gens1 = list(self.defining_ideal().gens())
gens2 = [i.lift() for i in I.gens()]
Expand Down Expand Up @@ -1441,10 +1461,10 @@ def degree(self, total=False):
sage: A(0).degree()
Traceback (most recent call last):
...
ValueError: The zero element does not have a well-defined degree
ValueError: the zero element does not have a well-defined degree
"""
if self.is_zero():
raise ValueError("The zero element does not have a well-defined degree")
raise ValueError("the zero element does not have a well-defined degree")
exps = self.lift().dict().keys()
degrees = self.parent()._degrees
n = self.parent().ngens()
Expand Down Expand Up @@ -1575,7 +1595,7 @@ def basis_coefficients(self, total=False):
sage: (t + x).basis_coefficients()
Traceback (most recent call last):
...
ValueError: This element is not homogeneous
ValueError: this element is not homogeneous
sage: B.<c,d> = GradedCommutativeAlgebra(QQ, degrees=((2,0), (0,4)))
sage: B.basis(4)
Expand All @@ -1585,10 +1605,10 @@ def basis_coefficients(self, total=False):
sage: (c^2 - 1/2 * d).basis_coefficients()
Traceback (most recent call last):
...
ValueError: This element is not homogeneous
ValueError: this element is not homogeneous
"""
if not self.is_homogeneous(total):
raise ValueError('This element is not homogeneous')
raise ValueError('this element is not homogeneous')

basis = self.parent().basis(self.degree(total))
lift = self.lift()
Expand Down Expand Up @@ -1720,7 +1740,7 @@ def quotient(self, I, check=True):
[x^2*z, y^2*z, z*t]
"""
if check and any(not i.is_homogeneous() for i in I.gens()):
raise ValueError("The ideal must be homogeneous")
raise ValueError("the ideal must be homogeneous")
NCR = self.cover_ring()
gens1 = list(self.defining_ideal().gens())
gens2 = [i.lift() for i in I.gens()]
Expand Down Expand Up @@ -1874,26 +1894,26 @@ def degree(self, total=False):
sage: (a**2*b + c).degree()
Traceback (most recent call last):
...
ValueError: This element is not homogeneous
ValueError: this element is not homogeneous
sage: (a**2*b + c).degree(total=True)
3
sage: A(0).degree()
Traceback (most recent call last):
...
ValueError: The zero element does not have a well-defined degree
ValueError: the zero element does not have a well-defined degree
"""
if total:
return GCAlgebra.Element.degree(self)
if self.is_zero():
raise ValueError("The zero element does not have a well-defined degree")
raise ValueError("the zero element does not have a well-defined degree")
degrees = self.parent()._degrees_multi
n = self.parent().ngens()
exps = self.lift().dict().keys()
l = [sum(exp[i] * degrees[i] for i in range(n)) for exp in exps]
if len(set(l)) == 1:
return l[0]
else:
raise ValueError('This element is not homogeneous')
raise ValueError('this element is not homogeneous')


###########################################################
Expand Down Expand Up @@ -1989,15 +2009,15 @@ def __init__(self, A, differential):
sage: A.cdg_algebra({a: a*b*c})
Traceback (most recent call last):
...
ValueError: The given dictionary does not determine a degree 1 map
ValueError: the given dictionary does not determine a degree 1 map
The differential composed with itself must be zero::
sage: A.<a,b,c> = GradedCommutativeAlgebra(QQ, degrees=(1,2,3))
sage: A.cdg_algebra({a:b, b:c})
Traceback (most recent call last):
...
ValueError: The given dictionary does not determine a valid differential
ValueError: the given dictionary does not determine a valid differential
"""
cat = Algebras(A.base()).Graded() & ChainComplexes(A.base())
GCAlgebra.__init__(self, A.base(), names=A._names,
Expand Down Expand Up @@ -2125,17 +2145,17 @@ def quotient(self, I, check=True):
sage: B.quotient(B.ideal(y*x))
Traceback (most recent call last):
...
ValueError: The differential does not preserve the ideal
ValueError: the differential does not preserve the ideal
sage: B.quotient(B.ideal(x))
Traceback (most recent call last):
...
ValueError: The differential does not preserve the ideal
ValueError: the differential does not preserve the ideal
"""
J = self.ideal(I)
AQ = GCAlgebra.quotient(self, J, check)
for g in I.gens():
if not AQ(g.differential()).is_zero():
raise ValueError("The differential does not preserve the ideal")
raise ValueError("the differential does not preserve the ideal")
dic = {AQ(a): AQ(a.differential()) for a in self.gens()}
return AQ.cdg_algebra(dic)

Expand Down Expand Up @@ -2920,10 +2940,10 @@ def is_coboundary(self):
sage: (x*z+y**2).is_coboundary()
Traceback (most recent call last):
...
ValueError: This element is not homogeneous
ValueError: this element is not homogeneous
"""
if not self.is_homogeneous():
raise ValueError('This element is not homogeneous')
raise ValueError('this element is not homogeneous')
# To avoid taking the degree of 0, we special-case it.
if self.is_zero():
return True
Expand Down Expand Up @@ -2966,7 +2986,7 @@ def is_cohomologous_to(self, other):
return self.is_coboundary()
if (not isinstance(other, DifferentialGCAlgebra.Element)
or self.parent() is not other.parent()):
raise ValueError('The element {} does not lie in this DGA'
raise ValueError('the element {} does not lie in this DGA'
.format(other))
if (self - other).is_homogeneous():
return (self - other).is_coboundary()
Expand Down Expand Up @@ -3110,7 +3130,7 @@ def __init__(self, A, differential):
sage: B = A.cdg_algebra(differential={x:y, t:z}) # bad
Traceback (most recent call last):
...
ValueError: The differential does not have a well-defined degree
ValueError: the differential does not have a well-defined degree
"""
cat = Algebras(A.base()).Graded() & ChainComplexes(A.base())
GCAlgebra_multigraded.__init__(self, A.base(), names=A._names,
Expand Down Expand Up @@ -3463,7 +3483,7 @@ def GradedCommutativeAlgebra(ring, names=None, degrees=None, max_degree=None,
sage: GradedCommutativeAlgebra(QQ)
Traceback (most recent call last):
...
ValueError: You must specify names or degrees
ValueError: you must specify names or degrees
"""
if max_degree:
from .finite_gca import FiniteGCAlgebra
Expand Down

0 comments on commit 9a7b631

Please sign in to comment.