示例#1
0
    def plot(self, max_points=2500, **args):
        r"""
        Create a visualization of this `p`-adic ring as a fractal
        similar to a generalization of the Sierpi\'nski
        triangle.

        The resulting image attempts to capture the
        algebraic and topological characteristics of `\mathbb{Z}_p`.

        INPUT:

        - ``max_points`` -- the maximum number or points to plot,
          which controls the depth of recursion (default 2500)

        - ``**args`` -- color, size, etc. that are passed to the
          underlying point graphics objects

        REFERENCES:

        - Cuoco, A. ''Visualizing the `p`-adic Integers'', The
          American Mathematical Monthly, Vol. 98, No. 4 (Apr., 1991),
          pp. 355-364

        EXAMPLES::

            sage: Zp(3).plot()
            Graphics object consisting of 1 graphics primitive
            sage: Zp(5).plot(max_points=625)
            Graphics object consisting of 1 graphics primitive
            sage: Zp(23).plot(rgbcolor=(1,0,0))
            Graphics object consisting of 1 graphics primitive
        """
        if 'pointsize' not in args:
            args['pointsize'] = 1
        from sage.misc.mrange import cartesian_product_iterator
        from sage.rings.real_double import RDF
        from sage.plot.all import points, circle, Graphics
        p = self.prime()
        phi = 2*RDF.pi()/p
        V = RDF**2
        vs = [V([(phi*t).sin(), (phi*t).cos()]) for t in range(p)]
        all = []
        depth = max(RDF(max_points).log(p).floor(), 1)
        scale = min(RDF(1.5/p), 1/RDF(3))
        pts = [vs]*depth
        if depth == 1 and 23 < p < max_points:
            extras = int(max_points/p)
            if p/extras > 5:
                pts = [vs]*depth + [vs[::extras]]
        for digits in cartesian_product_iterator(pts):
            p = sum([v * scale**n for n, v in enumerate(digits)])
            all.append(tuple(p))
        g = points(all, **args)
        # Set default plotting options
        g.axes(False)
        g.set_aspect_ratio(1)
        return g
示例#2
0
    def plot(self, max_points=2500, **args):
        r"""
        Create a visualization of this `p`-adic ring as a fractal
        similar to a generalization of the Sierpi\'nski
        triangle.

        The resulting image attempts to capture the
        algebraic and topological characteristics of `\mathbb{Z}_p`.

        INPUT:

        - ``max_points`` -- the maximum number or points to plot,
          which controls the depth of recursion (default 2500)

        - ``**args`` -- color, size, etc. that are passed to the
          underlying point graphics objects

        REFERENCES:

        - Cuoco, A. ''Visualizing the `p`-adic Integers'', The
          American Mathematical Monthly, Vol. 98, No. 4 (Apr., 1991),
          pp. 355-364

        EXAMPLES::

            sage: Zp(3).plot()
            Graphics object consisting of 1 graphics primitive
            sage: Zp(5).plot(max_points=625)
            Graphics object consisting of 1 graphics primitive
            sage: Zp(23).plot(rgbcolor=(1,0,0))
            Graphics object consisting of 1 graphics primitive
        """
        if 'pointsize' not in args:
            args['pointsize'] = 1
        from sage.misc.mrange import cartesian_product_iterator
        from sage.rings.real_double import RDF
        from sage.plot.all import points, circle, Graphics
        p = self.prime()
        phi = 2 * RDF.pi() / p
        V = RDF**2
        vs = [V([(phi * t).sin(), (phi * t).cos()]) for t in range(p)]
        all = []
        depth = max(RDF(max_points).log(p).floor(), 1)
        scale = min(RDF(1.5 / p), 1 / RDF(3))
        pts = [vs] * depth
        if depth == 1 and 23 < p < max_points:
            extras = int(max_points / p)
            if p / extras > 5:
                pts = [vs] * depth + [vs[::extras]]
        for digits in cartesian_product_iterator(pts):
            p = sum([v * scale**n for n, v in enumerate(digits)])
            all.append(tuple(p))
        g = points(all, **args)
        # Set default plotting options
        g.axes(False)
        g.set_aspect_ratio(1)
        return g
示例#3
0
    def tensor_term_iterator(self):
        """Returns a coefficient, a list of S partitions, and a list of Q
        partitions which parametrize one term in the chern class of the
        tensor product of the bundles specified by the input data.
        INPUT: self
        OUTPUT: yields a ChernClassMonomial object
        """
        if self.blocks_computed == False:
            self.compute_block_sizes()
        FL_part = []
        n = self.num_nodes
        for i in range(n):
            FL_part.append(flagged_partition_iterator(self.l[i],self.r[i]))

        CPI = cartesian_product_iterator( [ list(a) for a in FL_part ] )
        for c in CPI:
            M = ChernClassMonomial()
            for i in range(n):
                (lam,mu) = c[i]
                M.append( ChernClass( dcoeff(lam,mu,self.l[i]), 's', i+1, mu ) )
                M.append( ChernClass( 1, 'q', i+1, conj( dual(lam,self.l[i],self.r[i]) )))
            yield M
示例#4
0
    def square_roots_of_one(self):
        """
        Return all square roots of 1 in self, i.e., all solutions to
        `x^2 - 1 = 0`.

        OUTPUT:

        The square roots of 1 in ``self`` as a tuple.

        EXAMPLES::

            sage: R = Integers(2^10)
            sage: [x for x in R if x^2 == 1]
            [1, 511, 513, 1023]
            sage: R.square_roots_of_one()
            (1, 511, 513, 1023)

        ::

            sage: v = Integers(9*5).square_roots_of_one(); v
            (1, 19, 26, 44)
            sage: [x^2 for x in v]
            [1, 1, 1, 1]
            sage: v = Integers(9*5*8).square_roots_of_one(); v
            (1, 19, 71, 89, 91, 109, 161, 179, 181, 199, 251, 269, 271, 289, 341, 359)
            sage: [x^2 for x in v]
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
        """
        try:
            return self.__square_roots_of_one
        except AttributeError:
            pass
        n = self.__order
        if n.is_prime_power():
            if n % 2 == 0:
                # power of 2
                if n == 2:
                    v = [self(1)]
                elif n == 4:
                    v = [self(1), self(3)]
                else:  # n >= 8
                    half_ord = n // 2
                    v = [
                        self(1),
                        self(-1),
                        self(half_ord - 1),
                        self(half_ord + 1)
                    ]
            else:
                v = [self(1), self(-1)]
        else:
            # Reduce to the prime power case.
            F = self.factored_order()
            vmod = []
            moduli = []
            for p, e in F:
                k = p**e
                R = IntegerModRing(p**e)
                w = [self(x) for x in R.square_roots_of_one()]
                vmod.append(w)
                moduli.append(k)
            # Now combine in all possible ways using the CRT
            basis = CRT_basis(moduli)
            from sage.misc.mrange import cartesian_product_iterator
            v = []
            for x in cartesian_product_iterator(vmod):
                # x is a specific choice of roots modulo each prime power divisor
                a = sum([basis[i] * x[i] for i in range(len(x))])
                v.append(a)
            #end for
        #end if

        v.sort()
        v = tuple(v)
        self.__square_roots_of_one = v
        return v
示例#5
0
    def square_roots_of_one(self):
        """
        Return all square roots of 1 in self, i.e., all solutions to
        `x^2 - 1 = 0`.

        OUTPUT:

        The square roots of 1 in ``self`` as a tuple.

        EXAMPLES::

            sage: R = Integers(2^10)
            sage: [x for x in R if x^2 == 1]
            [1, 511, 513, 1023]
            sage: R.square_roots_of_one()
            (1, 511, 513, 1023)

        ::

            sage: v = Integers(9*5).square_roots_of_one(); v
            (1, 19, 26, 44)
            sage: [x^2 for x in v]
            [1, 1, 1, 1]
            sage: v = Integers(9*5*8).square_roots_of_one(); v
            (1, 19, 71, 89, 91, 109, 161, 179, 181, 199, 251, 269, 271, 289, 341, 359)
            sage: [x^2 for x in v]
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
        """
        try:
            return self.__square_roots_of_one
        except AttributeError:
            pass
        n = self.__order
        if n.is_prime_power():
            if n % 2 == 0:
                # power of 2
                if n == 2:
                    v = [self(1)]
                elif n == 4:
                    v = [self(1), self(3)]
                else:  # n >= 8
                    half_ord = n // 2
                    v = [self(1), self(-1), self(half_ord - 1), self(half_ord + 1)]
            else:
                v = [self(1), self(-1)]
        else:
            # Reduce to the prime power case.
            F = self.factored_order()
            vmod = []
            moduli = []
            for p, e in F:
                k = p ** e
                R = IntegerModRing(p ** e)
                w = [self(x) for x in R.square_roots_of_one()]
                vmod.append(w)
                moduli.append(k)
            # Now combine in all possible ways using the CRT
            from sage.rings.arith import CRT_basis

            basis = CRT_basis(moduli)
            from sage.misc.mrange import cartesian_product_iterator

            v = []
            for x in cartesian_product_iterator(vmod):
                # x is a specific choice of roots modulo each prime power divisor
                a = sum([basis[i] * x[i] for i in range(len(x))])
                v.append(a)
            # end for
        # end if

        v.sort()
        v = tuple(v)
        self.__square_roots_of_one = v
        return v
示例#6
0
    def subgroups(self, check=False):
        r"""
        Compute all the subgroups of this abelian group (which must be finite).
        
        TODO: This is *many orders of magnitude* slower than Magma.

        INPUT:

        - check: if True, performs the same computation in GAP and checks that
          the number of subgroups generated is the same. (I don't know how to
          convert GAP's output back into Sage, so we don't actually compare the
          subgroups).

        ALGORITHM:

            If the group is cyclic, the problem is easy. Otherwise, write it as
            a direct product A x B, where B is cyclic. Compute the subgroups of
            A (by recursion).

            Now, for every subgroup C of A x B, let G be its *projection onto*
            A and H its *intersection with* B. Then there is a well-defined
            homomorphism f: G -> B/H that sends a in G to the class mod H of b,
            where (a,b) is any element of C lifting a; and every subgroup C
            arises from a unique triple (G, H, f). 

        EXAMPLES::

            sage: AbelianGroup([2,3]).subgroups()
            [Multiplicative Abelian Group isomorphic to C2 x C3, which is the subgroup of
            Multiplicative Abelian Group isomorphic to C2 x C3
            generated by [f0*f1^2],
             Multiplicative Abelian Group isomorphic to C2, which is the subgroup of
            Multiplicative Abelian Group isomorphic to C2 x C3
            generated by [f0],
             Multiplicative Abelian Group isomorphic to C3, which is the subgroup of
            Multiplicative Abelian Group isomorphic to C2 x C3
            generated by [f1],
             Trivial Abelian Group, which is the subgroup of
            Multiplicative Abelian Group isomorphic to C2 x C3
            generated by []]

            sage: len(AbelianGroup([2,4,8]).subgroups())
            81

        """
        if not self.is_finite(): raise ValueError, "Group must be finite"
        from sage.misc.misc import verbose

        v = self.invariants()
        
        
        if len(v) <= 1:
            if v == [] or v[0] == 1:
                return [self]
            else:
                return [ self.subgroup([self.gen(0)**i]) for i in divisors(v[0])[:-1]] + [self.subgroup([])]

        A = AbelianGroup(v[:-1])
        x = v[-1]

        Wsubs = A.subgroups()

        subgps = []
        for G in Wsubs:
            verbose("G = subgp generated by %s" % G.gens())
            verbose("invariants are:", [t.order() for t in G.gens()]) # G.invariants() doesn't work
            for H in divisors(x):
                # H = the subgroup of *index* H.
                its = [xrange(0, H, H/gcd(H, G.gen(i).order())) for i in xrange(len(G.gens()))] 
                for f in cartesian_product_iterator(its):
                    verbose("using hom from G to C_%s sending gens to %s" % (H,f))
                    new_sub = []
                    for a in xrange(len(G.gens())):
                        new_sub.append(G.gen(a).list() + [f[a]])
                    if H != x:
                        new_sub.append([0]*A.ngens() + [H])
                    subgps.append(self.subgroup_reduced(new_sub))
        
        if check:
            from sage.interfaces.all import gap
            verbose("Running Gap cross-check")
            t = ZZ(gap.eval("Size(SubgroupsSolvableGroup(AbelianGroup(%s)))" % v))
            if t != len(subgps):
                raise ArithmeticError, "For %s Gap finds %s subgroups, I found %s" % (v, t, len(subgps))
            verbose("Gap check OK for %s: %s" % (v, t))
        return subgps
示例#7
0
    def subgroups(self, check=False):
        r"""
        Compute all the subgroups of this abelian group (which must be finite).
        
        TODO: This is *many orders of magnitude* slower than Magma.

        INPUT:

        - check: if True, performs the same computation in GAP and checks that
          the number of subgroups generated is the same. (I don't know how to
          convert GAP's output back into Sage, so we don't actually compare the
          subgroups).

        ALGORITHM:

            If the group is cyclic, the problem is easy. Otherwise, write it as
            a direct product A x B, where B is cyclic. Compute the subgroups of
            A (by recursion).

            Now, for every subgroup C of A x B, let G be its *projection onto*
            A and H its *intersection with* B. Then there is a well-defined
            homomorphism f: G -> B/H that sends a in G to the class mod H of b,
            where (a,b) is any element of C lifting a; and every subgroup C
            arises from a unique triple (G, H, f). 

        EXAMPLES::

            sage: AbelianGroup([2,3]).subgroups()
            [Multiplicative Abelian Group isomorphic to C2 x C3, which is the subgroup of
            Multiplicative Abelian Group isomorphic to C2 x C3
            generated by [f0*f1^2],
             Multiplicative Abelian Group isomorphic to C2, which is the subgroup of
            Multiplicative Abelian Group isomorphic to C2 x C3
            generated by [f0],
             Multiplicative Abelian Group isomorphic to C3, which is the subgroup of
            Multiplicative Abelian Group isomorphic to C2 x C3
            generated by [f1],
             Trivial Abelian Group, which is the subgroup of
            Multiplicative Abelian Group isomorphic to C2 x C3
            generated by []]

            sage: len(AbelianGroup([2,4,8]).subgroups())
            81

        """
        if not self.is_finite(): raise ValueError, "Group must be finite"
        from sage.misc.misc import verbose

        v = self.invariants()

        if len(v) <= 1:
            if v == [] or v[0] == 1:
                return [self]
            else:
                return [
                    self.subgroup([self.gen(0)**i])
                    for i in divisors(v[0])[:-1]
                ] + [self.subgroup([])]

        A = AbelianGroup(v[:-1])
        x = v[-1]

        Wsubs = A.subgroups()

        subgps = []
        for G in Wsubs:
            verbose("G = subgp generated by %s" % G.gens())
            verbose("invariants are:",
                    [t.order()
                     for t in G.gens()])  # G.invariants() doesn't work
            for H in divisors(x):
                # H = the subgroup of *index* H.
                its = [
                    xrange(0, H, H / gcd(H,
                                         G.gen(i).order()))
                    for i in xrange(len(G.gens()))
                ]
                for f in cartesian_product_iterator(its):
                    verbose("using hom from G to C_%s sending gens to %s" %
                            (H, f))
                    new_sub = []
                    for a in xrange(len(G.gens())):
                        new_sub.append(G.gen(a).list() + [f[a]])
                    if H != x:
                        new_sub.append([0] * A.ngens() + [H])
                    subgps.append(self.subgroup_reduced(new_sub))

        if check:
            from sage.interfaces.all import gap
            verbose("Running Gap cross-check")
            t = ZZ(
                gap.eval("Size(SubgroupsSolvableGroup(AbelianGroup(%s)))" % v))
            if t != len(subgps):
                raise ArithmeticError, "For %s Gap finds %s subgroups, I found %s" % (
                    v, t, len(subgps))
            verbose("Gap check OK for %s: %s" % (v, t))
        return subgps