diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index dda85132dc7..88046a341a7 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -2776,6 +2776,78 @@ def __richcmp__(self, other, op): # remaining case < return contained and not contains + def __mul__(self, other): + """ + Return the product of ``self`` with ``other``. + + .. WARNING:: + + If ``self`` is a right ideal and ``other`` is a left ideal, + this returns a submodule rather than an ideal. + + EXAMPLES:: + + sage: E. = ExteriorAlgebra(QQ) + + sage: I = E.ideal([a + 1], side="left") + sage: J = I * I; J + Left Ideal (2*a + 1, a, b, c, d, a*b, a*c, a*d, 2*a*b*c + b*c, 2*a*b*d + b*d, + 2*a*c*d + c*d, a*b*c, a*b*d, a*c*d, b*c*d, a*b*c*d) + of The exterior algebra of rank 4 over Rational Field + sage: J.groebner_basis() + (1,) + sage: I.gen(0)^2 + 2*a + 1 + + sage: J = E.ideal([b+c]) + sage: I * J + Twosided Ideal (a*b + a*c + b + c) of The exterior algebra of rank 4 over Rational Field + sage: J * I + Left Ideal (-a*b - a*c + b + c) of The exterior algebra of rank 4 over Rational Field + + sage: K = J * I + sage: K + Left Ideal (-a*b - a*c + b + c) of The exterior algebra of rank 4 over Rational Field + sage: E.ideal([J.gen(0) * d * I.gen(0)], side="left") <= K + True + + sage: J = E.ideal([b + c*d], side="right") + sage: I * J + Twosided Ideal (a*c*d + a*b + c*d + b) of The exterior algebra of rank 4 over Rational Field + sage: X = J * I; X + Free module generated by {0, 1, 2, 3, 4, 5, 6, 7} over Rational Field + sage: [X.lift(b) for b in X.basis()] + [c*d + b, -a*c*d + a*b, b*c, b*d, a*b*c, a*b*d, b*c*d, a*b*c*d] + sage: p = X.lift(X.basis()[0]) + sage: p + c*d + b + sage: a * p # not a left ideal + a*c*d + a*b + + sage: I = E.ideal([a + 1], side="right") + sage: E.ideal([1]) * I + Twosided Ideal (a + 1) of The exterior algebra of rank 4 over Rational Field + sage: I * E.ideal([1]) + Right Ideal (a + 1) of The exterior algebra of rank 4 over Rational Field + """ + if not isinstance(other, ExteriorAlgebraIdeal) or self.ring() != other.ring(): + return super().__mul__(other) + + if self._homogeneous or other._homogeneous or (self.side() == "left" and other.side() == "right"): + gens = (x * y for x in self.gens() for y in other.gens()) + else: + gens = (x * t * y for t in self.ring().basis() for x in self.gens() for y in other.gens()) + gens = [z for z in gens if z] + + if self.side() == "right" and other.side() == "left": + return self.ring().submodule(gens) + + if self.side() == "left" or self.side() == "twosided": + if other.side() == "right" or other.side() == "twosided": + return self.ring().ideal(gens, side="twosided") + return self.ring().ideal(gens, side="left") + return self.ring().ideal(gens, side="right") + def groebner_basis(self, term_order="neglex"): r""" Return the reduced Gröbner basis of ``self``.