def __add__(self, other): """ Return the sum of two subgroups. EXAMPLES:: sage: C = J0(22).cuspidal_subgroup() sage: C.gens() [[(1/5, 1/5, 4/5, 0)], [(0, 0, 0, 1/5)]] sage: A = C.subgroup([C.0]); B = C.subgroup([C.1]) sage: A + B == C True An example where the parent abelian varieties are different:: A = J0(48); A[0].cuspidal_subgroup() + A[1].cuspidal_subgroup() Finite subgroup with invariants [2, 4, 4] over QQ of Abelian subvariety of dimension 2 of J0(48) """ if not isinstance(other, FiniteSubgroup): raise TypeError("only addition of two finite subgroups is defined") A = self.abelian_variety() B = other.abelian_variety() if not A.in_same_ambient_variety(B): raise ValueError("self and other must be in the same ambient Jacobian") K = coercion_model.common_parent(self.field_of_definition(), other.field_of_definition()) lattice = self.lattice() + other.lattice() if A != B: C = A + B lattice += C.lattice() return FiniteSubgroup_lattice(C, lattice, field_of_definition=K) else: return FiniteSubgroup_lattice(self.abelian_variety(), lattice, field_of_definition=K)
def __add__(self, other): """ Return the sum of two subgroups. EXAMPLES:: sage: C = J0(22).cuspidal_subgroup() sage: C.gens() [[(1/5, 1/5, 4/5, 0)], [(0, 0, 0, 1/5)]] sage: A = C.subgroup([C.0]); B = C.subgroup([C.1]) sage: A + B == C True """ if not isinstance(other, FiniteSubgroup): raise TypeError("only addition of two finite subgroups is defined") A = self.abelian_variety() B = other.abelian_variety() if not A.in_same_ambient_variety(B): raise ValueError("self and other must be in the same ambient Jacobian") K = coercion_model.common_parent(self.field_of_definition(), other.field_of_definition()) lattice = self.lattice() + other.lattice() if A != B: lattice += C.lattice() return FiniteSubgroup_lattice(self.abelian_variety(), lattice, field_of_definition=K)
def __add__(self, other): """ Return the sum of two subgroups. EXAMPLES:: sage: C = J0(22).cuspidal_subgroup() sage: C.gens() [[(1/5, 1/5, 4/5, 0)], [(0, 0, 0, 1/5)]] sage: A = C.subgroup([C.0]); B = C.subgroup([C.1]) sage: A + B == C True """ if not isinstance(other, FiniteSubgroup): raise TypeError("only addition of two finite subgroups is defined") A = self.abelian_variety() B = other.abelian_variety() if not A.in_same_ambient_variety(B): raise ValueError( "self and other must be in the same ambient Jacobian") K = coercion_model.common_parent(self.field_of_definition(), other.field_of_definition()) lattice = self.lattice() + other.lattice() if A != B: lattice += C.lattice() return FiniteSubgroup_lattice(self.abelian_variety(), lattice, field_of_definition=K)
def cup_product(self, cochain): """ Return the cup product with another cochain INPUT: - ``cochain`` -- cochain over the same cell complex EXAMPLES:: sage: T2 = simplicial_complexes.Torus() sage: C1 = T2.n_chains(1, base_ring=ZZ, cochains=True) sage: def l(i, j): ....: return C1(Simplex([i, j])) sage: l1 = l(1, 3) + l(1, 4) + l(1, 6) + l(2, 4) - l(4, 5) + l(5, 6) sage: l2 = l(1, 6) - l(2, 3) - l(2, 5) + l(3, 6) - l(4, 5) + l(5, 6) The two one-cocycles are cohomology generators:: sage: l1.is_cocycle(), l1.is_coboundary() (True, False) sage: l2.is_cocycle(), l2.is_coboundary() (True, False) Their cup product is a two-cocycle that is again non-trivial in cohomology:: sage: l12 = l1.cup_product(l2) sage: l12 \chi_(1, 3, 6) - \chi_(2, 4, 5) - \chi_(4, 5, 6) sage: l1.parent().degree(), l2.parent().degree(), l12.parent().degree() (1, 1, 2) sage: l12.is_cocycle(), l12.is_coboundary() (True, False) """ if not isinstance(cochain.parent(), Cochains): raise ValueError('argument must be a cochain') if cochain.parent().cell_complex() != self.parent().cell_complex(): raise ValueError('cochain must be over the same cell complex') left_deg = self.parent().degree() right_deg = cochain.parent().degree() left_chains = self.parent().dual() right_chains = cochain.parent().dual() base_ring = coercion_model.common_parent(left_chains.base_ring(), right_chains.base_ring()) cx = self.parent().cell_complex() codomain = cx.n_chains(left_deg + right_deg, base_ring=base_ring, cochains=True) accumulator = codomain.zero() for cell in codomain.indices(): for (coeff, left_cell, right_cell) in cx.alexander_whitney(cell, left_deg): if not coeff: continue left = left_chains(left_cell) right = right_chains(right_cell) accumulator += codomain(cell) * coeff * self.eval( left) * cochain.eval(right) return accumulator
def extend_scalars(self, *pts): r""" Extend the ground field so that the new field contains pts. """ Dops = self.parent() Pols = Dops.base_ring() Scalars = Pols.base_ring() if all(Scalars.has_coerce_map_from(pt.parent()) for pt in pts): return (self, ) + pts gen = Scalars.gen() try: # Largely redundant with the other branch, but may do a better job # in some cases, e.g. pushout(QQ, QQ(α)), where as_enf_elts() would # invent new generator names. NF0 = coercion_model.common_parent(Scalars, *pts) if not is_NumberField(NF0): raise CoercionException NF, hom = utilities.good_number_field(NF0) gen1 = hom(NF0.coerce(gen)) pts1 = tuple(hom(NF0.coerce(pt)) for pt in pts) except (CoercionException, TypeError): NF, val1 = as_embedded_number_field_elements((gen, ) + pts) gen1, pts1 = val1[0], tuple(val1[1:]) hom = Scalars.hom([gen1], codomain=NF) Dops1 = OreAlgebra(Pols.change_ring(NF), (Dops.variable_name(), {}, { Pols.gen(): Pols.one() })) dop1 = Dops1([pol.map_coefficients(hom) for pol in self]) dop1 = PlainDifferentialOperator(dop1) assert dop1.base_ring().base_ring() is NF return (dop1, ) + pts1
def cup_product(self, cochain): """ Return the cup product with another cochain INPUT: - ``cochain`` -- cochain over the same cell complex EXAMPLES:: sage: T2 = simplicial_complexes.Torus() sage: C1 = T2.n_chains(1, base_ring=ZZ, cochains=True) sage: def l(i, j): ....: return C1(Simplex([i, j])) sage: l1 = l(1, 3) + l(1, 4) + l(1, 6) + l(2, 4) - l(4, 5) + l(5, 6) sage: l2 = l(1, 6) - l(2, 3) - l(2, 5) + l(3, 6) - l(4, 5) + l(5, 6) The two one-cocycles are cohomology generators:: sage: l1.is_cocycle(), l1.is_coboundary() (True, False) sage: l2.is_cocycle(), l2.is_coboundary() (True, False) Their cup product is a two-cocycle that is again non-trivial in cohomology:: sage: l12 = l1.cup_product(l2) sage: l12 \chi_(1, 3, 6) - \chi_(2, 4, 5) - \chi_(4, 5, 6) sage: l1.parent().degree(), l2.parent().degree(), l12.parent().degree() (1, 1, 2) sage: l12.is_cocycle(), l12.is_coboundary() (True, False) """ if not isinstance(cochain.parent(), Cochains): raise ValueError('argument must be a cochain') if cochain.parent().cell_complex() != self.parent().cell_complex(): raise ValueError('cochain must be over the same cell complex') left_deg = self.parent().degree() right_deg = cochain.parent().degree() left_chains = self.parent().dual() right_chains = cochain.parent().dual() base_ring = coercion_model.common_parent( left_chains.base_ring(), right_chains.base_ring()) cx = self.parent().cell_complex() codomain = cx.n_chains( left_deg + right_deg, base_ring=base_ring, cochains=True) accumulator = codomain.zero() for cell in codomain.indices(): for (coeff, left_cell, right_cell) in cx.alexander_whitney(cell, left_deg): if not coeff: continue left = left_chains(left_cell) right = right_chains(right_cell) accumulator += codomain(cell) * coeff * self.eval(left) * cochain.eval(right) return accumulator
def eval(self, other): """ Evaluate this cochain on the chain ``other``. INPUT: - ``other`` -- a chain for the same cell complex in the same dimension with the same base ring OUTPUT: scalar EXAMPLES:: sage: S2 = simplicial_complexes.Sphere(2) sage: C_2 = S2.n_chains(1) sage: C_2_co = S2.n_chains(1, cochains=True) sage: x = C_2.basis()[Simplex((0,2))] sage: y = C_2.basis()[Simplex((1,3))] sage: z = x+2*y sage: a = C_2_co.basis()[Simplex((1,3))] sage: b = C_2_co.basis()[Simplex((0,3))] sage: c = 3*a-2*b sage: z (0, 2) + 2*(1, 3) sage: c -2*\chi_(0, 3) + 3*\chi_(1, 3) sage: c.eval(z) 6 TESTS:: sage: z.eval(c) # z is not a cochain Traceback (most recent call last): ... AttributeError: 'Chains_with_category.element_class' object has no attribute 'eval' sage: c.eval(c) # can't evaluate a cochain on a cochain Traceback (most recent call last): ... ValueError: argument is not a chain """ if not isinstance(other.parent(), Chains): raise ValueError('argument is not a chain') if other.parent().indices() != self.parent().indices(): raise ValueError('the cells are not compatible') result = sum(coeff * other.coefficient(cell) for cell, coeff in self) R = self.base_ring() if R != other.base_ring(): R = coercion_model.common_parent(R, other.base_ring()) return R(result)
def _from_polymake_polytope(cls, parent, polymake_polytope): r""" Initializes a polyhedron from a polymake Polytope object. TESTS:: sage: from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake sage: from sage.geometry.polyhedron.parent import Polyhedra sage: P=Polyhedron(ieqs=[[1, 0, 2], [3, 0, -2], [3, 2, -2]]) sage: PP = polymake(P) # optional - polymake sage: parent = Polyhedra(QQ, 2, backend='polymake') # optional - polymake sage: Q=Polyhedron_polymake._from_polymake_polytope(parent, PP) # optional - polymake """ if parent is None: from .parent import Polyhedra from sage.rings.rational_field import QQ from sage.rings.qqbar import AA if polymake_polytope.typeof( )[0] == 'Polymake::polytope::Polytope__Rational': base_ring = QQ else: from sage.structure.element import coercion_model data = [ g.sage() for g in itertools.chain(polymake_polytope.VERTICES, polymake_polytope.LINEALITY_SPACE, polymake_polytope.FACETS, polymake_polytope.AFFINE_HULL) ] if data: base_ring = coercion_model.common_parent(*data).base_ring() else: base_ring = QQ ambient_dim = polymake_polytope.AMBIENT_DIM().sage() parent = Polyhedra(base_ring=base_ring, ambient_dim=ambient_dim, backend='polymake') return cls(parent, None, None, polymake_polytope=polymake_polytope)
def __add__(self, other): """ Return the sum of two subgroups. EXAMPLES:: sage: C = J0(22).cuspidal_subgroup() sage: C.gens() [[(1/5, 1/5, 4/5, 0)], [(0, 0, 0, 1/5)]] sage: A = C.subgroup([C.0]); B = C.subgroup([C.1]) sage: A + B == C True An example where the parent abelian varieties are different:: A = J0(48); A[0].cuspidal_subgroup() + A[1].cuspidal_subgroup() Finite subgroup with invariants [2, 4, 4] over QQ of Abelian subvariety of dimension 2 of J0(48) """ if not isinstance(other, FiniteSubgroup): raise TypeError("only addition of two finite subgroups is defined") A = self.abelian_variety() B = other.abelian_variety() if not A.in_same_ambient_variety(B): raise ValueError( "self and other must be in the same ambient Jacobian") K = coercion_model.common_parent(self.field_of_definition(), other.field_of_definition()) lattice = self.lattice() + other.lattice() if A != B: C = A + B lattice += C.lattice() return FiniteSubgroup_lattice(C, lattice, field_of_definition=K) else: return FiniteSubgroup_lattice(self.abelian_variety(), lattice, field_of_definition=K)
def intersection(self, other): """ Return the intersection of the finite subgroups self and other. INPUT: - ``other`` - a finite group OUTPUT: a finite group EXAMPLES:: sage: E11a0, E11a1, B = J0(33) sage: G = E11a0.torsion_subgroup(6); H = E11a0.torsion_subgroup(9) sage: G.intersection(H) Finite subgroup with invariants [3, 3] over QQ of Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33) sage: W = E11a1.torsion_subgroup(15) sage: G.intersection(W) Finite subgroup with invariants [] over QQ of Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33) sage: E11a0.intersection(E11a1)[0] Finite subgroup with invariants [5] over QQ of Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33) We intersect subgroups of different abelian varieties. :: sage: E11a0, E11a1, B = J0(33) sage: G = E11a0.torsion_subgroup(5); H = E11a1.torsion_subgroup(5) sage: G.intersection(H) Finite subgroup with invariants [5] over QQ of Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33) sage: E11a0.intersection(E11a1)[0] Finite subgroup with invariants [5] over QQ of Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33) We intersect abelian varieties with subgroups:: sage: t = J0(33).hecke_operator(7) sage: G = t.kernel()[0]; G Finite subgroup with invariants [2, 2, 2, 2, 4, 4] over QQ of Abelian variety J0(33) of dimension 3 sage: A = J0(33).old_subvariety() sage: A.intersection(G) Finite subgroup with invariants [2, 2, 2, 2] over QQ of Abelian subvariety of dimension 2 of J0(33) sage: A.hecke_operator(7).kernel()[0] Finite subgroup with invariants [2, 2, 2, 2] over QQ of Abelian subvariety of dimension 2 of J0(33) sage: B = J0(33).new_subvariety() sage: B.intersection(G) Finite subgroup with invariants [4, 4] over QQ of Abelian subvariety of dimension 1 of J0(33) sage: B.hecke_operator(7).kernel()[0] Finite subgroup with invariants [4, 4] over QQ of Abelian subvariety of dimension 1 of J0(33) sage: A.intersection(B)[0] Finite subgroup with invariants [3, 3] over QQ of Abelian subvariety of dimension 2 of J0(33) """ from .abvar import is_ModularAbelianVariety A = self.abelian_variety() if is_ModularAbelianVariety(other): amb = other B = other M = B.lattice().scale(Integer(1)/self.exponent()) K = coercion_model.common_parent(self.field_of_definition(), other.base_field()) else: amb = A if not isinstance(other, FiniteSubgroup): raise TypeError("only intersection with a finite subgroup or " "modular abelian variety is defined") B = other.abelian_variety() if A.ambient_variety() != B.ambient_variety(): raise TypeError("finite subgroups must be in the same ambient product Jacobian") M = other.lattice() K = coercion_model.common_parent(self.field_of_definition(), other.field_of_definition()) L = self.lattice() if A != B: # TODO: This might be way slower than what we could do if # we think more carefully. C = A + B L = L + C.lattice() M = M + C.lattice() W = L.intersection(M).intersection(amb.vector_space()) return FiniteSubgroup_lattice(amb, W, field_of_definition=K)
def intersection(self, other): """ Return the intersection of the finite subgroups self and other. INPUT: - ``other`` - a finite group OUTPUT: a finite group EXAMPLES:: sage: E11a0, E11a1, B = J0(33) sage: G = E11a0.torsion_subgroup(6); H = E11a0.torsion_subgroup(9) sage: G.intersection(H) Finite subgroup with invariants [3, 3] over QQ of Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33) sage: W = E11a1.torsion_subgroup(15) sage: G.intersection(W) Finite subgroup with invariants [] over QQ of Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33) sage: E11a0.intersection(E11a1)[0] Finite subgroup with invariants [5] over QQ of Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33) We intersect subgroups of different abelian varieties. :: sage: E11a0, E11a1, B = J0(33) sage: G = E11a0.torsion_subgroup(5); H = E11a1.torsion_subgroup(5) sage: G.intersection(H) Finite subgroup with invariants [5] over QQ of Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33) sage: E11a0.intersection(E11a1)[0] Finite subgroup with invariants [5] over QQ of Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33) We intersect abelian varieties with subgroups:: sage: t = J0(33).hecke_operator(7) sage: G = t.kernel()[0]; G Finite subgroup with invariants [2, 2, 2, 2, 4, 4] over QQ of Abelian variety J0(33) of dimension 3 sage: A = J0(33).old_subvariety() sage: A.intersection(G) Finite subgroup with invariants [2, 2, 2, 2] over QQ of Abelian subvariety of dimension 2 of J0(33) sage: A.hecke_operator(7).kernel()[0] Finite subgroup with invariants [2, 2, 2, 2] over QQ of Abelian subvariety of dimension 2 of J0(33) sage: B = J0(33).new_subvariety() sage: B.intersection(G) Finite subgroup with invariants [4, 4] over QQ of Abelian subvariety of dimension 1 of J0(33) sage: B.hecke_operator(7).kernel()[0] Finite subgroup with invariants [4, 4] over QQ of Abelian subvariety of dimension 1 of J0(33) sage: A.intersection(B)[0] Finite subgroup with invariants [3, 3] over QQ of Abelian subvariety of dimension 2 of J0(33) """ from .abvar import is_ModularAbelianVariety A = self.abelian_variety() if is_ModularAbelianVariety(other): amb = other B = other M = B.lattice().scale(Integer(1) / self.exponent()) K = coercion_model.common_parent(self.field_of_definition(), other.base_field()) else: amb = A if not isinstance(other, FiniteSubgroup): raise TypeError("only intersection with a finite subgroup or " "modular abelian variety is defined") B = other.abelian_variety() if A.ambient_variety() != B.ambient_variety(): raise TypeError( "finite subgroups must be in the same ambient product Jacobian" ) M = other.lattice() K = coercion_model.common_parent(self.field_of_definition(), other.field_of_definition()) L = self.lattice() if A != B: # TODO: This might be way slower than what we could do if # we think more carefully. C = A + B L = L + C.lattice() M = M + C.lattice() W = L.intersection(M).intersection(amb.vector_space()) return FiniteSubgroup_lattice(amb, W, field_of_definition=K)
def __call__(self, *values): """ Replace the generators of the free group by corresponding elements of the iterable ``values`` in the group element ``self``. INPUT: - ``*values`` -- a sequence of values, or a list/tuple/iterable of the same length as the number of generators of the free group. OUTPUT: The product of ``values`` in the order and with exponents specified by ``self``. EXAMPLES:: sage: G.<a,b> = FreeGroup() sage: w = a^2 * b^-1 * a^3 sage: w(1, 2) 1/2 sage: w(2, 1) 32 sage: w.subs(b=1, a=2) # indirect doctest 32 TESTS:: sage: w([1, 2]) 1/2 sage: w((1, 2)) 1/2 sage: w(i+1 for i in range(2)) 1/2 Check that :trac:`25017` is fixed:: sage: F = FreeGroup(2) sage: x0, x1 = F.gens() sage: u = F(1) sage: parent(u.subs({x1:x0})) is F True sage: F = FreeGroup(2) sage: x0, x1 = F.gens() sage: u = x0*x1 sage: u.subs({x0:3, x1:2}) 6 sage: u.subs({x0:1r, x1:2r}) 2 sage: M0 = matrix(ZZ,2,[1,1,0,1]) sage: M1 = matrix(ZZ,2,[1,0,1,1]) sage: u.subs({x0: M0, x1: M1}) [2 1] [1 1] TESTS:: sage: F.<x,y> = FreeGroup() sage: F.one().subs(x=x, y=1) Traceback (most recent call last): ... TypeError: no common canonical parent for objects with parents: 'Free Group on generators {x, y}' and 'Integer Ring' """ if len(values) == 1: try: values = list(values[0]) except TypeError: pass G = self.parent() if len(values) != G.ngens(): raise ValueError('number of values has to match the number of generators') replace = dict(zip(G.gens(), values)) new_parent = coercion_model.common_parent(*[parent(v) for v in values]) try: return new_parent.prod(replace[gen] ** power for gen, power in self.syllables()) except AttributeError: return prod(new_parent(replace[gen]) ** power for gen, power in self.syllables())
def __call__(self, *values): """ Replace the generators of the free group by corresponding elements of the iterable ``values`` in the group element ``self``. INPUT: - ``*values`` -- a sequence of values, or a list/tuple/iterable of the same length as the number of generators of the free group. OUTPUT: The product of ``values`` in the order and with exponents specified by ``self``. EXAMPLES:: sage: G.<a,b> = FreeGroup() sage: w = a^2 * b^-1 * a^3 sage: w(1, 2) 1/2 sage: w(2, 1) 32 sage: w.subs(b=1, a=2) # indirect doctest 32 TESTS:: sage: w([1, 2]) 1/2 sage: w((1, 2)) 1/2 sage: w(i+1 for i in range(2)) 1/2 Check that :trac:`25017` is fixed:: sage: F = FreeGroup(2) sage: x0, x1 = F.gens() sage: u = F(1) sage: parent(u.subs({x1:x0})) is F True sage: F = FreeGroup(2) sage: x0, x1 = F.gens() sage: u = x0*x1 sage: u.subs({x0:3, x1:2}) 6 sage: u.subs({x0:1r, x1:2r}) 2 sage: M0 = matrix(ZZ,2,[1,1,0,1]) sage: M1 = matrix(ZZ,2,[1,0,1,1]) sage: u.subs({x0: M0, x1: M1}) [2 1] [1 1] TESTS:: sage: F.<x,y> = FreeGroup() sage: F.one().subs(x=x, y=1) Traceback (most recent call last): ... TypeError: no common canonical parent for objects with parents: 'Free Group on generators {x, y}' and 'Integer Ring' """ if len(values) == 1: try: values = list(values[0]) except TypeError: pass G = self.parent() if len(values) != G.ngens(): raise ValueError( 'number of values has to match the number of generators') replace = dict(zip(G.gens(), values)) new_parent = coercion_model.common_parent(*[parent(v) for v in values]) try: return new_parent.prod(replace[gen]**power for gen, power in self.syllables()) except AttributeError: return prod( new_parent(replace[gen])**power for gen, power in self.syllables())