def _is_a_cover(mt0, mt1):
    r"""
    Define the cover relations.

    Return ``True`` if and only if the second argument is a cover of
    the first one.

    EXAMPLES::

        sage: import sage.combinat.alternating_sign_matrix as asm
        sage: asm._is_a_cover([[1,2,3],[1,2],[1]], [[1,2,3],[1,3],[1]])
        True
        sage: asm._is_a_cover([[1,2,3],[1,3],[2]], [[1,2,3],[1,2],[1]])
        False
    """
    diffs = 0
    for (a,b) in itertools.izip(flatten(mt0), flatten(mt1)):
        if a != b:
            if a+1 == b:
                diffs += 1
            else:
                return False
        if diffs > 1:
            return False
    return diffs == 1
Beispiel #2
0
    def YoungsLattice(n):
        """
        Return Young's Lattice up to rank `n`.

        In other words, the poset of partitions
        of size less than or equal to `n` ordered by inclusion.

        INPUT:

        - ``n`` -- a positive integer

        EXAMPLES::

            sage: P = Posets.YoungsLattice(3); P
            Finite meet-semilattice containing 7 elements
            sage: P.cover_relations()
            [[[], [1]],
             [[1], [1, 1]],
             [[1], [2]],
             [[1, 1], [1, 1, 1]],
             [[1, 1], [2, 1]],
             [[2], [2, 1]],
             [[2], [3]]]
        """
        from sage.combinat.partition import Partitions, Partition
        from sage.misc.flatten import flatten
        partitions = flatten([list(Partitions(i)) for i in range(n + 1)])
        return JoinSemilattice((partitions, Partition.contains)).dual()
Beispiel #3
0
    def polish_notation(self):
        r"""
        Convert the calling boolean formula into polish notation.

        OUTPUT:

        A string representation of the formula in polish notation.

        EXAMPLES:

        This example illustrates converting a formula to polish notation::

            sage: import sage.logic.propcalc as propcalc
            sage: f = propcalc.formula("~~a|(c->b)")
            sage: f.polish_notation()
            '|~~a->cb'

            sage: g = propcalc.formula("(a|~b)->c")
            sage: g.polish_notation()
            '->|a~bc'

        AUTHORS:

        - Paul Scurek (2013-08-03)
        """
        return ''.join(flatten(logicparser.polish_parse(repr(self))))
def _prepare_coefficient_by_restriction(precision, weight_parity, relation_precision, S) :
    r"""
    Provide input data to ``_coefficient_by_restriction__with_restriction_matrix``.

    INPUT:
    
    - ``precision`` -- A filter for Jacobi forms of arbitrary index.
    
    - ``weight_parity`` -- An integer.
    
    - ``relation_precision`` -- A filter for Jacobi forms.

    - ``S`` -- A list of vectors.
    """
    L = precision.jacobi_index()

    rand = Random()
    max_S_length = max([L(s) for s in S])
    relation_S_pre = flatten(L.short_vector_list_up_to_length(max_S_length + 1, True)[1:])
    relation_S = list()
    for _ in range(4 * L.det()) :
        s = rand.choice(relation_S_pre)
        if s not in relation_S :
            relation_S.append(s)

    (global_restriction_matrix__big, row_groups, row_labels, column_labels) = _global_restriction_matrix(precision, S, weight_parity)
    (global_relation_matrix, column_labels_relations) = _global_relation_matrix(relation_precision, relation_S, weight_parity )
    global_restriction_matrix__big.change_ring(QQ)
    global_relation_matrix.change_ring(QQ)

    return ( global_restriction_matrix__big, row_groups, row_labels, column_labels,
             global_relation_matrix, column_labels_relations )
Beispiel #5
0
    def module_generator(self, shape):
        """
        This yields the module generator (or highest weight element) of a classical
        crystal of given shape. The module generator is the unique tableau with equal
        shape and content.

        EXAMPLE::

            sage: T = CrystalOfTableaux(['D',3], shape = [1,1])
            sage: T.module_generator([1,1])
            [[1], [2]]
        """
        type = self.cartan_type()
        if type[0] == 'D' and len(shape) == type[1] and shape[type[1]-1] < 0:
            invert = True
            shape = shape[:-1]+(-shape[type[1]-1],)
        else:
            invert = False
        p = Partition(shape).conjugate()
        # The column canonical tableau, read by columns
        module_generator = flatten([[p[j]-i for i in range(p[j])] for j in range(len(p))])
        if invert:
            for i in range(type[1]):
                if module_generator[i] == type[1]:
                    module_generator[i] = -type[1]
        return self(list=[self.letters(x) for x in module_generator])
Beispiel #6
0
    def module_generator(self, shape):
        """
        This yields the module generator (or highest weight element) of a classical
        crystal of given shape. The module generator is the unique tableau with equal
        shape and content.

        EXAMPLES::

            sage: T = crystals.Tableaux(['D',3], shape = [1,1])
            sage: T.module_generator([1,1])
            [[1], [2]]

            sage: T = crystals.Tableaux(['D',4],shape=[2,2,2,-2])
            sage: T.module_generator(tuple([2,2,2,-2]))
            [[1, 1], [2, 2], [3, 3], [-4, -4]]
            sage: T.cardinality()
            294
            sage: T = crystals.Tableaux(['D',4],shape=[2,2,2,2])
            sage: T.module_generator(tuple([2,2,2,2]))
            [[1, 1], [2, 2], [3, 3], [4, 4]]
            sage: T.cardinality()
            294
        """
        type = self.cartan_type()
        if type[0] == 'D' and len(shape) == type[1] and shape[type[1]-1] < 0:
            invert = True
            shape = shape[:-1] + (-shape[type[1]-1],)
        else:
            invert = False
        p = Partition(shape).conjugate()
        # The column canonical tableau, read by columns
        module_generator = flatten([[val-i for i in range(val)] for val in p])
        if invert:
            module_generator = [(-x if x == type[1] else x) for x in module_generator]
        return self(list=[self.letters(x) for x in module_generator])
Beispiel #7
0
     def bruhat_interval(self, x, y):
         """
         Returns the list of t such that x <= t <= y.
 
         EXAMPLES::
 
             sage: W = WeylGroup("A3", prefix="s")
             sage: [s1,s2,s3]=W.simple_reflections()
             sage: W.bruhat_interval(s2,s1*s3*s2*s1*s3)
             [s1*s2*s3*s2*s1, s2*s3*s2*s1, s3*s1*s2*s1, s1*s2*s3*s1, s1*s2*s3*s2, s3*s2*s1, s2*s3*s1, s2*s3*s2, s1*s2*s1, s3*s1*s2, s1*s2*s3, s2*s1, s3*s2, s2*s3, s1*s2, s2]
             sage: W = WeylGroup(['A',2,1], prefix="s")
             sage: [s0,s1,s2]=W.simple_reflections()
             sage: W.bruhat_interval(1,s0*s1*s2)
             [s0*s1*s2, s1*s2, s0*s2, s0*s1, s2, s1, s0, 1]
         """
         if x == 1:
             x = self.one()
         if y == 1:
             y = self.one()
         if x == y:
             return [x]
         ret = []
         if not x.bruhat_le(y):
             return ret
         ret.append([y])
         while ret[-1] != []:
             nextlayer = []
             for z in ret[-1]:
                 for t in z.bruhat_lower_covers():
                     if t not in nextlayer:
                         if x.bruhat_le(t):
                             nextlayer.append(t)
             ret.append(nextlayer)
         return flatten(ret)
    def minimal_composition_filter(self, ls, rs) :
        if len(ls) == 0 or len(rs) == 0 :
            return SiegelModularFormGnFilter_diagonal_lll(self.__n, 0, self.__reduced)

        maxd = flatten( map(lambda (ml, mr): [ml[i,i] + mr[i,i] for i in xrange(self.__n)],
                                itertools.product(ls, rs) ) )

        return SiegelModularFormGnFilter_diagonal_lll(self.__n, maxd + 1, self.__reduced)
    def plot_cluster_fan_stereographically(self, northsign=1, north=None, right=None, colors=None):
        from sage.plot.graphics import Graphics
        from sage.plot.point import point
        from sage.misc.flatten import flatten
        from sage.plot.line import line
        from sage.misc.functional import norm

        if self.rk !=3:
            raise ValueError("Can only stereographically project fans in 3d.")
        if not self.is_finite() and self._depth == infinity:
            raise ValueError("For infinite algebras you must specify the depth.")

        if north == None:
            if self.is_affine():
                north = vector(self.delta())
            else:
                north = vector( (-1,-1,-1) )
        if right == None:
            if self.is_affine():
                right = vector(self.gamma())
            else:
                right = vector( (1,0,0) )
        if colors == None:
            colors = dict([(0,'red'),(1,'green'),(2,'blue'),(3,'cyan'),(4,'yellow')])
        G = Graphics()

        roots = list(self.g_vectors())
        compatible = []
        while roots:
            x = roots.pop()
            for y in roots:
                if self.compatibility_degree(x,y) == 0:
                    compatible.append((x,y))
        for (u,v) in compatible:
            G += _stereo_arc(vector(u),vector(v),vector(u+v),north=northsign*north,right=right,thickness=0.5,color='black')

        for i in range(3):
            orbit = self.ith_orbit(i)
            for j in orbit:
                G += point(_stereo_coordinates(vector(orbit[j]),north=northsign*north,right=right),color=colors[i],zorder=len(G))

        if self.is_affine():
            tube_vectors = map(vector,flatten(self.affine_tubes()))
            for v in tube_vectors:
                G += point(_stereo_coordinates(v,north=northsign*north,right=right),color=colors[3],zorder=len(G))
            if north != vector(self.delta()):
                G += _stereo_arc(tube_vectors[0],tube_vectors[1],vector(self.delta()),north=northsign*north,right=right,thickness=2,color=colors[4],zorder=0)
            else:
                # FIXME: refactor this before publishing
                tube_projections = [
                        _stereo_coordinates(v,north=northsign*north,right=right)
                        for v in tube_vectors ]
                t=min((G.get_minmax_data()['xmax'],G.get_minmax_data()['ymax']))
                G += line([tube_projections[0],tube_projections[0]+t*(_normalize(tube_projections[0]-tube_projections[1]))],thickness=2,color=colors[4],zorder=0)
                G += line([tube_projections[1],tube_projections[1]+t*(_normalize(tube_projections[1]-tube_projections[0]))],thickness=2,color=colors[4],zorder=0)
        G.set_aspect_ratio(1)
        G._show_axes = False
        return G
Beispiel #10
0
 def contained_partitions(l):
     """
     Nested function returning those partitions contained in
     the partition `l`
     """
     if l == Partition([]):
         return l
     return flatten([l, [contained_partitions(m)
                         for m in lower_covers(l)]])
Beispiel #11
0
    def _call_(self, x):
        r"""
        Return the image of ``x`` in the tableau model of `B(\infty)`.

        EXAMPLES::

            sage: T = crystals.infinity.Tableaux(['A',3])
            sage: RC = crystals.infinity.RiggedConfigurations(['A',3])
            sage: phi = T.coerce_map_from(RC)
            sage: x = RC.an_element().f_string([2,2,1,1,3,2,1,2,1,3])
            sage: y = phi(x); y.pp()
              1  1  1  1  1  2  2  3  4
              2  2  3  4
              3
            sage: (~phi)(y) == x
            True
        """
        lam = [sum(nu)+1 for nu in x]
        ct = self.domain().cartan_type()
        I = ct.index_set()
        if ct.type() == 'D':
            lam[-2] = max(lam[-2], lam[-1])
            lam.pop()
            l = sum([ [[r+1,1]]*v for r,v in enumerate(lam[:-1]) ], [])
            n = len(I)
            l = l + sum([ [[n,1], [n-1,1]] for k in range(lam[-1])], [])
        else:
            if ct.type() == 'B':
                lam[-1] *= 2
            l = sum([ [[r,1]]*lam[i] for i,r in enumerate(I) ], [])

        RC = RiggedConfigurations(ct.affine(), reversed(l))
        elt = RC(x)
        if ct.type() == 'A':
            bij = RCToKRTBijectionTypeA(elt)
        elif ct.type() == 'B':
            bij = RCToMLTBijectionTypeB(elt)
        elif ct.type() == 'C':
            bij = RCToKRTBijectionTypeC(elt)
        elif ct.type() == 'D':
            bij = RCToMLTBijectionTypeD(elt)
        else:
            raise NotImplementedError("bijection of type {} not yet implemented".format(ct))
        y = bij.run()

        # Now make the result marginally large
        y = [list(c) for c in y]
        cur = []
        L = CrystalOfLetters(ct)
        for i in I:
            cur.insert(0, L(i))
            c = y.count(cur)
            while c > 1:
                y.remove(cur)
                c -= 1
        return self.codomain()(*flatten(y))
Beispiel #12
0
    def loops_iterator(self, other=None):
        r"""
        INPUT:

             - ``other`` -- a perfect matching of the same set of ``self``.
               (if the second argument is empty, the method :meth:`an_element` is
               called on the parent of the first)

        OUTPUT:

            If we draw the two perfect matchings simultaneously as edges of a
            graph, the graph obtained is a union of cycles of even lengths.
            The function returns an iterator for these cycles (each cycle is
            given as a list).

        EXAMPLES::

            sage: o = PerfectMatching([(1, 7), (2, 4), (3, 8), (5, 6)])
            sage: p = PerfectMatching([(1, 6), (2, 7), (3, 4), (5, 8)])
            sage: it = o.loops_iterator(p)
            sage: it.next()
            [1, 7, 2, 4, 3, 8, 5, 6]
            sage: it.next()
            Traceback (most recent call last):
            ...
            StopIteration
        """
        if other is None:
            other = self.parent().an_element()
        elif self.parent() != other.parent():
            s = "%s is not a matching of the ground set of %s" % (other, self)
            raise ValueError(s)
        remain = flatten(self.value)
        while len(remain) > 0:
            a = remain.pop(0)
            b = self.partner(a)
            remain.remove(b)
            loop = [a, b]
            c = other.partner(b)
            while c != a:
                b = self.partner(c)
                remain.remove(c)
                loop.append(c)
                remain.remove(b)
                loop.append(b)
                c = other.partner(b)
            yield loop
Beispiel #13
0
    def _build_module_generators(self):
        r"""
        Build the module generators.

        There is only one module generator which corresponds to a single
        `r \times s` rectangle.

        EXAMPLES::

            sage: KRT = KirillovReshetikhinTableaux(['A', 4, 1], 2, 3)
            sage: KRT._build_module_generators()
            ([[1, 1, 1], [2, 2, 2]],)
        """
        tableau = []
        for i in range(self._s):
            tableau.append( [self._r - j for j in range(self._r)] )

        return (self([self.letters(x) for x in flatten(tableau)]),)
    def module_generator(self):
        """
        Return the module generator (or highest weight element) of ``self``.

        The module generator is the unique tableau of shape `(n-1, \ldots, 2,
        1)` with weight `0`.

        EXAMPLES::

            sage: T = crystals.infinity.Tableaux(['D',4])
            sage: T.module_generator()
            [[1, 1, 1], [2, 2], [3]]
        """
        n = self._cartan_type.rank()
        p = Partition([x for x in reversed(range(1, n))])
        # The column canonical tableau, read by columns
        module_generator = flatten([[p[j]-i for i in range(p[j])] for j in range(n-1)])
        return self(list=[self.letters(x) for x in module_generator])
Beispiel #15
0
def generateCode (f, pars):
	'''
	Creates list1 and list 2 from the right side function f of an ODE:
	input: 
		f -> right side function for ODE system
		pars -> list with the parameters on f
	output:
		C code for Automatic Differentiation


	Example with Lorenz Equation
	sage: var('t, x, y, z')		# variables for lorenz equations
	sage: var('s, r, b')		# parameters for lorenz equations
	sage: f(t,x,y,z) = [s*(y-x), x*(r-z) - y, x*y - b*z]	# Right side function for Lorenz equation
	sage: generateCode (f, [s, r, b])

	'''
	list1, list2 = createLists (f, pars)
	removeRepeated (list1, list2)
	constList1, constList2 = removeConstants (list1, list2, pars)
	list3 = createCodeList(list1, list2, constList1, f, pars)
	constList3 = createConstCodeList (constList1, constList2, pars)

	parsedConstList = createParsedConstList (constList3)
	parsedList = createParsedList (list1, list3, f)
	vars = f[0].arguments ()
	auxSet = set(flatten([i.variables() for i in f]))	# set of variables in f
	if set ([vars[0]]).issubset (auxSet):				# non autonomous system
		print '\tdouble T[order];'
		print '\tfor (i=2; i<order; i++) T[i] = 0.0;'
		print '\tT[0] = t;'
		print '\tT[1] = 1.0;'

	if len(list1) > 0:	# checks if there are links
		print '\tdouble l[{}][order];'.format (len (list1))
	if len(constList1) > 0: # checks if there are constant expresions
		print '\tdouble c[{}];'.format (len (constList1))
	for s in parsedConstList:
        	print s
	print '\tfor (i=0; i<order; i++) {'
	for s in parsedList:
		print s
	print '\t}'
    def plot3d(self,depth=None):
        # FIXME: refactor this before publishing
        from sage.plot.graphics import Graphics
        from sage.plot.point import point
        from sage.misc.flatten import flatten
        from sage.plot.plot3d.shapes2 import sphere
        if self._n !=3:
            raise ValueError("Can only 3d plot fans.")
        if depth == None:
            depth = self._depth
        if not self.is_finite() and depth==infinity:
            raise ValueError("For infinite algebras you must specify the depth.")

        colors = dict([(0,'red'),(1,'green'),(2,'blue'),(3,'cyan')])
        G = Graphics()

        roots = self.d_vectors(depth=depth)
        compatible = []
        while roots:
            x = roots.pop()
            for y in roots:
                if self.compatibility_degree(x,y) == 0:
                    compatible.append((x,y))
        for (u,v) in compatible:
            G += _arc3d((_normalize(vector(u)),_normalize(vector(v))),thickness=0.5,color='black')

        for i in range(3):
            orbit = self.ith_orbit(i,depth=depth)
            for j in orbit:
                G += point(_normalize(vector(orbit[j])),color=colors[i],size=10,zorder=len(G.all))

        if self.is_affine():
            tube_vectors=map(vector,flatten(self.affine_tubes()))
            tube_vectors=map(_normalize,tube_vectors)
            for v in tube_vectors:
                G += point(v,color=colors[3],size=10,zorder=len(G.all))
            G += _arc3d((tube_vectors[0],tube_vectors[1]),thickness=5,color='gray',zorder=0)
        
        G += sphere((0,0,0),opacity=0.1,zorder=0)
        G._extra_kwds['frame']=False
        G._extra_kwds['aspect_ratio']=1 
        return G
 def _tube_support(self, alpha):
     gck = self.gamma().associated_coroot()
     if gck.scalar(alpha) != 0:
         raise ValueError("Root not in U_c")
     tubes = list(self.affine_tubes())
     ack = alpha.associated_coroot()
     while tubes:
         tube = tubes.pop()
         if any([ack.scalar(x) != 0 for x in tube[0]]):
             sup_a = []
             roots = flatten(tube)+[0]
             basis = tube[0]
             a = copy(alpha)
             while a != 0:
                 edges = [ x for x in basis if a-x in roots ]
                 sup_a += edges
                 while edges:
                     a = a-edges.pop()
             return tuple(sup_a)
     raise ValueError("Unable to compute support of root")
Beispiel #18
0
    def _build_module_generators(self):
        r"""
        Build the module generators.

        There is only one module generator which corresponds to a single
        `n \times s` rectangle.

        EXAMPLES::

            sage: KRT = KirillovReshetikhinTableaux(['D', 4, 1], 3, 3)
            sage: KRT._build_module_generators()
            ([[1, 1, 1], [2, 2, 2], [3, 3, 3], [-4, -4, -4]],)
        """
        if self._r == self.cartan_type().n:
            return KRTableauxRectangle._build_module_generators(self)

        tableau = []
        for i in range(self._s):
            tableau.append( [-4] + [self._r - j for j in range(self._r)] )

        return (self([self.letters(x) for x in flatten(tableau)]),)
Beispiel #19
0
    def nestings_iterator(self):
        r"""
        INPUT:

            A perfect matching on a *totally ordered* ground set.

        OUTPUT:

            We place the element of a ground set and draw the perfect matching
            by linking the elements of the same pair in the upper
            half-plane. This function returns an iterator over the pairs of
            nesting lines (as a line correspond to a pair, the iterator
            produces pairs of pairs).

        EXAMPLES::

            sage: n = PerfectMatching([(1, 6), (2, 7), (3, 5), (4, 8)])
            sage: it = n.nestings_iterator();
            sage: it.next()
            ((1, 6), (3, 5))
            sage: it.next()
            ((2, 7), (3, 5))
            sage: it.next()
            Traceback (most recent call last):
            ...
            StopIteration
        """
        x = self.value[:]
        if len(x) == 0:
            return
        (i, j) = x.pop(0)
        for (a, b) in x:
            # if (i<a<j<b) or (i<b<j<a) or (j<a<i<b) or (j<b<i<a) or (
            #        a<i<b<j) or (a<j<b<i) or (b<i<a<j) or (b<j<a<i):
            labij = sorted([a, b, i, j])
            posij = sorted([labij.index(i), labij.index(j)])
            if posij == [0, 3] or posij == [1, 2]:
                yield ((i, j), (a, b))
        for nest in PerfectMatchings(flatten(x))(x).nestings_iterator():
            yield nest
Beispiel #20
0
    def face_poset(self):
        r"""
        The face poset of this cell complex, the poset of
        nonempty cells, ordered by inclusion.

        This uses the :meth:`cells` method, and also assumes that for
        each cell ``f``, all of ``f.faces()``, ``tuple(f)``, and
        ``f.dimension()`` make sense.  (If this is not the case in
        some derived class, as happens with `\Delta`-complexes, then
        override this method.)

        EXAMPLES::

            sage: P = SimplicialComplex([[0, 1], [1,2], [2,3]]).face_poset(); P
            Finite poset containing 7 elements
            sage: P.list()
            [(3,), (2,), (2, 3), (1,), (0,), (0, 1), (1, 2)]

            sage: S2 = cubical_complexes.Sphere(2)
            sage: S2.face_poset()
            Finite poset containing 26 elements
        """
        from sage.combinat.posets.posets import Poset
        from sage.misc.flatten import flatten

        covers = {}
        # The code for posets seems to work better if each cell is
        # converted to a tuple.
        all_cells = flatten([list(f) for f in self.cells().values()])

        for C in all_cells:
            if C.dimension() >= 0:
                covers[tuple(C)] = []
        for C in all_cells:
            for face in C.faces():
                if face.dimension() >= 0:
                    covers[tuple(face)].append(tuple(C))
        return Poset(covers)
Beispiel #21
0
def _prepare_coefficient_by_restriction(precision, weight_parity,
                                        relation_precision, S):
    r"""
    Provide input data to ``_coefficient_by_restriction__with_restriction_matrix``.

    INPUT:
    
    - ``precision`` -- A filter for Jacobi forms of arbitrary index.
    
    - ``weight_parity`` -- An integer.
    
    - ``relation_precision`` -- A filter for Jacobi forms.

    - ``S`` -- A list of vectors.
    """
    L = precision.jacobi_index()

    rand = Random()
    max_S_length = max([L(s) for s in S])
    relation_S_pre = flatten(
        L.short_vector_list_up_to_length(max_S_length + 1, True)[1:])
    relation_S = list()
    for _ in range(4 * L.det()):
        s = rand.choice(relation_S_pre)
        if s not in relation_S:
            relation_S.append(s)

    (global_restriction_matrix__big, row_groups, row_labels,
     column_labels) = _global_restriction_matrix(precision, S, weight_parity)
    (global_relation_matrix,
     column_labels_relations) = _global_relation_matrix(
         relation_precision, relation_S, weight_parity)
    global_restriction_matrix__big.change_ring(QQ)
    global_relation_matrix.change_ring(QQ)

    return (global_restriction_matrix__big, row_groups, row_labels,
            column_labels, global_relation_matrix, column_labels_relations)
Beispiel #22
0
    def face_poset(self):
        r"""
        The face poset of this cell complex, the poset of
        nonempty cells, ordered by inclusion.

        This uses the :meth:`cells` method, and also assumes that for
        each cell ``f``, all of ``f.faces()``, ``tuple(f)``, and
        ``f.dimension()`` make sense.  (If this is not the case in
        some derived class, as happens with `\Delta`-complexes, then
        override this method.)

        EXAMPLES::

            sage: P = SimplicialComplex([[0, 1], [1,2], [2,3]]).face_poset(); P
            Finite poset containing 7 elements
            sage: P.list()
            [(3,), (2,), (2, 3), (1,), (1, 2), (0,), (0, 1)]

            sage: S2 = cubical_complexes.Sphere(2)
            sage: S2.face_poset()
            Finite poset containing 26 elements
        """
        from sage.combinat.posets.posets import Poset
        from sage.misc.flatten import flatten
        covers = {}
        # The code for posets seems to work better if each cell is
        # converted to a tuple.
        all_cells = flatten([list(f) for f in self.cells().values()])

        for C in all_cells:
            if C.dimension() >= 0:
                covers[tuple(C)] = []
        for C in all_cells:
            for face in C.faces():
                if face.dimension() >= 0:
                    covers[tuple(face)].append(tuple(C))
        return Poset(covers)
    def module_generator(self, shape):
        """
        This yields the module generator (or highest weight element) of a classical
        crystal of given shape. The module generator is the unique tableau with equal
        shape and content.

        EXAMPLE::

            sage: T = CrystalOfTableaux(['D',3], shape = [1,1])
            sage: T.module_generator([1,1])
            [[1], [2]]

            sage: T = CrystalOfTableaux(['D',4],shape=[2,2,2,-2])
            sage: T.module_generator(tuple([2,2,2,-2]))
            [[1, 1], [2, 2], [3, 3], [-4, -4]]
            sage: T.cardinality()
            294
            sage: T = CrystalOfTableaux(['D',4],shape=[2,2,2,2])
            sage: T.module_generator(tuple([2,2,2,2]))
            [[1, 1], [2, 2], [3, 3], [4, 4]]
            sage: T.cardinality()
            294
        """
        type = self.cartan_type()
        if type[0] == 'D' and len(shape) == type[1] and shape[type[1] - 1] < 0:
            invert = True
            shape = shape[:-1] + (-shape[type[1] - 1], )
        else:
            invert = False
        p = Partition(shape).conjugate()
        # The column canonical tableau, read by columns
        module_generator = flatten([[p[j] - i for i in range(p[j])]
                                    for j in range(len(p))])
        if invert:
            f = lambda x: -x if x == type[1] else x
            module_generator = map(f, module_generator)
        return self(list=[self.letters(x) for x in module_generator])
Beispiel #24
0
def _test__coefficient_by_restriction(precision,
                                      k,
                                      relation_precision=None,
                                      additional_lengths=1):
    r"""
    TESTS::
    
        sage: from psage.modform.jacobiforms.jacobiformd1_fourierexpansion import *
        sage: from psage.modform.jacobiforms.jacobiformd1_fegenerators import _test__coefficient_by_restriction

    ::

        sage: indices = JacobiFormD1Indices(QuadraticForm(matrix(2, [2,1,1,2])))
        sage: precision = indices.filter(10)
        sage: _test__coefficient_by_restriction(precision, 10, additional_lengths = 10)
        
    ::

        sage: indices = JacobiFormD1Indices(QuadraticForm(matrix(2, [4,1,1,2])))
        sage: precision = JacobiFormD1Filter(5, indices.jacobi_index())
        sage: _test__coefficient_by_restriction(precision, 40, additional_lengths = 4) # long test
        
    We use different precisions for relations and restrictions::

        sage: indices = JacobiFormD1Indices(QuadraticForm(matrix(2, [2,1,1,2])))
        sage: precision = indices.filter(20)
        sage: relation_precision = indices.filter(2)
        sage: _test__coefficient_by_restriction(precision, 10, relation_precision, additional_lengths = 4)
    """
    from sage.misc.misc import verbose

    L = precision.jacobi_index()

    if relation_precision is not None and not relation_precision <= precision:
        raise ValueError(
            "Relation precision must be less than or equal to precision.")

    expansions = _coefficient_by_restriction(precision, k, relation_precision)
    verbose(
        "Start testing restrictions of {2} Jacobi forms of weight {0} and index {1}"
        .format(k, L, len(expansions)))

    ch1 = JacobiFormD1WeightCharacter(k)
    chL = JacobiFormD1WeightCharacter(k, L.matrix().nrows())

    R = precision.monoid()._r_representatives
    S_extended = _find_complete_set_of_restriction_vectors(L, R)

    S = list()
    for (s, _) in S_extended:
        if s not in S:
            S.append(s)
    max_S_length = max([L(s) for s in S])

    S = L.short_vector_list_up_to_length(max_S_length + 1 + additional_lengths,
                                         True)[1:]
    Sold = flatten(S[:max_S_length + 1], max_level=1)
    Snew = flatten(S[max_S_length + 1:], max_level=1)
    S = flatten(S, max_level=1)
    verbose("Will use the following restriction vectors: {0}".format(S))

    jacobi_forms_dict = dict()
    non_zero_expansions = list()
    for s in S:
        m = L(s)
        verbose("Restriction to index {0} via {1}".format(m, s))

        try:
            jacobi_forms = jacobi_forms_dict[m]
        except KeyError:
            jacobi_forms = JacobiFormsD1NN(
                QQ, JacobiFormD1NNGamma(k, m),
                JacobiFormD1NNFilter(precision.index(), m))
            jacobi_forms_dict[m] = jacobi_forms
        jacobi_forms_module = span([
            vector(b[(ch1, k)]
                   for k in jacobi_forms.fourier_expansion_precision())
            for b in map(lambda b: b.fourier_expansion(),
                         jacobi_forms.graded_submodule(None).basis())
        ])

        fourier_expansion_module = jacobi_forms.fourier_expansion_ambient()

        for (i, expansion) in enumerate(expansions):
            verbose("Testing restriction of {0}-th form".format(i))
            restricted_expansion_dict = dict()
            for (n, r) in precision.monoid_filter():
                rres = s.dot_product(vector(r))
                try:
                    restricted_expansion_dict[(n, rres)] += expansion[(chL,
                                                                       (n, r))]
                except KeyError:
                    restricted_expansion_dict[(n, rres)] = expansion[(chL,
                                                                      (n, r))]

            restricted_expansion = vector(
                restricted_expansion_dict.get(k, 0)
                for k in jacobi_forms.fourier_expansion_precision())
            if restricted_expansion not in jacobi_forms_module:
                raise RuntimeError(
                    "{0}-th restricted via {1} is not a Jacobi form".format(
                        i, s))

            if restricted_expansion != 0:
                non_zero_expansions.append(i)

    assert Set(non_zero_expansions) == Set(range(len(expansions)))
Beispiel #25
0
    def __classcall_private__(cls, p):
        r"""
        This function tries to recognize the input (it can be either a list or
        a tuple of pairs, or a fix-point free involution given as a list or as
        a permutation), constructs the parent (enumerated set of
        PerfectMatchings of the ground set) and calls the __init__ function to
        construct our object.

        EXAMPLES::

            sage: m=PerfectMatching([('a','e'),('b','c'),('d','f')]);m
            [('a', 'e'), ('b', 'c'), ('d', 'f')]
            sage: isinstance(m,PerfectMatching)
            True
            sage: n=PerfectMatching([3, 8, 1, 7, 6, 5, 4, 2]);n
            [(1, 3), (2, 8), (4, 7), (5, 6)]
            sage: n.parent()
            Set of perfect matchings of {1, 2, 3, 4, 5, 6, 7, 8}
            sage: PerfectMatching([(1, 4), (2, 3), (5, 6)]).is_non_crossing()
            True

        The function checks that the given list or permutation is a valid perfect
        matching (i.e. a list of pairs with pairwise disjoint elements  or a
        fixpoint-free involution) and raises a ValueError otherwise:

            sage: PerfectMatching([(1, 2, 3), (4, 5)])
            Traceback (most recent call last):
            ...
            ValueError: [(1, 2, 3), (4, 5)] is not a valid perfect matching: all elements of the list must be pairs

        If you know your datas are in a good format, use directly
        ``PerfectMatchings(objects)(data)``.

        TESTS::

             sage: m=PerfectMatching([('a','e'),('b','c'),('d','f')])
             sage: TestSuite(m).run()
             sage: m=PerfectMatching([])
             sage: TestSuite(m).run()
             sage: PerfectMatching(6)
             Traceback (most recent call last):
             ...
             ValueError: cannot convert p (= 6) to a PerfectMatching
             sage: PerfectMatching([(1,2,3)])
             Traceback (most recent call last):
             ...
             ValueError: [(1, 2, 3)] is not a valid perfect matching:
             all elements of the list must be pairs
             sage: PerfectMatching([(1,1)])
             Traceback (most recent call last):
             ...
             ValueError: [(1, 1)] is not a valid perfect matching:
             there are some repetitions
             sage: PerfectMatching(Permutation([4,2,1,3]))
             Traceback (most recent call last):
             ...
             ValueError: The permutation p (= [4, 2, 1, 3]) is not a fixed point free involution
        """
        # we have to extract from the argument p the set of objects of the
        # matching and the list of pairs.
        # First case: p is a list (resp tuple) of lists (resp tuple).
        if (isinstance(p, list) or isinstance(p, tuple)) and (all(
            [isinstance(x, list) or isinstance(x, tuple) for x in p])):
            objects = Set(flatten(p))
            data = (map(tuple, p))
            #check if the data are correct
            if not all([len(t) == 2 for t in data]):
                raise ValueError, ("%s is not a valid perfect matching:\n"
                                   "all elements of the list must be pairs" %
                                   p)
            if len(objects) < 2 * len(data):
                raise ValueError, ("%s is not a valid perfect matching:\n"
                                   "there are some repetitions" % p)
        # Second case: p is a permutation or a list of integers, we have to
        # check if it is a fix-point-free involution.
        elif ((isinstance(p, list) and all(
                map(lambda x:
                    (isinstance(x, Integer) or isinstance(x, int)), p)))
              or isinstance(p, Permutation_class)):
            p = Permutation(p)
            n = len(p)
            if not (p.cycle_type() == [2 for i in range(n // 2)]):
                raise ValueError, ("The permutation p (= %s) is not a "
                                   "fixed point free involution" % p)
            objects = Set(range(1, n + 1))
            data = p.to_cycles()
        # Third case: p is already a perfect matching, we return p directly
        elif isinstance(p, PerfectMatching):
            return p
        else:
            raise ValueError, "cannot convert p (= %s) to a PerfectMatching" % p
        # Finally, we create the parent and the element using the element
        # class of the parent. Note: as this function is private, when we
        # create an object via parent.element_class(...), __init__ is directly
        # executed and we do not have an infinite loop.
        return PerfectMatchings(objects)(data)
Beispiel #26
0
def import_statements(*objects, **options):
    """
    Print import statements for the given objects.

    INPUT:

    - ``*objects`` -- a sequence of objects.

    - ``lazy`` -- a boolean (default: ``False``)
      Whether to print a lazy import statement.

    - ``verbose`` -- a boolean (default: ``True``)
      Whether to print information in case of ambiguity.

    EXAMPLES::

        sage: import_statements(WeylGroup, lazy_attribute)
        from sage.combinat.root_system.weyl_group import WeylGroup
        from sage.misc.lazy_attribute import lazy_attribute

        sage: import_statements(IntegerRing)
        from sage.rings.integer_ring import IntegerRing

    If ``lazy`` is True, then :func:`lazy_import` statements are
    displayed instead::

        sage: import_statements(WeylGroup, lazy_attribute, lazy=True)
        from sage.misc.lazy_import import lazy_import
        lazy_import('sage.combinat.root_system.weyl_group', 'WeylGroup')
        lazy_import('sage.misc.lazy_attribute', 'lazy_attribute')

    In principle, the function should also work on object which are instances.
    In case of ambiguity, one or two warning lines are printed::

        sage: import_statements(NN)
        from sage.rings.semirings.non_negative_integer_semiring import NN

        sage: import_statements(ZZ)
          ** Warning **: several names for that object: Z, ZZ
        from sage.rings.integer_ring import Z

        sage: import_statements(euler_phi)
        from sage.rings.arith import euler_phi

        sage: import_statements(x)
          ** Warning **: several modules for that object: sage.all_cmdline, sage.calculus.predefined, sage.interacts.library
        from sage.calculus.predefined import x

    If you don't like the warning you can disable them with the option ``verbose``::

        sage: import_statements(ZZ, verbose=False)
        from sage.rings.integer_ring import Z

        sage: import_statements(x, verbose=False)
        from sage.calculus.predefined import x

    If the object has several names, an other way to get the import
    statement you expect is to use a string instead of the object::

        sage: import_statements(cached_function)
          ** Warning **: several names for that object: CachedFunction, cached_function
        from sage.misc.cachefunc import CachedFunction

        sage: import_statements('cached_function')
        from sage.misc.cachefunc import cached_function
        sage: import_statements('Z')
        from sage.rings.integer_ring import Z

    Specifying a string is also useful for objects that are not
    imported in the Sage interpreter namespace by default. In this
    case, an object with that name is looked up in all the modules
    that have been imported in this session::

        sage: print_import_statement
        Traceback (most recent call last):
        ...
        NameError: name 'print_import_statement' is not defined

        sage: import_statements("print_import_statement")
        from sage.misc.dev_tools import print_import_statement

    We test different object which have no appropriate answer::

        sage: import_statements('my_tailor_is_rich')
        Traceback (most recent call last):
        ...
        ValueError: no import statement for my_tailor_is_rich
        sage: import_statements(5)
        Traceback (most recent call last):
        ...
        ValueError: no import statement for 5
    """
    import inspect, sys, re
    import sage.all
    from sage.misc import sageinspect
    from sage.misc.flatten import flatten

    lazy = options.get("lazy", False)
    verbose = options.get("verbose", True)
    if lazy:
        print "from sage.misc.lazy_import import lazy_import"

    for obj in objects:
        # if obj is a string use it has a name and look for an object
        if isinstance(obj, str):
            name = obj
            if name in sage.all.__dict__:
                obj = sage.all.__dict__[name]
            else:
                # Look for the first module which contains that name.
                # TODO: improve this heuristic.
                for module in sys.modules.values():
                    if hasattr(module, '__dict__') and name in module.__dict__:
                        obj = module.__dict__[name]
                        break
        else:
            name = None

        # Case 1: the object is a module
        if inspect.ismodule(obj):
            if lazy:
                print "lazy_import('%s')" % obj.__name__
            else:
                print "import %s" % obj.__name__
            continue

        # Case 2: the object is defined in its module
        module = None
        if sageinspect.isclassinstance(obj):
            module = obj.__class__.__module__
        elif hasattr(obj, '__module__') and obj.__module__:
            module = obj.__module__

        if module:
            d = sys.modules[module].__dict__
            if name is None:
                names = sorted(key for key in d if d[key] is obj)
            else:
                names = [name]
            if names:
                if verbose and len(names) > 1:
                    print "  ** Warning **: several names for that object: %s" % ', '.join(
                        names)
                print_import_statement(module, names[0], lazy)
                continue

        # Case 3: search for this object in all modules
        names = {}  # dictionnary: module -> names of the object in that module
        for module in sys.modules:
            if module != '__main__' and hasattr(sys.modules[module],
                                                '__dict__'):
                d = sys.modules[module].__dict__

                if name is not None:
                    if name in d and d[name] is obj:
                        names[module] = name
                else:
                    n = [key for key in d if d[key] is obj]
                    if n:
                        names[module] = n

        all_names = sorted(set(flatten(names.values())))
        if len(all_names) == 0:
            raise ValueError("no import statement for %s" % obj)
        elif verbose and len(all_names) > 1:
            print "  ** Warning **: several names for that object:",
            print ", ".join(sorted(all_names))

        modules = sorted(flatten(names), cmp=module_names_cmp)
        if verbose and len(modules) > 1:
            print "  ** Warning **: several modules for that object:",
            print ", ".join(modules[:4]),
            if len(modules) > 4:
                print "..."
            else:
                print

        # Case 4: if the object is a class instance, we look for a
        # module where it is instanciated
        if sageinspect.isclassinstance(obj):
            names_pattern = dict(
                (name, re.compile("^%s\ *=" % name, re.MULTILINE))
                for name in all_names)

            for module in modules:
                sources = sageinspect.sage_getsource(sys.modules[module])
                for name in names[module]:
                    if names_pattern[name].search(sources):
                        break
                else:
                    continue
                break
        else:
            module = modules[0]
            name = names[module][0]

        if name is not None:
            print_import_statement(module, name, lazy)
        else:
            raise ValueError("no import statement for %s" % obj)
    def plot_cluster_fan_stereographically(self,
                                           northsign=1,
                                           north=None,
                                           right=None,
                                           colors=None,
                                           d_vectors=False):
        from sage.plot.graphics import Graphics
        from sage.plot.point import point
        from sage.misc.flatten import flatten
        from sage.plot.line import line
        from sage.misc.functional import norm

        if self.rk != 3:
            raise ValueError("Can only stereographically project fans in 3d.")
        if not self.is_finite() and self._depth == infinity:
            raise ValueError(
                "For infinite algebras you must specify the depth.")

        if north == None:
            if self.is_affine():
                north = vector(self.delta())
            else:
                north = vector((-1, -1, -1))
        if right == None:
            if self.is_affine():
                right = vector(self.gamma())
            else:
                right = vector((1, 0, 0))
        if colors == None:
            colors = dict([(0, 'red'), (1, 'green'), (2, 'blue'), (3, 'cyan'),
                           (4, 'yellow')])
        G = Graphics()

        roots = list(self.g_vectors())
        compatible = []
        while roots:
            x = roots.pop()
            if x in self.initial_cluster() and d_vectors:
                x1 = -self.simple_roots()[list(
                    self.initial_cluster()).index(x)]
            else:
                x1 = x
            for y in roots:
                if self.compatibility_degree(x, y) == 0:
                    if y in self.initial_cluster() and d_vectors:
                        y1 = -self.simple_roots()[list(
                            self.initial_cluster()).index(y)]
                    else:
                        y1 = y
                    compatible.append((x1, y1))
        for (u, v) in compatible:
            G += _stereo_arc(vector(u),
                             vector(v),
                             vector(u + v),
                             north=northsign * north,
                             right=right,
                             thickness=0.5,
                             color='black')

        for i in range(3):
            orbit = self.ith_orbit(i)
            if d_vectors:
                orbit[0] = -self.simple_roots()[list(
                    self.initial_cluster()).index(orbit[0])]
            for j in orbit:
                G += point(_stereo_coordinates(vector(orbit[j]),
                                               north=northsign * north,
                                               right=right),
                           color=colors[i],
                           zorder=len(G))

        if self.is_affine():
            tube_vectors = map(vector, flatten(self.affine_tubes()))
            for v in tube_vectors:
                G += point(_stereo_coordinates(v,
                                               north=northsign * north,
                                               right=right),
                           color=colors[3],
                           zorder=len(G))
            if north != vector(self.delta()):
                G += _stereo_arc(tube_vectors[0],
                                 tube_vectors[1],
                                 vector(self.delta()),
                                 north=northsign * north,
                                 right=right,
                                 thickness=2,
                                 color=colors[4],
                                 zorder=0)
            else:
                # FIXME: refactor this before publishing
                tube_projections = [
                    _stereo_coordinates(v,
                                        north=northsign * north,
                                        right=right) for v in tube_vectors
                ]
                t = min(
                    (G.get_minmax_data()['xmax'], G.get_minmax_data()['ymax']))
                G += line([
                    tube_projections[0], tube_projections[0] + t *
                    (_normalize(tube_projections[0] - tube_projections[1]))
                ],
                          thickness=2,
                          color=colors[4],
                          zorder=0)
                G += line([
                    tube_projections[1], tube_projections[1] + t *
                    (_normalize(tube_projections[1] - tube_projections[0]))
                ],
                          thickness=2,
                          color=colors[4],
                          zorder=0)
        G.set_aspect_ratio(1)
        G._show_axes = False
        return G
    def cluster_expansion(self, beta):
        if beta == 0:
            return dict()

        coefficients = beta.monomial_coefficients()
        if any(x < 0 for x in coefficients.values()):
            alpha = [-x for x in self.initial_cluster()]
            negative_part = dict([(-alpha[x], -coefficients[x])
                                  for x in coefficients
                                  if coefficients[x] < 0])
            positive_part = sum([
                coefficients[x] * alpha[x] for x in coefficients
                if coefficients[x] > 0
            ])
            return dict(negative_part.items() +
                        self.cluster_expansion(positive_part).items())

        if self.is_affine():
            if self.gamma().associated_coroot().scalar(beta) < 0:
                shifted_expansion = self.cluster_expansion(self.tau_c()(beta))
                return dict([(self.tau_c_inverse()(x), shifted_expansion[x])
                             for x in shifted_expansion])
            elif self.gamma().associated_coroot().scalar(beta) > 0:
                shifted_expansion = self.cluster_expansion(
                    self.tau_c_inverse()(beta))
                return dict([(self.tau_c()(x), shifted_expansion[x])
                             for x in shifted_expansion])
            else:
                ###
                # Assumptions
                #
                # Two cases are possible for vectors in the interior of the cone
                # according to how many tubes there are:
                # 1) If there is only one tube then its extremal rays are linearly
                # independent, therefore a point is in the interior of the cone
                # if and only if it is a linear combination of all the extremal
                # rays with strictly positive coefficients. In this case solve()
                # should produce only one solution.
                # 2) If there are two or three tubes then the extreme rays are
                # linearly dependent. A vector is in the interior of the cone if
                # and only if it can be written as a strictly positive linear
                # combination of all the rays of at least one tube. In this case
                # solve() should return at least two solutions.
                #
                # If a vector is on one face of the cone than it can be written
                # uniquely as linear combination of the rays of that face (they
                # are linearly independent). solve() should return only one
                # solution no matter how many tubes there are.

                rays = flatten([t[0] for t in self.affine_tubes()])
                system = matrix(map(vector, rays)).transpose()
                x = vector(var(['x%d' % i for i in range(len(rays))]))
                eqs = [(system * x)[i] == vector(beta)[i]
                       for i in range(self._n)]
                ieqs = [y >= 0 for y in x]
                solutions = solve(eqs + ieqs, x, solution_dict=True)

                if not solutions:
                    # we are outside the cone
                    shifted_expansion = self.cluster_expansion(
                        self.tau_c()(beta))
                    return dict([(self.tau_c_inverse()(v),
                                  shifted_expansion[v])
                                 for v in shifted_expansion])

                if len(solutions) > 1 or all(v > 0
                                             for v in solutions[0].values()):
                    # we are in the interior of the cone
                    raise ValueError("Vectors in the interior of the cone do "
                                     "not have a cluster expansion")

                # we are on the boundary of the cone
                solution_dict = dict([(rays[i], solutions[0][x[i]])
                                      for i in range(len(rays))])
                tube_bases = [t[0] for t in self.affine_tubes()]
                connected_components = []
                index = 0
                for t in tube_bases:
                    component = []
                    for a in t:
                        if solution_dict[a] == 0:
                            if component:
                                connected_components.append(component)
                                component = []
                        else:
                            component.append((a, solution_dict[a]))
                    if component:
                        if connected_components:
                            connected_components[index] = (
                                component + connected_components[index])
                        else:
                            connected_components.append(component)
                    index = len(connected_components)
                expansion = dict()
                while connected_components:
                    component = connected_components.pop()
                    c = min([a[1] for a in component])
                    expansion[sum([a[0] for a in component])] = c
                    component = [(a[0], a[1] - c) for a in component]
                    new_component = []
                    for a in component:
                        if a[1] == 0:
                            if new_component:
                                connected_components.append(new_component)
                                new_component = []
                        else:
                            new_component.append(a)
                    if new_component:
                        connected_components.append(new_component)
                return expansion

        if self.is_finite():
            shifted_expansion = self.cluster_expansion(self.tau_c()(beta))
            return dict([(self.tau_c_inverse()(x), shifted_expansion[x])
                         for x in shifted_expansion])
Beispiel #29
0
def Polyhedron(vertices=None,
               rays=None,
               lines=None,
               ieqs=None,
               eqns=None,
               ambient_dim=None,
               base_ring=None,
               minimize=True,
               verbose=False,
               backend=None,
               mutable=False):
    r"""
    Construct a polyhedron object.

    You may either define it with vertex/ray/line or
    inequalities/equations data, but not both. Redundant data will
    automatically be removed (unless ``minimize=False``), and the
    complementary representation will be computed.

    INPUT:

    - ``vertices`` -- list of points. Each point can be specified as
      any iterable container of ``base_ring`` elements. If ``rays`` or
      ``lines`` are specified but no ``vertices``, the origin is
      taken to be the single vertex.

    - ``rays`` -- list of rays. Each ray can be specified as any
      iterable container of ``base_ring`` elements.

    - ``lines`` -- list of lines. Each line can be specified as any
      iterable container of ``base_ring`` elements.

    - ``ieqs`` -- list of inequalities. Each line can be specified as any
      iterable container of ``base_ring`` elements. An entry equal to
      ``[-1,7,3,4]`` represents the inequality `7x_1+3x_2+4x_3\geq 1`.

    - ``eqns`` -- list of equalities. Each line can be specified as
      any iterable container of ``base_ring`` elements. An entry equal to
      ``[-1,7,3,4]`` represents the equality `7x_1+3x_2+4x_3= 1`.

    - ``base_ring`` -- a sub-field of the reals implemented in
      Sage. The field over which the polyhedron will be defined. For
      ``QQ`` and algebraic extensions, exact arithmetic will be
      used. For ``RDF``, floating point numbers will be used. Floating
      point arithmetic is faster but might give the wrong result for
      degenerate input.

    - ``ambient_dim`` -- integer. The ambient space dimension. Usually
      can be figured out automatically from the H/Vrepresentation
      dimensions.

    - ``backend`` -- string or ``None`` (default). The backend to use. Valid choices are

      * ``'cdd'``: use cdd
        (:mod:`~sage.geometry.polyhedron.backend_cdd`) with `\QQ` or
        `\RDF` coefficients depending on ``base_ring``

      * ``'normaliz'``: use normaliz
        (:mod:`~sage.geometry.polyhedron.backend_normaliz`) with `\ZZ` or
        `\QQ` coefficients depending on ``base_ring``

      * ``'polymake'``: use polymake
        (:mod:`~sage.geometry.polyhedron.backend_polymake`) with `\QQ`, `\RDF` or
        ``QuadraticField`` coefficients depending on ``base_ring``

      * ``'ppl'``: use ppl
        (:mod:`~sage.geometry.polyhedron.backend_ppl`) with `\ZZ` or
        `\QQ` coefficients depending on ``base_ring``

      * ``'field'``: use python implementation
        (:mod:`~sage.geometry.polyhedron.backend_field`) for any field

    Some backends support further optional arguments:

    - ``minimize`` -- boolean (default: ``True``); whether to
      immediately remove redundant H/V-representation data; currently
      not used.

    - ``verbose`` -- boolean (default: ``False``); whether to print
      verbose output for debugging purposes; only supported by the cdd and
      normaliz backends

    - ``mutable`` -- boolean (default: ``False``); whether the polyhedron
      is mutable

    OUTPUT:

    The polyhedron defined by the input data.

    EXAMPLES:

    Construct some polyhedra::

        sage: square_from_vertices = Polyhedron(vertices = [[1, 1], [1, -1], [-1, 1], [-1, -1]])
        sage: square_from_ieqs = Polyhedron(ieqs = [[1, 0, 1], [1, 1, 0], [1, 0, -1], [1, -1, 0]])
        sage: list(square_from_ieqs.vertex_generator())
        [A vertex at (1, -1),
         A vertex at (1, 1),
         A vertex at (-1, 1),
         A vertex at (-1, -1)]
        sage: list(square_from_vertices.inequality_generator())
        [An inequality (1, 0) x + 1 >= 0,
         An inequality (0, 1) x + 1 >= 0,
         An inequality (-1, 0) x + 1 >= 0,
         An inequality (0, -1) x + 1 >= 0]
        sage: p = Polyhedron(vertices = [[1.1, 2.2], [3.3, 4.4]], base_ring=RDF)
        sage: p.n_inequalities()
        2

    The same polyhedron given in two ways::

        sage: p = Polyhedron(ieqs = [[0,1,0,0],[0,0,1,0]])
        sage: p.Vrepresentation()
        (A line in the direction (0, 0, 1),
         A ray in the direction (1, 0, 0),
         A ray in the direction (0, 1, 0),
         A vertex at (0, 0, 0))
        sage: q = Polyhedron(vertices=[[0,0,0]], rays=[[1,0,0],[0,1,0]], lines=[[0,0,1]])
        sage: q.Hrepresentation()
        (An inequality (1, 0, 0) x + 0 >= 0,
         An inequality (0, 1, 0) x + 0 >= 0)

    Finally, a more complicated example. Take `\mathbb{R}_{\geq 0}^6` with
    coordinates `a, b, \dots, f` and

      * The inequality `e+b \geq c+d`
      * The inequality `e+c \geq b+d`
      * The equation `a+b+c+d+e+f = 31`

    ::

        sage: positive_coords = Polyhedron(ieqs=[
        ....:     [0, 1, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0],
        ....:     [0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 1]])
        sage: P = Polyhedron(ieqs=positive_coords.inequalities() + (
        ....:     [0,0,1,-1,-1,1,0], [0,0,-1,1,-1,1,0]), eqns=[[-31,1,1,1,1,1,1]])
        sage: P
        A 5-dimensional polyhedron in QQ^6 defined as the convex hull of 7 vertices
        sage: P.dim()
        5
        sage: P.Vrepresentation()
        (A vertex at (31, 0, 0, 0, 0, 0), A vertex at (0, 0, 0, 0, 0, 31),
         A vertex at (0, 0, 0, 0, 31, 0), A vertex at (0, 0, 31/2, 0, 31/2, 0),
         A vertex at (0, 31/2, 31/2, 0, 0, 0), A vertex at (0, 31/2, 0, 0, 31/2, 0),
         A vertex at (0, 0, 0, 31/2, 31/2, 0))

    Regular icosahedron, centered at `0` with edge length `2`, with vertices given
    by the cyclic shifts of `(0, \pm 1, \pm (1+\sqrt(5))/2)`, cf.
    :wikipedia:`Regular_icosahedron`. It needs a number field::

        sage: R0.<r0> = QQ[]                                                    # optional - sage.rings.number_field
        sage: R1.<r1> = NumberField(r0^2-5, embedding=AA(5)**(1/2))             # optional - sage.rings.number_field
        sage: gold = (1+r1)/2                                                   # optional - sage.rings.number_field
        sage: v = [[0, 1, gold], [0, 1, -gold], [0, -1, gold], [0, -1, -gold]]  # optional - sage.rings.number_field
        sage: pp = Permutation((1, 2, 3))          # optional - sage.combinat   # optional - sage.rings.number_field
        sage: icosah = Polyhedron(                 # optional - sage.combinat   # optional - sage.rings.number_field
        ....:    [(pp^2).action(w) for w in v] + [pp.action(w) for w in v] + v,
        ....:    base_ring=R1)
        sage: len(icosah.faces(2))                 # optional - sage.combinat   # optional - sage.rings.number_field
        20

    When the input contains elements of a Number Field, they require an
    embedding::

        sage: K = NumberField(x^2-2,'s')                                        # optional - sage.rings.number_field
        sage: s = K.0                                                           # optional - sage.rings.number_field
        sage: L = NumberField(x^3-2,'t')                                        # optional - sage.rings.number_field
        sage: t = L.0                                                           # optional - sage.rings.number_field
        sage: P = Polyhedron(vertices = [[0,s],[t,0]])                          # optional - sage.rings.number_field
        Traceback (most recent call last):
        ...
        ValueError: invalid base ring

    Create a mutable polyhedron::

        sage: P = Polyhedron(vertices=[[0, 1], [1, 0]], mutable=True)
        sage: P.is_mutable()
        True
        sage: hasattr(P, "_Vrepresentation")
        False
        sage: P.Vrepresentation()
        (A vertex at (0, 1), A vertex at (1, 0))
        sage: hasattr(P, "_Vrepresentation")
        True

    .. NOTE::

      * Once constructed, a ``Polyhedron`` object is immutable.

      * Although the option ``base_ring=RDF`` allows numerical data to
        be used, it might not give the right answer for degenerate
        input data - the results can depend upon the tolerance
        setting of cdd.


    TESTS:

    Check that giving ``float`` input gets converted to ``RDF`` (see :trac:`22605`)::

        sage: f = float(1.1)
        sage: Polyhedron(vertices=[[f]])
        A 0-dimensional polyhedron in RDF^1 defined as the convex hull of 1 vertex

    Check that giving ``int`` input gets converted to ``ZZ`` (see :trac:`22605`)::

        sage: Polyhedron(vertices=[[int(42)]])
        A 0-dimensional polyhedron in ZZ^1 defined as the convex hull of 1 vertex

    Check that giving ``Fraction`` input gets converted to ``QQ`` (see :trac:`22605`)::

        sage: from fractions import Fraction
        sage: f = Fraction(int(6), int(8))
        sage: Polyhedron(vertices=[[f]])
        A 0-dimensional polyhedron in QQ^1 defined as the convex hull of 1 vertex

    Check that non-compact polyhedra given by V-representation have base ring ``QQ``,
    not ``ZZ`` (see :trac:`27840`)::

        sage: Q = Polyhedron(vertices=[(1, 2, 3), (1, 3, 2), (2, 1, 3),
        ....:                          (2, 3, 1), (3, 1, 2), (3, 2, 1)],
        ....:                rays=[[1, 1, 1]], lines=[[1, 2, 3]], backend='ppl')
        sage: Q.base_ring()
        Rational Field

    Check that enforcing base ring `ZZ` for this example gives an error::

        sage: Q = Polyhedron(vertices=[(1, 2, 3), (1, 3, 2), (2, 1, 3),
        ....:                          (2, 3, 1), (3, 1, 2), (3, 2, 1)],
        ....:                rays=[[1, 1, 1]], lines=[[1, 2, 3]], backend='ppl',
        ....:                base_ring=ZZ)
        Traceback (most recent call last):
        ...
        TypeError: no conversion of this rational to integer

    Check that input with too many bits of precision returns an error (see
    :trac:`22552`)::

        sage: Polyhedron(vertices=[(8.3319544851638732, 7.0567045956967727), (6.4876921900819049, 4.8435898415984129)])
        Traceback (most recent call last):
        ...
        ValueError: the only allowed inexact ring is 'RDF' with backend 'cdd'

    Check that setting ``base_ring`` to a ``RealField`` returns an error (see :trac:`22552`)::

        sage: Polyhedron(vertices =[(8.3, 7.0), (6.4, 4.8)], base_ring=RealField(40))
        Traceback (most recent call last):
        ...
        ValueError: no default backend for computations with Real Field with 40 bits of precision
        sage: Polyhedron(vertices =[(8.3, 7.0), (6.4, 4.8)], base_ring=RealField(53))
        Traceback (most recent call last):
        ...
        ValueError: no default backend for computations with Real Field with 53 bits of precision

    Check that :trac:`17339` is fixed::

        sage: Polyhedron(ambient_dim=0, ieqs=[], eqns=[[1]], base_ring=QQ)
        The empty polyhedron in QQ^0
        sage: P = Polyhedron(ambient_dim=0, ieqs=[], eqns=[], base_ring=QQ); P
        A 0-dimensional polyhedron in QQ^0 defined as the convex hull of 1 vertex
        sage: P.Vrepresentation()
        (A vertex at (),)
        sage: Polyhedron(ambient_dim=2, ieqs=[], eqns=[], base_ring=QQ)
        A 2-dimensional polyhedron in QQ^2 defined as the convex hull
         of 1 vertex and 2 lines
        sage: Polyhedron(ambient_dim=2, ieqs=[], eqns=[], base_ring=QQ, backend='field')
        A 2-dimensional polyhedron in QQ^2 defined as the convex hull
         of 1 vertex and 2 lines
        sage: Polyhedron(ambient_dim=0, ieqs=[], eqns=[[1]], base_ring=QQ, backend="cdd")
        The empty polyhedron in QQ^0
        sage: Polyhedron(ambient_dim=0, ieqs=[], eqns=[[1]], base_ring=QQ, backend="ppl")
        The empty polyhedron in QQ^0
        sage: Polyhedron(ambient_dim=0, ieqs=[], eqns=[[1]], base_ring=QQ, backend="field")
        The empty polyhedron in QQ^0

        sage: Polyhedron(ambient_dim=2, vertices=[], rays=[], lines=[], base_ring=QQ)
        The empty polyhedron in QQ^2

    .. SEEALSO::

        :mod:`Library of polytopes <sage.geometry.polyhedron.library>`
    """
    got_Vrep = not ((vertices is None) and (rays is None) and (lines is None))
    got_Hrep = not ((ieqs is None) and (eqns is None))

    # Clean up the arguments
    vertices = _make_listlist(vertices)
    rays = _make_listlist(rays)
    lines = _make_listlist(lines)
    ieqs = _make_listlist(ieqs)
    eqns = _make_listlist(eqns)

    if got_Vrep and got_Hrep:
        raise ValueError('cannot specify both H- and V-representation.')
    elif got_Vrep:
        deduced_ambient_dim = _common_length_of(vertices, rays, lines)[1]
        if deduced_ambient_dim is None:
            if ambient_dim is not None:
                deduced_ambient_dim = ambient_dim
            else:
                deduced_ambient_dim = 0
    elif got_Hrep:
        deduced_ambient_dim = _common_length_of(ieqs, eqns)[1]
        if deduced_ambient_dim is None:
            if ambient_dim is not None:
                deduced_ambient_dim = ambient_dim
            else:
                deduced_ambient_dim = 0
        else:
            deduced_ambient_dim -= 1
    else:
        if ambient_dim is None:
            deduced_ambient_dim = 0
        else:
            deduced_ambient_dim = ambient_dim
        if base_ring is None:
            base_ring = ZZ

    # set ambient_dim
    if ambient_dim is not None and deduced_ambient_dim != ambient_dim:
        raise ValueError(
            'ambient space dimension mismatch. Try removing the "ambient_dim" parameter.'
        )
    ambient_dim = deduced_ambient_dim

    # figure out base_ring
    from sage.misc.flatten import flatten
    from sage.structure.element import parent
    from sage.categories.fields import Fields
    from sage.categories.rings import Rings

    values = flatten(vertices + rays + lines + ieqs + eqns)
    if base_ring is not None:
        convert = any(parent(x) is not base_ring for x in values)
    elif not values:
        base_ring = ZZ
        convert = False
    else:
        P = parent(values[0])
        if any(parent(x) is not P for x in values):
            from sage.structure.sequence import Sequence
            P = Sequence(values).universe()
            convert = True
        else:
            convert = False

        from sage.structure.coerce import py_scalar_parent
        if isinstance(P, type):
            base_ring = py_scalar_parent(P)
            convert = convert or P is not base_ring
        else:
            base_ring = P

        if base_ring not in Fields():
            got_compact_Vrep = got_Vrep and not rays and not lines
            got_cone_Vrep = got_Vrep and all(
                all(x == 0 for x in v) for v in vertices)
            if not got_compact_Vrep and not got_cone_Vrep:
                base_ring = base_ring.fraction_field()
                convert = True

        if base_ring not in Rings():
            raise ValueError('invalid base ring')

        try:
            from sage.symbolic.ring import SR
        except ImportError:
            SR = None
        if base_ring is not SR and not base_ring.is_exact():
            # TODO: remove this hack?
            if base_ring is RR:
                base_ring = RDF
                convert = True
            elif base_ring is not RDF:
                raise ValueError(
                    "the only allowed inexact ring is 'RDF' with backend 'cdd'"
                )

    # Add the origin if necessary
    if got_Vrep and len(vertices) == 0 and len(rays + lines) > 0:
        vertices = [[0] * ambient_dim]

    # Specific backends can override the base_ring
    from sage.geometry.polyhedron.parent import Polyhedra
    parent = Polyhedra(base_ring, ambient_dim, backend=backend)
    base_ring = parent.base_ring()

    # finally, construct the Polyhedron
    Hrep = Vrep = None
    if got_Hrep:
        Hrep = [ieqs, eqns]
    if got_Vrep:
        Vrep = [vertices, rays, lines]
    return parent(Vrep,
                  Hrep,
                  convert=convert,
                  verbose=verbose,
                  mutable=mutable)
Beispiel #30
0
    def normalize(self):
        r"""
        Return an equivalent graph such that the enumeration of its darts
        exhausts all numbers from 1 to the number of darts.

        OUTPUT:

        - a ribbon graph equivalent to ``self`` such that the enumeration
          of its darts exhausts all numbers from 1 to the number of darts.

        EXAMPLES::

            sage: s0 = PermutationGroupElement('(1,22,3,4,5,6,7,15)(8,16,9,10,11,12,13,14)')
            sage: r0 = PermutationGroupElement('(1,8)(22,9)(3,10)(4,11)(5,12)(6,13)(7,14)(15,16)')
            sage: R0 = RibbonGraph(s0,r0); R0
            Ribbon graph of genus 3 and 2 boundary components
            sage: RN0 = R0.normalize(); RN0; RN0.sigma(); RN0.rho()
            Ribbon graph of genus 3 and 2 boundary components
            (1,16,2,3,4,5,6,14)(7,15,8,9,10,11,12,13)
            (1,7)(2,9)(3,10)(4,11)(5,12)(6,13)(8,16)(14,15)

            sage: s1 = PermutationGroupElement('(5,10,12)(30,34,78)')
            sage: r1 = PermutationGroupElement('(5,30)(10,34)(12,78)')
            sage: R1 = RibbonGraph(s1,r1); R1
            Ribbon graph of genus 1 and 1 boundary components
            sage: RN1 = R1.normalize(); RN1; RN1.sigma(); RN1.rho()
            Ribbon graph of genus 1 and 1 boundary components
            (1,2,3)(4,5,6)
            (1,4)(2,5)(3,6)

        """
        #First we compute the vertices of valency 1 and store them in val_one.
        aux_sigma = [list(x) for x in self._sigma.cycle_tuples()]
        aux_rho = [list(x) for x in self._rho.cycle_tuples()]
        darts_rho = flatten(aux_rho)
        darts_sigma = flatten(aux_sigma)
        val_one = [x for x in darts_rho if x not in darts_sigma]

        #We add them to aux_sigma
        for i in range(len(val_one)):
            aux_sigma += [[val_one[i]]]
        #Now we proceed to normalize the numbers enumerating the darts.
        #We do this by checking if every number from 1 to len(darts_rho)
        #is actually in darts_rho.
        for i in range(len(darts_rho)):
            found = i + 1 in darts_rho
            #if a value is not in darts_rho, we take the next number that appears
            #and change it to the new value.
            if not found:
                aux_val = min(x for x in darts_rho if x > i + 1)
                pos_darts = darts_rho.index(aux_val)
                pos_rho = _find(aux_rho, aux_val)
                pos_sigma = _find(aux_sigma, aux_val)

                #Now we set the found positions to the new normalized value
                darts_rho[pos_darts] = i + 1
                aux_sigma[pos_sigma[0]][pos_sigma[1]] = i + 1
                aux_rho[pos_rho[0]][pos_rho[1]] = i + 1

        return RibbonGraph(
            PermutationGroupElement([tuple(x) for x in aux_sigma]),
            PermutationGroupElement([tuple(x) for x in aux_rho]))
Beispiel #31
0
def createLists(f, pars):
    '''
	Creates list1 and list 2 from the right side function f of an ODE:
	input: 
		f -> right side function for ODE system
		pars -> list with the parameters on f
	output:
		list1 and list2


	Example with Lorenz Equation
	sage: var('t, x, y, z')		# variables for lorenz equations
	sage: var('s, r, b')		# parameters for lorenz equations
	sage: f(t,x,y,z) = [s*(y-x), x*(r-z) - y, x*y - b*z]	# Right side function for Lorenz equation

	'''
    vars = f[0].arguments()  # gets the list of variables from function f
    varpar = list(vars) + list(pars)  # gets the list of vars and pars totegher
    _f = f(*vars).function(
        varpar)  # _f is f but with vars and pars as arguments

    fastCallList = flatten(
        [fast_callable(i, vars=varpar).op_list() for i in f], max_level=1)
    # This list is the fast callable version of f using a stack-mode call
    '''
	We create create the lists list1, list2 and stack.
	stack will be expresion stack-list

	'''
    list1 = []
    list2 = []
    stack = []
    '''
	Starts parser on fastCallList. 
	'''
    for s in fastCallList:
        if s[0] == 'load_arg':  # Loads a variable in stack. no changes on list1, or list2
            stack.append(varpar[
                s[1]])  # appends the variable or parameter on symbolic stack

        elif s[0] == 'ipow':  # Integer power.
            if s[1] in NN:  # If natural, parser as products
                basis = stack[-1]
                for j in range(s[1] - 1):
                    a = stack.pop(-1)
                    stack.append(a * basis)
                    list1.append(stack[-1])
                    list2.append(('mul', a, basis))
            elif -s[1] in NN:
                basis = stack[-1]
                for j in range(-s[1] - 1):
                    a = stack.pop(-1)
                    stack.append(a * basis)
                    list1.append(stack[-1])
                    list2.append(('mul', a, basis))
                a = stack.pop(-1)
                stack.append(1 / a)
                list1.append(stack[-1])
                list2.append(('div', 1, a))
            else:  # Attach as normal power
                a = stack.pop(-1)  #basis
                stack.append(a**s[1])
                list1.append(stack[-1])
                list2.append(('pow', a, s[1]))

        elif s[0] == 'load_const':  # Loads a constant value on stack. Not in list1 or list2
            stack.append(s[1])

        elif s == 'neg':  # multiplies by -1.0
            a = stack.pop(-1)  # expresion to be multiplied by -1
            stack.append(-a)
            list1.append(stack[-1])
            list2.append(('mul', -1, a))

        elif s == 'mul':  # Product
            a = stack.pop(-1)
            b = stack.pop(-1)
            list2.append(('mul', a, b))
            stack.append(a * b)
            list1.append(stack[-1])

        elif s == 'div':  # divission Numerator First.
            b = stack.pop(-1)  # denominator (after a in stack)
            a = stack.pop(-1)  # numerator (before b in stack)
            if expresionIsConstant(b, pars):
                list1.append(1 / b)
                list2.append(('div', 1, b))
                b = 1 / b
                stack.append(a * b)
                list1.append(stack[-1])
                list2.append(('mul', a, b))
            else:
                list2.append(('div', a, b))
                stack.append(a / b)
                list1.append(stack[-1])

        elif s == 'add':  # addition
            b = stack.pop(-1)  # second operand
            a = stack.pop(-1)  # first operand
            stack.append(a + b)
            list1.append(stack[-1])
            list2.append(('add', a, b))

        elif s == 'pow':  # any other pow
            b = stack.pop(-1)  # exponent
            a = stack.pop(-1)  # basis
            stack.append(a**b)
            list1.append(stack[-1])
            list2.append(('pow', a, b))

        elif s[0] == 'py_call' and 'sqrt' in str(
                s[1]):  # square root. Compute as power
            a = stack.pop(-1)  # argument of sqrt
            stack.append(sqrt(a))
            list1.append(stack[-1])
            list2.append(('pow', a, 0.5))

        elif s[0] == 'py_call' and str(s[1]) == 'log':  # logarithm
            a = stack.pop(-1)
            # argument of log
            stack.append(log(a))
            list1.append(stack[-1])
            list2.append(('log', a))

        elif s[0] == 'py_call' and str(s[1]) == 'exp':
            a = stack.pop(-1)
            # argument of exp
            stack.append(exp(a))
            list1.append(stack[-1])
            list2.append(('exp', a))

        elif s[0] == 'py_call' and str(
                s[1]) == 'sin':  # sine. For AD needs computation of cos
            a = stack.pop(-1)
            stack.append(sin(a))
            list1.append(sin(a))
            list1.append(cos(a))
            list2.append(('sin', a))
            list2.append(('cos', a))

        elif s[0] == 'py_call' and str(
                s[1]) == 'cos':  # cosine. For AD needs computation of sin
            a = stack.pop(-1)
            stack.append(cos(a))
            list1.append(sin(a))
            list1.append(cos(a))
            list2.append(('sin', a))
            list2.append(('cos', a))
        elif s[0] == 'py_call' and str(s[1]) == 'tan':
            a = stack.pop(-1)
            stack.append(tan(a))
            list1.append(sin(a))
            list1.append(cos(a))
            list1.append(tan(a))
            list2.append(('sin', a))
            list2.append(('cos', a))
            list2.append(('div', sin(a), cos(a)))

    return list1, list2
Beispiel #32
0
def test_finite_lattice(L):
    """
    Test several functions on a given finite lattice.

    The function contains tests of different kinds:

    - Implications of Boolean properties. Examples: a distributive lattice is modular,
      a dismantlable and distributive lattice is planar, a simple lattice can not be
      constructible by Day's doublings.
    - Dual and self-dual properties. Examples: Dual of a modular lattice is modular,
      dual of an atomic lattice is co-atomic.
    - Certificate tests. Example: certificate for a non-complemented lattice must be
      an element without a complement.
    - Verification of some property by known property or by a random test.
      Examples: A lattice is distributive iff join-primes are exactly
      join-irreducibles and an interval of a relatively complemented
      lattice is complemented.
    - Set inclusions. Example: Every co-atom must be meet-irreducible.
    - And several other tests. Example: The skeleton of a pseudocomplemented
      lattice must be Boolean.

    EXAMPLES::

        sage: from sage.tests.finite_poset import test_finite_lattice
        sage: L = posets.RandomLattice(10, 0.98)
        sage: test_finite_lattice(L) is None  # Long time
        True
    """
    from sage.combinat.posets.lattices import LatticePoset

    from sage.sets.set import Set
    from sage.combinat.subset import Subsets

    from sage.misc.prandom import randint
    from sage.misc.flatten import flatten
    from sage.misc.misc import attrcall

    from sage.misc.sageinspect import sage_getargspec

    if L.cardinality() < 4:
        # Special cases should be tested in specific TESTS-sections.
        return None

    all_props = set(list(implications) + flatten(implications.values()))
    P = {x: test_attrcall('is_' + x, L) for x in all_props}

    ### Relations between boolean-valued properties ###

    # Direct one-property implications
    for prop1 in implications:
        if P[prop1]:
            for prop2 in implications[prop1]:
                if not P[prop2]:
                    raise ValueError("error: %s should implicate %s" %
                                     (prop1, prop2))

    # Impossible combinations
    for p1, p2 in mutually_exclusive:
        if P[p1] and P[p2]:
            raise ValueError(
                "error: %s and %s should be impossible combination" % (p1, p2))

    # Two-property implications
    for p1, p2, p3 in two_to_one:
        if P[p1] and P[p2] and not P[p3]:
            raise ValueError("error: %s and %s, so should be %s" %
                             (p1, p2, p3))

    Ldual = L.dual()
    # Selfdual properties
    for p in selfdual_properties:
        if P[p] != test_attrcall('is_' + p, Ldual):
            raise ValueError("selfdual property %s error" % p)
    # Dual properties and elements
    for p1, p2 in dual_properties:
        if P[p1] != test_attrcall('is_' + p2, Ldual):
            raise ValueError("dual properties error %s" % p1)
    for e1, e2 in dual_elements:
        if set(attrcall(e1)(L)) != set(attrcall(e2)(Ldual)):
            raise ValueError("dual elements error %s" % e1)

    ### Certificates ###

    # Return value must be a pair with correct result as first element.
    for p_ in all_props:
        # Dirty fix first
        if p_[:9] == 'doubling_' or p_[:5] == 'uniq_': continue
        p = "is_" + p_
        if 'certificate' in sage_getargspec(getattr(L, p)).args:
            res = attrcall(p, certificate=True)(L)
            if type(res) != type((1, 2)) or len(res) != 2:
                raise ValueError(
                    "certificate-option does not return a pair in %s" % p)
            if P[p_] != res[0]:
                raise ValueError("certificate-option changes result in %s" % p)

    # Test for "yes"-certificates
    if P['supersolvable']:
        a = L.is_supersolvable(certificate=True)[1]
        S = Subsets(L).random_element()
        if L.is_chain_of_poset(S):
            if not L.sublattice(a + list(S)).is_distributive():
                raise ValueError("certificate error in is_supersolvable")
    if P['dismantlable']:
        elms = L.is_dismantlable(certificate=True)[1]
        if len(elms) != L.cardinality():
            raise ValueError("certificate error 1 in is_dismantlable")
        elms = elms[:randint(0, len(elms) - 1)]
        L_ = L.sublattice([x for x in L if x not in elms])
        if L_.cardinality() != L.cardinality() - len(elms):
            raise ValueError("certificate error 2 in is_dismantlable")
    if P['vertically_decomposable']:
        c = L.is_vertically_decomposable(certificate=True)[1]
        if c == L.bottom() or c == L.top():
            raise ValueError(
                "certificate error 1 in is_vertically_decomposable")
        e = L.random_element()
        if L.compare_elements(c, e) is None:
            raise ValueError(
                "certificate error 2 in is_vertically_decomposable")

    # Test for "no"-certificates
    if not P['atomic']:
        a = L.is_atomic(certificate=True)[1]
        if a in L.atoms() or a not in L.join_irreducibles():
            raise ValueError("certificate error in is_atomic")
    if not P['coatomic']:
        a = L.is_coatomic(certificate=True)[1]
        if a in L.coatoms() or a not in L.meet_irreducibles():
            raise ValueError("certificate error in is_coatomic")

    if not P['complemented']:
        a = L.is_complemented(certificate=True)[1]
        if L.complements(a) != []:
            raise ValueError("compl. error 1")
    if not P['sectionally_complemented']:
        a, b = L.is_sectionally_complemented(certificate=True)[1]
        L_ = L.sublattice(L.interval(L.bottom(), a))
        if L_.is_complemented():
            raise ValueError("sec. compl. error 1")
        if len(L_.complements(b)) > 0:
            raise ValueError("sec. compl. error 2")
    if not P['cosectionally_complemented']:
        a, b = L.is_cosectionally_complemented(certificate=True)[1]
        L_ = L.sublattice(L.interval(a, L.top()))
        if L_.is_complemented():
            raise ValueError("cosec. compl. error 1")
        if len(L_.complements(b)) > 0:
            raise ValueError("cosec. compl. error 2")
    if not P['relatively_complemented']:
        a, b, c = L.is_relatively_complemented(certificate=True)[1]
        I = L.interval(a, c)
        if len(I) != 3 or b not in I:
            raise ValueError("rel. compl. error 1")

    if not P['upper_semimodular']:
        a, b = L.is_upper_semimodular(certificate=True)[1]
        if not set(L.lower_covers(a)).intersection(set(
                L.lower_covers(b))) or set(L.upper_covers(a)).intersection(
                    set(L.upper_covers(b))):
            raise ValueError("certificate error in is_upper_semimodular")
    if not P['lower_semimodular']:
        a, b = L.is_lower_semimodular(certificate=True)[1]
        if set(L.lower_covers(a)).intersection(set(
                L.lower_covers(b))) or not set(L.upper_covers(a)).intersection(
                    set(L.upper_covers(b))):
            raise ValueError("certificate error in is_lower_semimodular")

    if not P['distributive']:
        x, y, z = L.is_distributive(certificate=True)[1]
        if L.meet(x, L.join(y, z)) == L.join(L.meet(x, y), L.meet(x, z)):
            raise ValueError("certificate error in is_distributive")
    if not P['modular']:
        x, a, b = L.is_modular(certificate=True)[1]
        if not L.is_less_than(x, b) or L.join(x, L.meet(a, b)) == L.meet(
                L.join(x, a), b):
            raise ValueError("certificate error in is_modular")

    if not P['pseudocomplemented']:
        a = L.is_pseudocomplemented(certificate=True)[1]
        L_ = L.subposet([e for e in L if L.meet(e, a) == L.bottom()])
        if L_.has_top():
            raise ValueError("certificate error in is_pseudocomplemented")
    if not P['join_pseudocomplemented']:
        a = L.is_join_pseudocomplemented(certificate=True)[1]
        L_ = L.subposet([e for e in L if L.join(e, a) == L.top()])
        if L_.has_bottom():
            raise ValueError("certificate error in is_join_pseudocomplemented")

    if not P['join_semidistributive']:
        e, x, y = L.is_join_semidistributive(certificate=True)[1]
        if L.join(e, x) != L.join(e, y) or L.join(e, x) == L.join(
                e, L.meet(x, y)):
            raise ValueError("certificate error in is_join_semidistributive")
    if not P['meet_semidistributive']:
        e, x, y = L.is_meet_semidistributive(certificate=True)[1]
        if L.meet(e, x) != L.meet(e, y) or L.meet(e, x) == L.meet(
                e, L.join(x, y)):
            raise ValueError("certificate error in is_meet_semidistributive")

    if not P['simple']:
        c = L.is_simple(certificate=True)[1]
        if len(L.congruence([c[randint(0, len(c) - 1)]])) == 1:
            raise ValueError("certificate error in is_simple")
    if not P['isoform']:
        c = L.is_isoform(certificate=True)[1]
        if len(c) == 1:
            raise ValueError("certificate error in is_isoform")
        if all(
                L.subposet(c[i]).is_isomorphic(L.subposet(c[i + 1]))
                for i in range(len(c) - 1)):
            raise ValueError("certificate error in is_isoform")
    if not P['uniform']:
        c = L.is_uniform(certificate=True)[1]
        if len(c) == 1:
            raise ValueError("certificate error in is_uniform")
        if all(len(c[i]) == len(c[i + 1]) for i in range(len(c) - 1)):
            raise ValueError("certificate error in is_uniform")
    if not P['regular']:
        c = L.is_regular(certificate=True)[1]
        if len(c[0]) == 1:
            raise ValueError("certificate error 1 in is_regular")
        if Set(c[1]) not in c[0]:
            raise ValueError("certificate error 2 in is_regular")
        if L.congruence([c[1]]) == c[0]:
            raise ValueError("certificate error 3 in is_regular")

    if not P['subdirectly_reducible']:
        x, y = L.is_subdirectly_reducible(certificate=True)[1]
        a = L.random_element()
        b = L.random_element()
        c = L.congruence([[a, b]])
        if len(c) != L.cardinality():
            for c_ in c:
                if x in c_:
                    if y not in c_:
                        raise ValueError(
                            "certificate error 1 in is_subdirectly_reducible")
                    break
            else:
                raise ValueError(
                    "certificate error 2 in is_subdirectly_reducible")

    if not P['join_distributive']:
        a = L.is_join_distributive(certificate=True)[1]
        L_ = L.sublattice(L.interval(a, L.join(L.upper_covers(a))))
        if L_.is_distributive():
            raise ValueError("certificate error in is_join_distributive")
    if not P['meet_distributive']:
        a = L.is_meet_distributive(certificate=True)[1]
        L_ = L.sublattice(L.interval(L.meet(L.lower_covers(a)), a))
        if L_.is_distributive():
            raise ValueError("certificate error in is_meet_distributive")

    ### Other ###

    # Other ways to recognize some boolean property
    if P['distributive'] != (set(L.join_primes()) == set(
            L.join_irreducibles())):
        raise ValueError(
            "every join-irreducible of a distributive lattice should be join-prime"
        )
    if P['distributive'] != (set(L.meet_primes()) == set(
            L.meet_irreducibles())):
        raise ValueError(
            "every meet-irreducible of a distributive lattice should be meet-prime"
        )
    if P['join_semidistributive'] != all(
            L.canonical_joinands(e) is not None for e in L):
        raise ValueError(
            "every element of join-semidistributive lattice should have canonical joinands"
        )
    if P['meet_semidistributive'] != all(
            L.canonical_meetands(e) is not None for e in L):
        raise ValueError(
            "every element of meet-semidistributive lattice should have canonical meetands"
        )

    # Random verification of a Boolean property
    if P['relatively_complemented']:
        a = L.random_element()
        b = L.random_element()
        if not L.sublattice(L.interval(a, b)).is_complemented():
            raise ValueError("rel. compl. error 3")
    if P['sectionally_complemented']:
        a = L.random_element()
        if not L.sublattice(L.interval(L.bottom(), a)).is_complemented():
            raise ValueError("sec. compl. error 3")
    if P['cosectionally_complemented']:
        a = L.random_element()
        if not L.sublattice(L.interval(a, L.top())).is_complemented():
            raise ValueError("cosec. compl. error 2")

    # Element set inclusions
    for s1, s2 in set_inclusions:
        if not set(attrcall(s1)(L)).issubset(set(attrcall(s2)(L))):
            raise ValueError("%s should be a subset of %s" % (s1, s2))

    # Sublattice-closed properties
    L_ = L.sublattice(Subsets(L).random_element())
    for p in sublattice_closed:
        if P[p] and not test_attrcall('is_' + p, L_):
            raise ValueError("property %s should apply to sublattices" % p)

    # Some sublattices
    L_ = L.center()  # Center is a Boolean lattice
    if not L_.is_atomic() or not L_.is_distributive():
        raise ValueError("error in center")
    if P['pseudocomplemented']:
        L_ = L.skeleton()  # Skeleton is a Boolean lattice
        if not L_.is_atomic() or not L_.is_distributive():
            raise ValueError("error in skeleton")
    L_ = L.frattini_sublattice()
    S = Subsets(L).random_element()
    if L.sublattice(S) == L and L.sublattice([e
                                              for e in S if e not in L_]) != L:
        raise ValueError("error in Frattini sublattice")
    L_ = L.maximal_sublattices()
    L_ = L_[randint(0, len(L_) - 1)]
    e = L.random_element()
    if e not in L_ and L.sublattice(list(L_) + [e]) != L:
        raise ValueError("error in maximal_sublattices")

    # Reverse functions: vertical composition and decomposition
    L_ = reduce(lambda a, b: a.vertical_composition(b),
                L.vertical_decomposition(), LatticePoset())
    if not L.is_isomorphic(L_):
        raise ValueError("error in vertical [de]composition")

    # Meet and join
    a = L.random_element()
    b = L.random_element()
    m = L.meet(a, b)
    j = L.join(a, b)
    m_ = L.subposet([
        e for e in L.principal_lower_set(a) if e in L.principal_lower_set(b)
    ]).top()
    j_ = L.subposet([
        e for e in L.principal_upper_set(a) if e in L.principal_upper_set(b)
    ]).bottom()
    if m != m_ or m != Ldual.join(a, b):
        raise ValueError("error in meet")
    if j != j_ or j != Ldual.meet(a, b):
        raise ValueError("error in join")

    # Misc misc
    e = L.neutral_elements()
    e = e[randint(0, len(e) - 1)]
    a = L.random_element()
    b = L.random_element()
    if not L.sublattice([e, a, b]).is_distributive():
        raise ValueError("error in neutral_elements")
Beispiel #33
0
    def wrapper(*args, **kwds):
        """
        TESTS::

            sage: from sage.rings.qqbar_decorators import handle_AA_and_QQbar
            sage: @handle_AA_and_QQbar
            ....: def return_base_ring(x):
            ....:     return x.base_ring()

            sage: P.<x> = QQbar[]
            sage: return_base_ring(x)
            Rational Field

            sage: P.<y,z> = QQbar[]
            sage: return_base_ring(y)
            Rational Field

            sage: return_base_ring(ideal(y,z))
            Rational Field
        """

        from sage.misc.flatten import flatten
        from sage.rings.polynomial.polynomial_element import Polynomial
        from sage.rings.polynomial.multi_polynomial import MPolynomial
        from sage.rings.ideal import Ideal, Ideal_generic
        from sage.rings.qqbar import AlgebraicField_common, number_field_elements_from_algebraics

        if not any([
                isinstance(a, (Polynomial, MPolynomial, Ideal_generic))
                and isinstance(a.base_ring(), AlgebraicField_common)
                for a in args
        ]):
            return func(*args, **kwds)

        polynomials = []

        for a in flatten(args, ltypes=(list, tuple, set)):
            if isinstance(a, Ideal_generic):
                polynomials.extend(a.gens())
            elif isinstance(a, Polynomial):
                polynomials.append(a)
            elif isinstance(a, MPolynomial):
                polynomials.append(a)

        orig_elems = flatten([p.coefficients() for p in polynomials])

        # We need minimal=True if these elements are over AA, because
        # same_field=True might trigger an exception otherwise.

        numfield, new_elems, morphism = number_field_elements_from_algebraics(
            orig_elems, same_field=True, minimal=True)

        elem_dict = dict(zip(orig_elems, new_elems))

        def forward_map(item):
            if isinstance(item, Ideal_generic):
                return Ideal([forward_map(g) for g in item.gens()])
            elif isinstance(item, Polynomial):
                return item.map_coefficients(elem_dict.__getitem__,
                                             new_base_ring=numfield)
            elif isinstance(item, MPolynomial):
                return item.map_coefficients(elem_dict.__getitem__,
                                             new_base_ring=numfield)
            elif isinstance(item, list):
                return map(forward_map, item)
            elif isinstance(item, tuple):
                return tuple(map(forward_map, item))
            elif isinstance(item, set):
                return set(map(forward_map, list(item)))
            else:
                return item

        def reverse_map(item):
            if isinstance(item, Ideal_generic):
                return Ideal([reverse_map(g) for g in item.gens()])
            elif isinstance(item, Polynomial):
                return item.map_coefficients(morphism)
            elif isinstance(item, MPolynomial):
                return item.map_coefficients(morphism)
            elif isinstance(item, list):
                return map(reverse_map, item)
            elif isinstance(item, tuple):
                return tuple(map(reverse_map, item))
            elif isinstance(item, set):
                return set(map(reverse_map, list(item)))
            else:
                return item

        args = map(forward_map, args)

        return reverse_map(func(*args, **kwds))
def fundamental_group(f, simplified=True, projective=False):
    r"""
    Return a presentation of the fundamental group of the complement of
    the algebraic set defined by the polynomial ``f``.

    INPUT:

    - ``f`` -- a polynomial in two variables, with coefficients in either
      the rationals or a number field with a fixed embedding in `\QQbar`

    - ``simplified`` -- boolean (default: ``True``); if set to ``True`` the
      presentation will be simplified (see below)

    - ``projective`` -- boolean (default: ``False``); if set to ``True``,
      the fundamental group of the complement of the projective completion
      of the curve will be computed, otherwise, the fundamental group of
      the complement in the affine plane will be computed

    If ``simplified`` is ``False``, the returned presentation has as
    many generators as degree of the polynomial times the points in the
    base used to create the segments that surround the discriminant. In
    this case, the generators are granted to be meridians of the curve.

    OUTPUT:

    A presentation of the fundamental group of the complement of the
    curve defined by ``f``.

    EXAMPLES::

        sage: from sage.schemes.curves.zariski_vankampen import fundamental_group # optional - sirocco
        sage: R.<x,y> = QQ[]
        sage: f = x^2 + y^3
        sage: fundamental_group(f) # optional - sirocco
        Finitely presented group < ... >
        sage: fundamental_group(f, simplified=False) # optional - sirocco
        Finitely presented group < ... >

    ::

        sage: from sage.schemes.curves.zariski_vankampen import fundamental_group # optional - sirocco
        sage: R.<x,y> = QQ[]
        sage: f = y^3 + x^3
        sage: fundamental_group(f) # optional - sirocco
        Finitely presented group < ... >

    It is also possible to have coefficients in a number field with a
    fixed embedding in `\QQbar`::

        sage: from sage.schemes.curves.zariski_vankampen import fundamental_group # optional - sirocco
        sage: zeta = QQbar['x']('x^2+x+1').roots(multiplicities=False)[0]
        sage: zeta
        -0.50000000000000000? - 0.866025403784439?*I
        sage: F = NumberField(zeta.minpoly(), 'zeta', embedding=zeta)
        sage: F.inject_variables()
        Defining zeta
        sage: R.<x,y> = F[]
        sage: f = y^3 + x^3 +zeta *x + 1
        sage: fundamental_group(f) # optional - sirocco
        Finitely presented group < x0 |  >
    """
    (x, y) = f.variables()
    F = f.base_ring()
    g = f.factor().radical().prod()
    d = g.degree(y)
    while not g.coefficient(y**d) in F or (projective and g.total_degree() > d):
        g = g.subs({x: x + y})
        d = g.degree(y)
    disc = discrim(g)
    segs = segments(disc)
    vertices = list(set(flatten(segs)))
    Faux = FreeGroup(d)
    F = FreeGroup(d * len(vertices))
    rels = []
    if projective:
        rels.append(prod(F.gen(i) for i in range(d)))
    braidscomputed = braid_in_segment([(g, seg[0], seg[1]) for seg in segs])
    for braidcomputed in braidscomputed:
        seg = (braidcomputed[0][0][1], braidcomputed[0][0][2])
        b = braidcomputed[1]
        i = vertices.index(seg[0])
        j = vertices.index(seg[1])
        for k in range(d):
            el1 = Faux([k + 1]) * b.inverse()
            el2 = k + 1
            w1 = F([sign(a)*d*i + a for a in el1.Tietze()])
            w2 = F([d*j + el2])
            rels.append(w1/w2)
    G = F / rels
    if simplified:
        return G.simplified()
    else:
        return G
Beispiel #35
0
def solve_with_extension(monic_polynomial,
                         root_names=None,
                         var='x',
                         flatten=False,
                         warning=True):
    r"""
    Return all roots of a monic polynomial in its base ring or in an appropriate
    extension ring, as far as possible.

    INPUT:

    - ``monic_polynomial`` -- the monic polynomial whose roots should be created
    - ``root_names``  -- names for the indeterminates needed to define the
      splitting algebra of the ``monic_polynomial`` (if necessary and possible)
    - ``var``  -- (default: ``'x'``) for the indeterminate needed to define the
      splitting field of the ``monic_polynomial`` (if necessary and possible)
    - ``flatten`` -- (default: ``True``) if ``True`` the roots will not be
      given as a list of pairs ``(root, multiplicity)`` but as a list of
      roots repeated according to their multiplicity
    - ``warning`` -- (default: ``True``) can be used (by setting to ``False``)
      to suppress a warning which will be thrown whenever it cannot be checked
      that the Galois group of ``monic_polynomial`` is maximal

    OUTPUT:

    List of tuples ``(root, multiplicity)`` respectively list of roots repeated
    according to their multiplicity if option ``flatten`` is ``True``.

    EXAMPLES::

        sage: from sage.algebras.splitting_algebra import solve_with_extension
        sage: t = polygen(ZZ)
        sage: p = t^2 -2*t +1
        sage: solve_with_extension(p, flatten=True )
        [1, 1]
        sage: solve_with_extension(p)
        [(1, 2)]

        sage: cp5 = cyclotomic_polynomial(5, var='T').change_ring(UniversalCyclotomicField())
        sage: solve_with_extension(cp5)
        [(E(5), 1), (E(5)^4, 1), (E(5)^2, 1), (E(5)^3, 1)]
        sage: _[0][0].parent()
        Universal Cyclotomic Field
    """
    def create_roots(monic_polynomial, warning=True):
        r"""
        This internal function creates all roots of a polynomial in an
        appropriate extension ring assuming that none of the roots is
        contained its base ring.

        It first tries to create the splitting field of the given polynomial.
        If this is not faithful the splitting algebra will be created.

        INPUT:

        - ``monic_polynomial`` -- the monic polynomial whose roots should
          be created
        - ``warning`` -- (default: ``True``) can be used (by setting to ``False``)
          to suppress a warning which will be thrown whenever it cannot be
          checked that the Galois group of ``monic_polynomial`` is maximal
        """
        parent = monic_polynomial.parent()
        base_ring = parent.base_ring()

        try:
            ext_field, embed = monic_polynomial.splitting_field(var, map=True)

            if embed.domain() != base_ring:
                # in this case the SplittingAlgebra is preferred
                raise NotImplementedError

            # -------------------------------------------------------------------------------------
            # in some cases the embedding of the base_ring in ext_field can not be obtained
            # as coercion
            # -------------------------------------------------------------------------------------
            reset_coercion = False
            from sage.rings.number_field.number_field import NumberField_generic
            if isinstance(base_ring, NumberField_generic):
                reset_coercion = True
            elif base_ring.is_finite() and not base_ring.is_prime_field():
                reset_coercion = True
            if reset_coercion:
                ext_field._unset_coercions_used()
                ext_field.register_coercion(embed)
                ext_field.register_conversion(embed)

            verbose("splitting field %s defined" % (ext_field))
            pol_emb = monic_polynomial.change_ring(ext_field)
            roots = pol_emb.roots()
        except NotImplementedError:
            ext_ring = SplittingAlgebra(monic_polynomial,
                                        name_list,
                                        warning=warning)
            verbose("splitting algebra %s defined" % (ext_ring))
            roots = [(r, 1) for r in ext_ring.splitting_roots()]
        return roots

    deg_pol = monic_polynomial.degree()
    if not root_names:
        from sage.structure.category_object import normalize_names
        root_names = normalize_names(deg_pol - 1, 'r')
    name_list = list(root_names)
    root_list = []
    try:
        root_list = monic_polynomial.roots()
    except (TypeError, ValueError, NotImplementedError):
        pass

    if not root_list:
        # ------------------------------------------------------------------------------
        # no roots found: find roots in an appropriate extension ring
        # ------------------------------------------------------------------------------
        verbose("no roots in base_ring")
        if len(name_list) > deg_pol - 1:
            name_list = [name_list[i] for i in range(deg_pol - 1)]
        roots = create_roots(monic_polynomial, warning=warning)

    else:
        # ------------------------------------------------------------------------------
        # root calculation was possible but maybe some more roots in an apropriate
        # extension ring can be constructed.
        # ------------------------------------------------------------------------------
        num_roots = sum(m for r, m in root_list)
        if num_roots < deg_pol:
            h = monic_polynomial.variables()[0]
            divisor = monic_polynomial.base_ring().one()
            for r, m in root_list:
                divisor *= (h - r)**m
            q, r = monic_polynomial.quo_rem(divisor)
            if len(name_list) > deg_pol - num_roots - 1:
                name_list = [
                    name_list[i] for i in range(deg_pol - num_roots - 1)
                ]
            verbose("%d root found in base ring, now solving %s" %
                    (num_roots, q))
            missing_roots = create_roots(q, warning=True)
            roots = root_list + missing_roots
        else:
            roots = root_list
            verbose("all roots in base ring")

    if flatten:
        from sage.misc.flatten import flatten
        return flatten([[rt] * m for rt, m in roots])
    return roots
Beispiel #36
0
def import_statements(*objects, **options):
    """
    Print import statements for the given objects.

    INPUT:

    - ``*objects`` -- a sequence of objects.

    - ``lazy`` -- a boolean (default: ``False``)
      Whether to print a lazy import statement.

    - ``verbose`` -- a boolean (default: ``True``)
      Whether to print information in case of ambiguity.

    EXAMPLES::

        sage: import_statements(WeylGroup, lazy_attribute)
        from sage.combinat.root_system.weyl_group import WeylGroup
        from sage.misc.lazy_attribute import lazy_attribute

        sage: import_statements(IntegerRing)
        from sage.rings.integer_ring import IntegerRing

    If ``lazy`` is True, then :func:`lazy_import` statements are
    displayed instead::

        sage: import_statements(WeylGroup, lazy_attribute, lazy=True)
        from sage.misc.lazy_import import lazy_import
        lazy_import('sage.combinat.root_system.weyl_group', 'WeylGroup')
        lazy_import('sage.misc.lazy_attribute', 'lazy_attribute')

    In principle, the function should also work on object which are instances.
    In case of ambiguity, one or two warning lines are printed::

        sage: import_statements(NN)
        from sage.rings.semirings.non_negative_integer_semiring import NN

        sage: import_statements(ZZ)
          ** Warning **: several names for that object: Z, ZZ
        from sage.rings.integer_ring import Z

        sage: import_statements(euler_phi)
        from sage.rings.arith import euler_phi

        sage: import_statements(x)
          ** Warning **: several modules for that object: sage.all_cmdline, sage.calculus.predefined, sage.interacts.library
        from sage.calculus.predefined import x

    If you don't like the warning you can disable them with the option ``verbose``::

        sage: import_statements(ZZ, verbose=False)
        from sage.rings.integer_ring import Z

        sage: import_statements(x, verbose=False)
        from sage.calculus.predefined import x

    If the object has several names, an other way to get the import
    statement you expect is to use a string instead of the object::

        sage: import_statements(cached_function)
          ** Warning **: several names for that object: CachedFunction, cached_function
        from sage.misc.cachefunc import CachedFunction

        sage: import_statements('cached_function')
        from sage.misc.cachefunc import cached_function
        sage: import_statements('Z')
        from sage.rings.integer_ring import Z


    Specifying a string is also useful for objects that are not
    imported in the Sage interpreter namespace by default. In this
    case, an object with that name is looked up in all the modules
    that have been imported in this session::

        sage: print_import_statement
        Traceback (most recent call last):
        ...
        NameError: name 'print_import_statement' is not defined

        sage: import_statements("print_import_statement")
        from sage.misc.dev_tools import print_import_statement

    We test different object which have no appropriate answer::

        sage: import_statements('my_tailor_is_rich')
        Traceback (most recent call last):
        ...
        ValueError: no import statement for my_tailor_is_rich
        sage: import_statements(5)
        Traceback (most recent call last):
        ...
        ValueError: no import statement for 5
    """
    import inspect, sys, re
    import sage.all
    from sage.misc import sageinspect
    from sage.misc.flatten import flatten

    lazy = options.get("lazy", False)
    verbose = options.get("verbose", True)
    if lazy:
        print "from sage.misc.lazy_import import lazy_import"

    for obj in objects:
        # if obj is a string use it has a name and look for an object
        if isinstance(obj, str):
            name = obj
            if name in sage.all.__dict__:
                obj = sage.all.__dict__[name]
            else:
                # Look for the first module which contains that name.
                # TODO: improve this heuristic.
                for module in sys.modules.values():
                    if hasattr(module, '__dict__') and name in module.__dict__:
                        obj = module.__dict__[name]
                        break
        else:
            name = None

        # Case 1: the object is a module
        if inspect.ismodule(obj):
            if lazy:
                print "lazy_import('%s')"%obj.__name__
            else:
                print "import %s"%obj.__name__
            continue

        # Case 2: the object is defined in its module
        module = None
        if sageinspect.isclassinstance(obj):
            module = obj.__class__.__module__
        elif hasattr(obj, '__module__') and obj.__module__:
            module = obj.__module__

        if module:
            d = sys.modules[module].__dict__
            if name is None:
                names = sorted(key for key in d if d[key] is obj)
            else:
                names = [name]
            if names:
                if verbose and len(names) > 1:
                    print "  ** Warning **: several names for that object: %s"%', '.join(names)
                print_import_statement(module, names[0], lazy)
                continue


        # Case 3: search for this object in all modules
        names = {} # dictionnary: module -> names of the object in that module
        for module in sys.modules:
            if module != '__main__' and hasattr(sys.modules[module],'__dict__'):
                d = sys.modules[module].__dict__

                if name is not None:
                    if name in d and d[name] is obj:
                        names[module] = name
                else:
                    n = [key for key in d if d[key] is obj]
                    if n:
                        names[module] = n

        all_names = sorted(set(flatten(names.values())))
        if len(all_names) == 0:
            raise ValueError("no import statement for %s"%obj)
        elif verbose and len(all_names) > 1:
            print "  ** Warning **: several names for that object:",
            print ", ".join(sorted(all_names))

        modules = sorted(flatten(names),cmp=module_names_cmp)
        if verbose and len(modules) > 1:
            print "  ** Warning **: several modules for that object:",
            print ", ".join(modules[:4]),
            if len(modules) > 4:
                print "..."
            else:
                print

        # Case 4: if the object is a class instance, we look for a
        # module where it is instanciated
        if sageinspect.isclassinstance(obj):
            names_pattern = dict((name,re.compile("^%s\ *="%name, re.MULTILINE)) for name in all_names)

            for module in modules:
                sources = sageinspect.sage_getsource(sys.modules[module])
                for name in names[module]:
                    if names_pattern[name].search(sources):
                        break
                else:
                    continue
                break
        else:
            module = modules[0]
            name = names[module][0]

        if name is not None:
            print_import_statement(module, name, lazy)
        else:
            raise ValueError("no import statement for %s"%obj)
Beispiel #37
0
def update_stats(verbose=True):
    from data_mgt.utilities.rewrite import update_attribute_stats
    from bson.code import Code
    ec = C.elliptic_curves
    ecdbstats = ec.nfcurves.stats

    # get list of degrees

    degrees = nfcurves.distinct('degree')
    if verbose:
        print("degrees: {}".format(degrees))

    # get list of signatures for each degree.  Note that it would not
    # work to use nfcurves.find({'degree':d}).distinct('signature')
    # since 'signature' is currently a list of integers an mongo would
    # return a list of integers, not a list of lists.  With hindsight
    # it would have been better to store the signature as a string.

    if verbose:
        print("Adding signatures_by_degree")
    reducer = Code("""function(key,values){return Array.sum(values);}""")
    attr = 'signature'
    mapper = Code("""function(){emit(""+this.""" + attr + """,1);}""")
    sigs_by_deg = {}
    for d in degrees:
        sigs_by_deg[str(d)] = [
            r['_id'] for r in nfcurves.inline_map_reduce(
                mapper, reducer, query={'degree': d})
        ]
        if verbose:
            print("degree {} has signatures {}".format(d, sigs_by_deg[str(d)]))

    entry = {'_id': 'signatures_by_degree'}
    ecdbstats.delete_one(entry)
    entry.update(sigs_by_deg)
    ecdbstats.insert_one(entry)

    # get list of fields for each signature.  Simple code here faster than map/reduce

    if verbose:
        print("Adding fields_by_signature")
    from sage.misc.flatten import flatten
    sigs = flatten(sigs_by_deg.values())
    fields_by_sig = dict([
        sig,
        nfcurves.find({
            'signature': [int(x) for x in sig.split(",")]
        }).distinct('field_label')
    ] for sig in sigs)
    entry = {'_id': 'fields_by_signature'}
    ecdbstats.delete_one(entry)
    entry.update(fields_by_sig)
    ecdbstats.insert_one(entry)

    # get list of fields for each degree

    if verbose:
        print("Adding fields_by_degree")
    fields_by_deg = dict(
        [str(d),
         sorted(nfcurves.find({
             'degree': d
         }).distinct('field_label'))] for d in degrees)
    entry = {'_id': 'fields_by_degree'}
    ecdbstats.delete_one(entry)
    entry.update(fields_by_deg)
    ecdbstats.insert_one(entry)

    fields = flatten(fields_by_deg.values())
    if verbose:
        print("{} fields, {} signatures, {} degrees".format(
            len(fields), len(sigs), len(degrees)))

    if verbose:
        print("Adding curve counts for torsion order, torsion structure")
    update_attribute_stats(ec, 'nfcurves',
                           ['torsion_order', 'torsion_structure'])

    if verbose:
        print("Adding curve counts by degree, signature and field")
    update_attribute_stats(ec, 'nfcurves',
                           ['degree', 'signature', 'field_label'])

    if verbose:
        print("Adding class counts by degree, signature and field")
    update_attribute_stats(ec,
                           'nfcurves', ['degree', 'signature', 'field_label'],
                           prefix="classes",
                           filter={'number': int(1)})

    # conductor norm ranges:
    # total:
    if verbose:
        print("Adding curve and class counts and conductor range")
    norms = ec.nfcurves.distinct('conductor_norm')
    data = {
        'ncurves': ec.nfcurves.count(),
        'nclasses': ec.nfcurves.find({
            'number': 1
        }).count(),
        'min_norm': min(norms),
        'max_norm': max(norms),
    }
    entry = {'_id': 'conductor_norm'}
    ecdbstats.delete_one(entry)
    entry.update(data)
    ecdbstats.insert_one(entry)

    # by degree:
    if verbose:
        print("Adding curve and class counts and conductor range, by degree")
    degree_data = {}
    for d in degrees:
        query = {'degree': d}
        res = nfcurves.find(query)
        ncurves = res.count()
        Ns = res.distinct('conductor_norm')
        min_norm = min(Ns)
        max_norm = max(Ns)
        query['number'] = 1
        nclasses = nfcurves.count(query)
        degree_data[str(d)] = {
            'ncurves': ncurves,
            'nclasses': nclasses,
            'min_norm': min_norm,
            'max_norm': max_norm,
        }

    entry = {'_id': 'conductor_norm_by_degree'}
    ecdbstats.delete_one(entry)
    entry.update(degree_data)
    ecdbstats.insert_one(entry)

    # by signature:
    if verbose:
        print(
            "Adding curve and class counts and conductor range, by signature")
    sig_data = {}
    for sig in sigs:
        query = {'signature': [int(c) for c in sig.split(",")]}
        res = nfcurves.find(query)
        ncurves = res.count()
        Ns = res.distinct('conductor_norm')
        min_norm = min(Ns)
        max_norm = max(Ns)
        query['number'] = 1
        nclasses = nfcurves.count(query)
        sig_data[sig] = {
            'ncurves': ncurves,
            'nclasses': nclasses,
            'min_norm': min_norm,
            'max_norm': max_norm,
        }
    entry = {'_id': 'conductor_norm_by_signature'}
    ecdbstats.delete_one(entry)
    entry.update(sig_data)
    ecdbstats.insert_one(entry)

    # by field:
    if verbose:
        print("Adding curve and class counts and conductor range, by field")
    entry = {'_id': 'conductor_norm_by_field'}
    ecdbstats.delete_one(entry)
    field_data = {}
    for f in fields:
        ff = f.replace(".", ":")  # mongo does not allow "." in key strings
        query = {'field_label': f}
        res = nfcurves.find(query)
        ncurves = res.count()
        Ns = res.distinct('conductor_norm')
        min_norm = min(Ns)
        max_norm = max(Ns)
        query['number'] = 1
        nclasses = nfcurves.count(query)
        field_data[ff] = {
            'ncurves': ncurves,
            'nclasses': nclasses,
            'min_norm': min_norm,
            'max_norm': max_norm,
        }
    entry = {'_id': 'conductor_norm_by_field'}
    ecdbstats.delete_one(entry)
    entry.update(field_data)
    ecdbstats.insert_one(entry)
Beispiel #38
0
    def shard_covectors(self):
        r"""
        Return the shard covectors for the given planar vector configuraton.

        The shard covectors are defined in [CEL]_ and shown to be in bijection
        with the shards of the hyperplane arrangement with specified base 
        region. A shard covector of a shard on hyperplane `i` is a restricted
        covector with a unique zero in position `i`.

        NOTE:

        An acyclic vector configuration corresponds to a hyperplane arrangement
        with selected base region.

        OUTPUT:

        A tuple of covectors as sequences of -1,0,1,'3'.

        EXAMPLES::

            sage: from cn_hyperarr.vector_classes import *
            sage: vc = VectorConfiguration([[1,0,0],[0,1,0],[0,0,1],[1,1,0],[0,1,1],[1,1,1]])
            sage: len(vc.shard_covectors())
            11

        The following vector configuration is not congruence normal and has 29
        shards::

            sage: tau = AA((1+sqrt(5))/2)
            sage: ncn = [[2*tau+1,2*tau,tau],[2*tau+2,2*tau+1,tau+1],[1,1,1],[tau+1,tau+1,tau],[2*tau,2*tau,tau],[tau+1,tau+1,1],[1,1,0],[0,1,0],[1,0,0],[tau+1,tau,tau]]
            sage: ncn_conf = VectorConfiguration(ncn);
            sage: len(ncn_conf.shard_covectors())
            29

        The vector configuration [[-1,0,1],[1,0,1],[0,0,1],[0,1,0]] has five shards::

            sage: vc = VectorConfiguration([[-1,0,1],[1,0,1],[0,0,1],[0,1,0]])
            sage: len(vc.shard_covectors())
            5
        """
        nb_pts = self.n_vectors()
        dom_dict = self.dominating_pairs()
        cocircuits = self.three_dim_cocircuits()
        rms_covectors = []
        for index in range(nb_pts):
            the_pairs = dom_dict[index]
            if len(the_pairs) == 0:
                # The vector is not dominated
                # We put a joker everywhere
                # and set to 0 the entry at the index
                cov = [3] * nb_pts
                cov[index] = 0
                rms_covectors += [Covector(cov)]
            else:
                # The vector is dominated at least once
                the_restricted_set = flatten([list(p) for p in the_pairs])
                for pair in the_pairs:
                    p1, p2 = pair
                    the_indices = list(pair) + [index]
                    # Get the two cocircuits that contain the triple
                    the_coc_l = [
                        coc for coc in cocircuits
                        if all(i in coc[1] for i in the_indices)
                    ]
                    assert len(the_coc_l
                               ) == 2, "There is a problem with the cocircuits"
                    coc1, coc2 = the_coc_l
                    # Setup the two restricted covectors
                    restricted_coc1 = [
                        [i for i in s if i in the_restricted_set] for s in coc1
                    ]
                    restricted_coc2 = [
                        [i for i in s if i in the_restricted_set] for s in coc2
                    ]

                    # Creating the four possible fillings
                    # By placing p1 and p2 in the four possible ways
                    l_minres_coc = []
                    l_minres_coc += [[
                        restricted_coc1[0] + [p1], [index],
                        restricted_coc1[2] + [p2]
                    ]]
                    l_minres_coc += [[
                        restricted_coc1[0] + [p2], [index],
                        restricted_coc1[2] + [p1]
                    ]]
                    l_minres_coc += [[
                        restricted_coc2[0] + [p1], [index],
                        restricted_coc2[2] + [p2]
                    ]]
                    l_minres_coc += [[
                        restricted_coc2[0] + [p2], [index],
                        restricted_coc2[2] + [p1]
                    ]]

                    # From the indices, get the covectors
                    for r_coc in l_minres_coc:
                        cov = Covector(r_coc, nb_pts)
                        rms_covectors += [cov]
            rms_covectors = list(set(rms_covectors))
        return tuple(rms_covectors)
def braid_monodromy(f):
    r"""
    Compute the braid monodromy of a projection of the curve defined by a polynomial

    INPUT:

    - ``f`` -- a polynomial with two variables, over a number field with an embedding
      in the complex numbers.

    OUTPUT:

    A list of braids. The braids correspond to paths based in the same point;
    each of this paths is the conjugated of a loop around one of the points
    in the discriminant of the projection of ``f``.

    .. NOTE::

        The projection over the `x` axis is used if there are no vertical asymptotes.
        Otherwise, a linear change of variables is done to fall into the previous case.

    EXAMPLES::

        sage: from sage.schemes.curves.zariski_vankampen import braid_monodromy
        sage: R.<x,y> = QQ[]
        sage: f = (x^2-y^3)*(x+3*y-5)
        sage: braid_monodromy(f)  # optional - sirocco
        [s1*s0*(s1*s2)^2*s0*s2^2*s0^-1*(s2^-1*s1^-1)^2*s0^-1*s1^-1,
         s1*s0*(s1*s2)^2*(s0*s2^-1*s1*s2*s1*s2^-1)^2*(s2^-1*s1^-1)^2*s0^-1*s1^-1,
         s1*s0*(s1*s2)^2*s2*s1^-1*s2^-1*s1^-1*s0^-1*s1^-1,
         s1*s0*s2*s0^-1*s2*s1^-1]

    """
    global roots_interval_cache
    (x, y) = f.parent().gens()
    F = f.base_ring()
    g = f.radical()
    d = g.degree(y)
    while not g.coefficient(y**d) in F:
        g = g.subs({x: x + y})
        d = g.degree(y)
    disc = discrim(g)
    V = corrected_voronoi_diagram(tuple(disc))
    G = Graph()
    for reg in V.regions().values():
        G = G.union(reg.vertex_graph())
    E = Graph()
    for reg in V.regions().values():
        if reg.rays() or reg.lines():
            E = E.union(reg.vertex_graph())
    p = next(E.vertex_iterator())
    geombasis = geometric_basis(G, E, p)
    segs = set([])
    for p in geombasis:
        for s in zip(p[:-1], p[1:]):
            if (s[1], s[0]) not in segs:
                segs.add((s[0], s[1]))
    I = QQbar.gen()
    segs = [(a[0] + I * a[1], b[0] + I * b[1]) for (a, b) in segs]
    vertices = list(set(flatten(segs)))
    tocacheverts = [(g, v) for v in vertices]
    populate_roots_interval_cache(tocacheverts)
    gfac = g.factor()
    try:
        braidscomputed = list(
            braid_in_segment([(gfac, seg[0], seg[1]) for seg in segs]))
    except ChildProcessError:  # hack to deal with random fails first time
        braidscomputed = list(
            braid_in_segment([(gfac, seg[0], seg[1]) for seg in segs]))
    segsbraids = dict()
    for braidcomputed in braidscomputed:
        seg = (braidcomputed[0][0][1], braidcomputed[0][0][2])
        beginseg = (QQ(seg[0].real()), QQ(seg[0].imag()))
        endseg = (QQ(seg[1].real()), QQ(seg[1].imag()))
        b = braidcomputed[1]
        segsbraids[(beginseg, endseg)] = b
        segsbraids[(endseg, beginseg)] = b.inverse()
    B = b.parent()
    result = []
    for path in geombasis:
        braidpath = B.one()
        for i in range(len(path) - 1):
            x0 = tuple(path[i].vector())
            x1 = tuple(path[i + 1].vector())
            braidpath = braidpath * segsbraids[(x0, x1)]
        result.append(braidpath)
    return result
Beispiel #40
0
def Polyhedron(vertices=None, rays=None, lines=None,
               ieqs=None, eqns=None,
               ambient_dim=None, base_ring=None, minimize=True, verbose=False,
               backend=None):
    """
    Construct a polyhedron object.

    You may either define it with vertex/ray/line or
    inequalities/equations data, but not both. Redundant data will
    automatically be removed (unless ``minimize=False``), and the
    complementary representation will be computed.

    INPUT:

    - ``vertices`` -- list of point. Each point can be specified as
      any iterable container of ``base_ring`` elements. If ``rays`` or
      ``lines`` are specified but no ``vertices``, the origin is
      taken to be the single vertex.

    - ``rays`` -- list of rays. Each ray can be specified as any
      iterable container of ``base_ring`` elements.

    - ``lines`` -- list of lines. Each line can be specified as any
      iterable container of ``base_ring`` elements.

    - ``ieqs`` -- list of inequalities. Each line can be specified as any
      iterable container of ``base_ring`` elements. An entry equal to
      ``[-1,7,3,4]`` represents the inequality `7x_1+3x_2+4x_3\geq 1`.

    - ``eqns`` -- list of equalities. Each line can be specified as
      any iterable container of ``base_ring`` elements. An entry equal to
      ``[-1,7,3,4]`` represents the equality `7x_1+3x_2+4x_3= 1`.

    - ``base_ring`` -- either ``QQ`` or ``RDF``. The field over which
      the polyhedron will be defined. For ``QQ``, exact arithmetic
      will be used. For ``RDF``, floating point numbers will be
      used. Floating point arithmetic is faster but might give the
      wrong result for degenerate input.

    - ``ambient_dim`` -- integer. The ambient space dimension. Usually
      can be figured out automatically from the H/Vrepresentation
      dimensions.

    - ``backend`` -- string or ``None`` (default). The backend to use. Valid choices are

      * ``'cdd'``: use cdd
        (:mod:`~sage.geometry.polyhedron.backend_cdd`) with `\QQ` or
        `\RDF` coefficients depending on ``base_ring``.


      * ``'ppl'``: use ppl
        (:mod:`~sage.geometry.polyhedron.backend_ppl`) with `\ZZ` or
        `\QQ` coefficients depending on ``base_ring``.

    Some backends support further optional arguments:

    - ``minimize`` -- boolean (default: ``True``). Whether to
      immediately remove redundant H/V-representation data. Currently
      not used.

    - ``verbose`` -- boolean (default: ``False``). Whether to print
      verbose output for debugging purposes. Only supported by the cdd
      backends.

    OUTPUT:

    The polyhedron defined by the input data.

    EXAMPLES:

    Construct some polyhedra::

        sage: square_from_vertices = Polyhedron(vertices = [[1, 1], [1, -1], [-1, 1], [-1, -1]])
        sage: square_from_ieqs = Polyhedron(ieqs = [[1, 0, 1], [1, 1, 0], [1, 0, -1], [1, -1, 0]])
        sage: list(square_from_ieqs.vertex_generator())
        [A vertex at (1, -1),
         A vertex at (1, 1),
         A vertex at (-1, 1),
         A vertex at (-1, -1)]
        sage: list(square_from_vertices.inequality_generator())
        [An inequality (1, 0) x + 1 >= 0,
         An inequality (0, 1) x + 1 >= 0,
         An inequality (-1, 0) x + 1 >= 0,
         An inequality (0, -1) x + 1 >= 0]
        sage: p = Polyhedron(vertices = [[1.1, 2.2], [3.3, 4.4]], base_ring=RDF)
        sage: p.n_inequalities()
        2

    The same polyhedron given in two ways::

        sage: p = Polyhedron(ieqs = [[0,1,0,0],[0,0,1,0]])
        sage: p.Vrepresentation()
        (A line in the direction (0, 0, 1),
         A ray in the direction (1, 0, 0),
         A ray in the direction (0, 1, 0),
         A vertex at (0, 0, 0))
        sage: q = Polyhedron(vertices=[[0,0,0]], rays=[[1,0,0],[0,1,0]], lines=[[0,0,1]])
        sage: q.Hrepresentation()
        (An inequality (1, 0, 0) x + 0 >= 0,
         An inequality (0, 1, 0) x + 0 >= 0)

    Finally, a more complicated example. Take `\mathbb{R}_{\geq 0}^6` with
    coordinates `a, b, \dots, f` and

      * The inequality `e+b \geq c+d`
      * The inequality `e+c \geq b+d`
      * The equation `a+b+c+d+e+f = 31`

    ::

        sage: positive_coords = Polyhedron(ieqs=[
        ...       [0, 1, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0],
        ...       [0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 1]])
        sage: P = Polyhedron(ieqs=positive_coords.inequalities() + (
        ...       [0,0,1,-1,-1,1,0], [0,0,-1,1,-1,1,0]), eqns=[[-31,1,1,1,1,1,1]])
        sage: P
        A 5-dimensional polyhedron in QQ^6 defined as the convex hull of 7 vertices
        sage: P.dim()
        5
        sage: P.Vrepresentation()
        (A vertex at (31, 0, 0, 0, 0, 0), A vertex at (0, 0, 0, 0, 0, 31),
         A vertex at (0, 0, 0, 0, 31, 0), A vertex at (0, 0, 31/2, 0, 31/2, 0),
         A vertex at (0, 31/2, 31/2, 0, 0, 0), A vertex at (0, 31/2, 0, 0, 31/2, 0),
         A vertex at (0, 0, 0, 31/2, 31/2, 0))

    .. NOTE::

      * Once constructed, a ``Polyhedron`` object is immutable.
      * Although the option ``field=RDF`` allows numerical data to
        be used, it might not give the right answer for degenerate
        input data - the results can depend upon the tolerance
        setting of cdd.
    """
    # Clean up the arguments
    vertices = _make_listlist(vertices)
    rays     = _make_listlist(rays)
    lines    = _make_listlist(lines)
    ieqs     = _make_listlist(ieqs)
    eqns     = _make_listlist(eqns)

    got_Vrep = (len(vertices+rays+lines) > 0)
    got_Hrep = (len(ieqs+eqns) > 0)

    if got_Vrep and got_Hrep:
        raise ValueError('You cannot specify both H- and V-representation.')
    elif got_Vrep:
        deduced_ambient_dim = _common_length_of(vertices, rays, lines)[1]
    elif got_Hrep:
        deduced_ambient_dim = _common_length_of(ieqs, eqns)[1] - 1
    else:
        if ambient_dim is None:
            deduced_ambient_dim = 0
        else:
            deduced_ambient_dim = ambient_dim
        if base_ring is None:
            base_ring = ZZ

    # set ambient_dim
    if ambient_dim is not None and deduced_ambient_dim!=ambient_dim:
        raise ValueError('Ambient space dimension mismatch. Try removing the "ambient_dim" parameter.')
    ambient_dim = deduced_ambient_dim

    # figure out base_ring
    from sage.misc.flatten import flatten
    values = flatten(vertices+rays+lines+ieqs+eqns)
    if base_ring is not None:
        try:
            convert = not all(x.parent() is base_ring for x in values)
        except AttributeError:   # No x.parent() method?
            convert = True
    else:
        from sage.rings.integer import is_Integer
        from sage.rings.rational import is_Rational
        from sage.rings.real_double import is_RealDoubleElement
        if all(is_Integer(x) for x in values):
            if got_Vrep:
                base_ring = ZZ
            else:   # integral inequalities usually do not determine a latice polytope!
                base_ring = QQ
            convert=False
        elif all(is_Rational(x) for x in values):
            base_ring = QQ
            convert=False
        elif all(is_RealDoubleElement(x) for x in values):
            base_ring = RDF
            convert=False
        else:
            try:
                map(ZZ, values)
                if got_Vrep:
                    base_ring = ZZ
                else:
                    base_ring = QQ
                convert = True
            except TypeError:
                from sage.structure.sequence import Sequence
                values = Sequence(values)
                if QQ.has_coerce_map_from(values.universe()):
                    base_ring = QQ
                    convert = True
                else:
                    base_ring = RDF
                    convert = True

    # Add the origin if necesarry
    if got_Vrep and len(vertices)==0:
        vertices = [ [0]*ambient_dim ]

    # Specific backends can override the base_ring
    from sage.geometry.polyhedron.parent import Polyhedra
    parent = Polyhedra(base_ring, ambient_dim, backend=backend)
    base_ring = parent.base_ring()

    # Convert into base_ring if necessary
    def convert_base_ring(lstlst):
        return [ [base_ring(x) for x in lst] for lst in lstlst]
    Hrep = Vrep = None
    if got_Hrep:
        Hrep = [ieqs, eqns]
    if got_Vrep:
        Vrep = [vertices, rays, lines]

    # finally, construct the Polyhedron
    return parent(Vrep, Hrep, convert=convert)
Beispiel #41
0
def Polyhedron(vertices=None,
               rays=None,
               lines=None,
               ieqs=None,
               eqns=None,
               ambient_dim=None,
               base_ring=None,
               minimize=True,
               verbose=False,
               backend=None):
    """
    Construct a polyhedron object.

    You may either define it with vertex/ray/line or
    inequalities/equations data, but not both. Redundant data will
    automatically be removed (unless ``minimize=False``), and the
    complementary representation will be computed.

    INPUT:

    - ``vertices`` -- list of point. Each point can be specified as
      any iterable container of ``base_ring`` elements. If ``rays`` or
      ``lines`` are specified but no ``vertices``, the origin is
      taken to be the single vertex.

    - ``rays`` -- list of rays. Each ray can be specified as any
      iterable container of ``base_ring`` elements.

    - ``lines`` -- list of lines. Each line can be specified as any
      iterable container of ``base_ring`` elements.

    - ``ieqs`` -- list of inequalities. Each line can be specified as any
      iterable container of ``base_ring`` elements. An entry equal to
      ``[-1,7,3,4]`` represents the inequality `7x_1+3x_2+4x_3\geq 1`.

    - ``eqns`` -- list of equalities. Each line can be specified as
      any iterable container of ``base_ring`` elements. An entry equal to
      ``[-1,7,3,4]`` represents the equality `7x_1+3x_2+4x_3= 1`.

    - ``base_ring`` -- a sub-field of the reals implemented in
      Sage. The field over which the polyhedron will be defined. For
      ``QQ`` and algebraic extensions, exact arithmetic will be
      used. For ``RDF``, floating point numbers will be used. Floating
      point arithmetic is faster but might give the wrong result for
      degenerate input.

    - ``ambient_dim`` -- integer. The ambient space dimension. Usually
      can be figured out automatically from the H/Vrepresentation
      dimensions.

    - ``backend`` -- string or ``None`` (default). The backend to use. Valid choices are

      * ``'cdd'``: use cdd
        (:mod:`~sage.geometry.polyhedron.backend_cdd`) with `\QQ` or
        `\RDF` coefficients depending on ``base_ring``.

      * ``'normaliz'``: use normaliz
        (:mod:`~sage.geometry.polyhedron.backend_normaliz`) with `\ZZ` or
        `\QQ` coefficients depending on ``base_ring``.

      * ``'polymake'``: use polymake
        (:mod:`~sage.geometry.polyhedron.backend_polymake`) with `\QQ`, `\RDF` or
        ``QuadraticField`` coefficients depending on ``base_ring``.

      * ``'ppl'``: use ppl
        (:mod:`~sage.geometry.polyhedron.backend_ppl`) with `\ZZ` or
        `\QQ` coefficients depending on ``base_ring``.

      * ``'field'``: use python implementation
        (:mod:`~sage.geometry.polyhedron.backend_field`) for any field

    Some backends support further optional arguments:

    - ``minimize`` -- boolean (default: ``True``). Whether to
      immediately remove redundant H/V-representation data. Currently
      not used.

    - ``verbose`` -- boolean (default: ``False``). Whether to print
      verbose output for debugging purposes. Only supported by the cdd
      backends.

    OUTPUT:

    The polyhedron defined by the input data.

    EXAMPLES:

    Construct some polyhedra::

        sage: square_from_vertices = Polyhedron(vertices = [[1, 1], [1, -1], [-1, 1], [-1, -1]])
        sage: square_from_ieqs = Polyhedron(ieqs = [[1, 0, 1], [1, 1, 0], [1, 0, -1], [1, -1, 0]])
        sage: list(square_from_ieqs.vertex_generator())
        [A vertex at (1, -1),
         A vertex at (1, 1),
         A vertex at (-1, 1),
         A vertex at (-1, -1)]
        sage: list(square_from_vertices.inequality_generator())
        [An inequality (1, 0) x + 1 >= 0,
         An inequality (0, 1) x + 1 >= 0,
         An inequality (-1, 0) x + 1 >= 0,
         An inequality (0, -1) x + 1 >= 0]
        sage: p = Polyhedron(vertices = [[1.1, 2.2], [3.3, 4.4]], base_ring=RDF)
        sage: p.n_inequalities()
        2

    The same polyhedron given in two ways::

        sage: p = Polyhedron(ieqs = [[0,1,0,0],[0,0,1,0]])
        sage: p.Vrepresentation()
        (A line in the direction (0, 0, 1),
         A ray in the direction (1, 0, 0),
         A ray in the direction (0, 1, 0),
         A vertex at (0, 0, 0))
        sage: q = Polyhedron(vertices=[[0,0,0]], rays=[[1,0,0],[0,1,0]], lines=[[0,0,1]])
        sage: q.Hrepresentation()
        (An inequality (1, 0, 0) x + 0 >= 0,
         An inequality (0, 1, 0) x + 0 >= 0)

    Finally, a more complicated example. Take `\mathbb{R}_{\geq 0}^6` with
    coordinates `a, b, \dots, f` and

      * The inequality `e+b \geq c+d`
      * The inequality `e+c \geq b+d`
      * The equation `a+b+c+d+e+f = 31`

    ::

        sage: positive_coords = Polyhedron(ieqs=[
        ....:     [0, 1, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0],
        ....:     [0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 1]])
        sage: P = Polyhedron(ieqs=positive_coords.inequalities() + (
        ....:     [0,0,1,-1,-1,1,0], [0,0,-1,1,-1,1,0]), eqns=[[-31,1,1,1,1,1,1]])
        sage: P
        A 5-dimensional polyhedron in QQ^6 defined as the convex hull of 7 vertices
        sage: P.dim()
        5
        sage: P.Vrepresentation()
        (A vertex at (31, 0, 0, 0, 0, 0), A vertex at (0, 0, 0, 0, 0, 31),
         A vertex at (0, 0, 0, 0, 31, 0), A vertex at (0, 0, 31/2, 0, 31/2, 0),
         A vertex at (0, 31/2, 31/2, 0, 0, 0), A vertex at (0, 31/2, 0, 0, 31/2, 0),
         A vertex at (0, 0, 0, 31/2, 31/2, 0))

    When the input contains elements of a Number Field, they require an
    embedding::

        sage: K = NumberField(x^2-2,'s')
        sage: s = K.0
        sage: L = NumberField(x^3-2,'t')
        sage: t = L.0
        sage: P = Polyhedron(vertices = [[0,s],[t,0]])
        Traceback (most recent call last):
        ...
        ValueError: invalid base ring

    .. NOTE::

      * Once constructed, a ``Polyhedron`` object is immutable.

      * Although the option ``base_ring=RDF`` allows numerical data to
        be used, it might not give the right answer for degenerate
        input data - the results can depend upon the tolerance
        setting of cdd.


    TESTS:

    Check that giving ``float`` input gets converted to ``RDF`` (see :trac:`22605`)::

        sage: f = float(1.1)
        sage: Polyhedron(vertices=[[f]])
        A 0-dimensional polyhedron in RDF^1 defined as the convex hull of 1 vertex

    Check that giving ``int`` input gets converted to ``ZZ`` (see :trac:`22605`)::

        sage: Polyhedron(vertices=[[int(42)]])
        A 0-dimensional polyhedron in ZZ^1 defined as the convex hull of 1 vertex

    Check that giving ``Fraction`` input gets converted to ``QQ`` (see :trac:`22605`)::

        sage: from fractions import Fraction
        sage: f = Fraction(int(6), int(8))
        sage: Polyhedron(vertices=[[f]])
        A 0-dimensional polyhedron in QQ^1 defined as the convex hull of 1 vertex

    Check that input with too many bits of precision returns an error (see
    :trac:`22552`)::

        sage: Polyhedron(vertices=[(8.3319544851638732, 7.0567045956967727), (6.4876921900819049, 4.8435898415984129)])
        Traceback (most recent call last):
        ...
        ValueError: for polyhedra with floating point numbers, the only allowed ring is RDF with backend 'cdd'
    
    Check that setting ``base_ring`` to a ``RealField`` returns an error (see :trac:`22552`)::
    
        sage: Polyhedron(vertices =[(8.3, 7.0), (6.4, 4.8)], base_ring=RealField(40))
        Traceback (most recent call last):
        ...
        ValueError: no appropriate backend for computations with Real Field with 40 bits of precision
        sage: Polyhedron(vertices =[(8.3, 7.0), (6.4, 4.8)], base_ring=RealField(53))
        Traceback (most recent call last):
        ...
        ValueError: no appropriate backend for computations with Real Field with 53 bits of precision
    """
    # Clean up the arguments
    vertices = _make_listlist(vertices)
    rays = _make_listlist(rays)
    lines = _make_listlist(lines)
    ieqs = _make_listlist(ieqs)
    eqns = _make_listlist(eqns)

    got_Vrep = (len(vertices + rays + lines) > 0)
    got_Hrep = (len(ieqs + eqns) > 0)

    if got_Vrep and got_Hrep:
        raise ValueError('cannot specify both H- and V-representation.')
    elif got_Vrep:
        deduced_ambient_dim = _common_length_of(vertices, rays, lines)[1]
    elif got_Hrep:
        deduced_ambient_dim = _common_length_of(ieqs, eqns)[1] - 1
    else:
        if ambient_dim is None:
            deduced_ambient_dim = 0
        else:
            deduced_ambient_dim = ambient_dim
        if base_ring is None:
            base_ring = ZZ

    # set ambient_dim
    if ambient_dim is not None and deduced_ambient_dim != ambient_dim:
        raise ValueError(
            'ambient space dimension mismatch. Try removing the "ambient_dim" parameter.'
        )
    ambient_dim = deduced_ambient_dim

    # figure out base_ring
    from sage.misc.flatten import flatten
    from sage.structure.element import parent
    from sage.categories.all import Rings, Fields

    values = flatten(vertices + rays + lines + ieqs + eqns)
    if base_ring is not None:
        convert = any(parent(x) is not base_ring for x in values)
    elif not values:
        base_ring = ZZ
        convert = False
    else:
        P = parent(values[0])
        if any(parent(x) is not P for x in values):
            from sage.structure.sequence import Sequence
            P = Sequence(values).universe()
            convert = True
        else:
            convert = False

        from sage.structure.coerce import py_scalar_parent
        if isinstance(P, type):
            base_ring = py_scalar_parent(P)
            convert = convert or P is not base_ring
        else:
            base_ring = P

        if not got_Vrep and base_ring not in Fields():
            base_ring = base_ring.fraction_field()
            convert = True

        if base_ring not in Rings():
            raise ValueError('invalid base ring')

        if not base_ring.is_exact():
            # TODO: remove this hack?
            if base_ring is RR:
                base_ring = RDF
                convert = True
            elif base_ring is not RDF:
                raise ValueError(
                    "for polyhedra with floating point numbers, the only allowed ring is RDF with backend 'cdd'"
                )

    # Add the origin if necessary
    if got_Vrep and len(vertices) == 0:
        vertices = [[0] * ambient_dim]

    # Specific backends can override the base_ring
    from sage.geometry.polyhedron.parent import Polyhedra
    parent = Polyhedra(base_ring, ambient_dim, backend=backend)
    base_ring = parent.base_ring()

    # finally, construct the Polyhedron
    Hrep = Vrep = None
    if got_Hrep:
        Hrep = [ieqs, eqns]
    if got_Vrep:
        Vrep = [vertices, rays, lines]
    return parent(Vrep, Hrep, convert=convert, verbose=verbose)
Beispiel #42
0
    def __init__(self, vector_list, backend=None):
        r"""
        Construct a vector configuration.

        INPUT:

        - ``vector_list`` -- a list of vectors

        - ``backend`` -- a string, a polyhedral backend or``None`` (default)

        OUTPUT:

        A vector configuration.


        EXAMPLES::

            sage: from cn_hyperarr.vector_classes import *
            sage: vc = VectorConfiguration([[1,0,0],[0,1,0],[0,0,1],[1,1,0],[0,1,1],[1,1,1]])
            sage: vc
            Vector configuration of 6 vectors in dimension 3
            sage: vc.ambient_dimension()
            3
            sage: vc.vectors()
            ((1, 0, 0), (0, 1, 0), (0, 0, 1), (1, 1, 0), (0, 1, 1), (1, 1, 1))

        The same vector configuration with backend ``'normaliz'``::

            sage: vc = VectorConfiguration([[1,0,0],[0,1,0],[0,0,1],[1,1,0],[0,1,1],[1,1,1]], backend = 'normaliz')  # optional - pynormaliz
            sage: vc                                    # optional - pynormaliz
            Vector configuration of 6 vectors in dimension 3
            sage: vc.backend()                          # optional - pynormaliz
            'normaliz'

        The vectors should all have the same dimension::

            sage: vc = VectorConfiguration([[1,0,0],[0,1,0,0]])
            Traceback (most recent call last):
            ...
            AssertionError: The vectors are not all of the same dimension

        The list of vectors can have repeats::

            sage: vc = VectorConfiguration([[0,0],[0,0]])
            sage: vc
            Vector configuration of 2 vectors in dimension 2

        TESTS:

        An empty vector configuration::

            sage: vc = VectorConfiguration([])
            sage: vc.vectors()
            ()
            sage: vc.ambient_dimension()
            -1
        """
        values = flatten([list(v) for v in vector_list])
        br = Sequence(values).universe()
        self._base_ring = br
        vector_list = tuple(vector(br, v, immutable=True) for v in vector_list)
        self._nb_vectors = len(vector_list)
        self._vectors = vector_list
        if self._nb_vectors == 0:
            self._dimension = -1
        else:
            self._dimension = len(self._vectors[0])
        # add that empty configuration has dim -1
        self._backend = backend
        if self._nb_vectors != 0:
            assert set([len(v) for v in self._vectors]) == set([
                self._dimension
            ]), "The vectors are not all of the same dimension"
Beispiel #43
0
    def _fill(self, shape):
        r"""
        Return the highest weight KR tableau of weight ``shape``.

        INPUT:

        - ``shape`` -- The weight of the highest weight KR tableau (the
          conjugate of the shape of the KR crystal's tableau)

        OUTPUT:

        - A `r \times s` tableau

        EXAMPLES::

            sage: KRT = KirillovReshetikhinTableaux(['D', 4, 1], 2, 1)
            sage: KRT._fill([])
            [[1], [-1]]
            sage: KRT = KirillovReshetikhinTableaux(['D', 14, 1], 12, 7)
            sage: KRT._fill([10,10,8,2,2,2])
            [[1, 1, 1, 1, 1, 7, 1], [2, 2, 2, 2, 2, 8, 2], [3, 3, 7, 9, 7, 9, 3], [4, 4, 8, 10, 8, 10, 4], [5, 5, 9, 11, 9, 11, 5], [6, 6, 10, 12, 10, 12, 6], [7, 7, 11, -12, 11, -12, 7], [8, 8, 12, -11, 12, -11, 8], [9, 9, -12, -10, -12, -10, 9], [10, 10, -11, -9, -11, -9, -9], [-12, 11, -10, -8, -10, -8, -8], [-11, 12, -9, -7, -9, -7, -7]]
            sage: KRT._fill([10,10,6,2,2,2])
            [[1, 1, 1, 1, 1, 5, 1], [2, 2, 2, 2, 2, 6, 2], [3, 3, 9, 7, 9, 7, 3], [4, 4, 10, 8, 10, 8, 4], [5, 5, 11, 9, 11, 9, 5], [6, 6, 12, 10, 12, 10, 6], [7, 7, -12, 11, -12, 11, 7], [8, 8, -11, 12, -11, 12, 8], [9, 9, -10, -12, -10, -12, -8], [10, 10, -9, -11, -9, -11, -7], [-12, 11, -8, -10, -8, -10, -6], [-11, 12, -7, -9, -7, -9, -5]]    
        """
        # Add zeros until the shape has length s
        shape_list = list(shape) # Make sure we have a list
        while len(shape_list) != self._s:
            shape_list.append(0)

        tableau = []
        i = 0
        # Step 0 - Fill first columns of height r
        while i < self._s and shape_list[i] == self._r:
            tableau.append( [self._r - j for j in range(self._r)] )
            i += 1

        # Step 1 - Add the alternating columns until we hit an odd number of columns
        c = -1
        while i < self._s:
            # If it is an odd number of columns
            if i == self._s - 1 or shape_list[i] != shape_list[i+1]:
                c = shape_list[i]
                i += 1
                break
            temp_list = [-(shape_list[i] + j + 1) for j in range(self._r - shape_list[i])]
            for j in range(shape_list[i]):
                temp_list.append(shape_list[i] - j)
            tableau.append(temp_list)
            tableau.append( [self._r - j for j in range(self._r)] )
            i += 2

        # Step 2 - Add the x dependent columns
        x = c + 1
        while i < self._s:
            temp_list = [-x - j for j in range(self._r - x + 1)] # +1 for indexing
            for j in range(x - shape_list[i] - 1): # +1 for indexing
                temp_list.append(self._r - j)
            x = temp_list[-1] # This is the h+1 entry of the column
            for j in range(shape_list[i]):
                temp_list.append(shape_list[i] - j)

            tableau.append(temp_list)
            i += 1

        # Step 3 - Add the final column
        if c > -1:
            val = (self._r + x - 1) / 2
            temp_list = [-x - j for j in range(self._r - val)]
            for j in range(val):
                temp_list.append(val - j)
            tableau.append(temp_list)

        return self([self.letters(x) for x in flatten(tableau)])
Beispiel #44
0
    def characters(self):
        r"""
        Return the two conjugate characters of `K^\times`, where `K` is some
        quadratic extension of `\QQ_p`, defining this representation. An error
        will be raised in some 2-adic cases, since not all 2-adic supercuspidal
        representations arise in this way.

        EXAMPLES:

        The first example from [LW2012]_::

            sage: f = Newform('50a')
            sage: Pi = LocalComponent(f, 5)
            sage: chars = Pi.characters(); chars
            [
            Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), of level 1, mapping s |--> -d - 1, 5 |--> 1,
            Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), of level 1, mapping s |--> d, 5 |--> 1
            ]
            sage: chars[0].base_ring()
            Number Field in d with defining polynomial x^2 + x + 1

        These characters are interchanged by the Frobenius automorphism of `\GF{25}`::

            sage: chars[0] == chars[1]**5
            True

        A more complicated example (higher weight and nontrivial central character)::

            sage: f = Newforms(GammaH(25, [6]), 3, names='j')[0]; f
            q + j0*q^2 + 1/3*j0^3*q^3 - 1/3*j0^2*q^4 + O(q^6)
            sage: Pi = LocalComponent(f, 5)
            sage: Pi.characters()
            [
            Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), of level 1, mapping s |--> 1/3*j0^2*d - 1/3*j0^3, 5 |--> 5,
            Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), of level 1, mapping s |--> -1/3*j0^2*d, 5 |--> 5
            ]
            sage: Pi.characters()[0].base_ring()
            Number Field in d with defining polynomial x^2 - j0*x + 1/3*j0^2 over its base field

        .. warning::

            The above output isn't actually the same as in Example 2 of
            [LW2012]_, due to an error in the published paper (correction
            pending) -- the published paper has the inverses of the above
            characters.

        A higher level example::

            sage: f = Newform('81a', names='j'); f
            q + j0*q^2 + q^4 - j0*q^5 + O(q^6)
            sage: LocalComponent(f, 3).characters()  # long time (12s on sage.math, 2012)
            [
            Character of unramified extension Q_3(s)* (s^2 + 2*s + 2 = 0), of level 2, mapping -2*s |--> -2*d + j0, 4 |--> 1, 3*s + 1 |--> -j0*d + 1, 3 |--> 1,
            Character of unramified extension Q_3(s)* (s^2 + 2*s + 2 = 0), of level 2, mapping -2*s |--> 2*d - j0, 4 |--> 1, 3*s + 1 |--> j0*d - 2, 3 |--> 1
            ]

        Some ramified examples::

            sage: Newform('27a').local_component(3).characters()
            [
            Character of ramified extension Q_3(s)* (s^2 - 6 = 0), of level 2, mapping 2 |--> 1, s + 1 |--> -d, s |--> -1,
            Character of ramified extension Q_3(s)* (s^2 - 6 = 0), of level 2, mapping 2 |--> 1, s + 1 |--> d - 1, s |--> -1
            ]
            sage: LocalComponent(Newform('54a'), 3, twist_factor=4).characters()
            [
            Character of ramified extension Q_3(s)* (s^2 - 3 = 0), of level 2, mapping 2 |--> 1, s + 1 |--> -1/9*d, s |--> -9,
            Character of ramified extension Q_3(s)* (s^2 - 3 = 0), of level 2, mapping 2 |--> 1, s + 1 |--> 1/9*d - 1, s |--> -9
            ]

        A 2-adic non-example::

            sage: Newform('24a').local_component(2).characters()
            Traceback (most recent call last):
            ...
            ValueError: Totally ramified 2-adic representations are not classified by characters

        Examples where `K^\times / \QQ_p^\times` is not topologically cyclic
        (which complicates the computations greatly)::

            sage: Newforms(DirichletGroup(64, QQ).1, 2, names='a')[0].local_component(2).characters() # long time, random
            [
            Character of unramified extension Q_2(s)* (s^2 + s + 1 = 0), of level 3, mapping s |--> 1, 2*s + 1 |--> 1/2*a0, 4*s + 1 |--> 1, -1 |--> 1, 2 |--> 1,
            Character of unramified extension Q_2(s)* (s^2 + s + 1 = 0), of level 3, mapping s |--> 1, 2*s + 1 |--> 1/2*a0, 4*s + 1 |--> -1, -1 |--> 1, 2 |--> 1
            ]
            sage: Newform('243a',names='a').local_component(3).characters() # long time
            [
            Character of ramified extension Q_3(s)* (s^2 - 6 = 0), of level 4, mapping -2*s - 1 |--> -d - 1, 4 |--> 1, 3*s + 1 |--> -d - 1, s |--> 1,
            Character of ramified extension Q_3(s)* (s^2 - 6 = 0), of level 4, mapping -2*s - 1 |--> d, 4 |--> 1, 3*s + 1 |--> d, s |--> 1
            ]
        """
        T = self.type_space()
        p = self.prime()
        if self.conductor() % 2 == 0:

            G = SmoothCharacterGroupUnramifiedQuadratic(
                self.prime(), self.coefficient_field())
            n = self.conductor() // 2

            gs = G.quotient_gens(n)
            g = gs[-1]

            assert g.valuation(G.ideal(1)) == 0
            m = g.matrix().change_ring(ZZ).list()
            tr = (~T.rho(m)).trace()

            # The inverse is needed here because T is the *homological* type space,
            # which is dual to the cohomological one that defines the local component.

            X = polygen(self.coefficient_field())
            theta_poly = X**2 - (-1)**n * tr * X + self.central_character()(
                g.norm())
            verbose("theta_poly for %s is %s" % (g, theta_poly), level=1)
            if theta_poly.is_irreducible():
                F = self.coefficient_field().extension(theta_poly, "d")
                G = G.base_extend(F)

            # roots with repetitions allowed
            gvals = flatten([[y[0]] * y[1]
                             for y in theta_poly.roots(G.base_ring())])

            if len(gs) == 1:
                # This is always the case if p != 2
                chi1, chi2 = [
                    G.extend_character(n, self.central_character(), [x])
                    for x in gvals
                ]
            else:
                # 2-adic cases, conductor >= 64. Here life is complicated
                # because the quotient (O_K* / p^n)^* / (image of Z_2^*) is not
                # cyclic.
                g0 = gs[0]
                try:
                    G._reduce_Qp(1, g0)
                    raise ArithmeticError("Bad generators returned")
                except ValueError:
                    pass

                tr = (~T.rho(g0.matrix().list())).trace()
                X = polygen(G.base_ring())
                theta0_poly = X**2 - (
                    -1)**n * tr * X + self.central_character()(g0.norm())
                verbose("theta_poly for %s is %s" % (g0, theta_poly), level=1)
                if theta0_poly.is_irreducible():
                    F = theta0_poly.base_ring().extension(theta_poly, "e")
                    G = G.base_extend(F)
                g0vals = flatten([[y[0]] * y[1]
                                  for y in theta0_poly.roots(G.base_ring())])

                pairA = [[g0vals[0], gvals[0]], [g0vals[1], gvals[1]]]
                pairB = [[g0vals[0], gvals[1]], [g0vals[1], gvals[0]]]

                A_fail = 0
                B_fail = 0
                try:
                    chisA = [
                        G.extend_character(n, self.central_character(), [y, x])
                        for (y, x) in pairA
                    ]
                except ValueError:
                    A_fail = 1
                try:
                    chisB = [
                        G.extend_character(n, self.central_character(), [y, x])
                        for (y, x) in pairB
                    ]
                except ValueError:
                    B_fail = 1

                if chisA == chisB or chisA == reversed(chisB):
                    # repeated roots -- break symmetry arbitrarily
                    B_fail = 1

                # check the character relation from LW12
                if (not A_fail and not B_fail):
                    for x in G.ideal(n).invertible_residues():
                        try:
                            # test if G mod p is in Fp
                            flag = G._reduce_Qp(1, x)
                        except ValueError:
                            flag = None
                        if flag is not None:
                            verbose("skipping x=%s as congruent to %s mod p" %
                                    (x, flag))
                            continue

                        verbose("testing x = %s" % x, level=1)
                        ti = (-1)**n * (~T.rho(x.matrix().list())).trace()
                        verbose("  trace of matrix is %s" % ti, level=1)
                        if ti != chisA[0](x) + chisA[1](x):
                            verbose("  chisA FAILED", level=1)
                            A_fail = 1
                            break
                        if ti != chisB[0](x) + chisB[1](x):
                            verbose("  chisB FAILED", level=1)
                            B_fail = 1
                            break
                        else:
                            verbose("  Trace identity check works for both",
                                    level=1)

                if B_fail and not A_fail:
                    chi1, chi2 = chisA
                elif A_fail and not B_fail:
                    chi1, chi2 = chisB
                else:
                    raise ValueError(
                        "Something went wrong: can't identify the characters")

            # Consistency checks
            assert chi1.restrict_to_Qp() == chi2.restrict_to_Qp(
            ) == self.central_character()
            assert chi1 * chi2 == chi1.parent().compose_with_norm(
                self.central_character())

            return Sequence([chi1, chi2], check=False, cr=True)

        else:
            # The ramified case.

            n = self.conductor() - 1
            if p == 2:
                # The ramified 2-adic representations aren't classified by admissible pairs. Die.
                raise ValueError(
                    "Totally ramified 2-adic representations are not classified by characters"
                )

            G0 = SmoothCharacterGroupRamifiedQuadratic(
                p, 0, self.coefficient_field())
            G1 = SmoothCharacterGroupRamifiedQuadratic(
                p, 1, self.coefficient_field())
            q0 = G0.quotient_gens(n)
            assert all(x.valuation(G0.ideal(1)) == 1 for x in q0)
            q1 = G1.quotient_gens(n)
            assert all(x.valuation(G1.ideal(1)) == 1 for x in q1)

            t0 = [(~T.rho(q.matrix().list())).trace() for q in q0]
            t1 = [(~T.rho(q.matrix().list())).trace() for q in q1]

            if all(x == 0 for x in t0 + t1):
                # Can't happen?
                raise NotImplementedError(
                    "Can't identify ramified quadratic extension -- all traces zero"
                )
            elif all(x == 0 for x in t1):
                G, qs, ts = G0, q0, t0
            elif all(x == 0 for x in t0):
                G, qs, ts = G1, q1, t1
            else:
                # At least one of the traces is *always* 0, since the type
                # space has to be isomorphic to its twist by the (ramified
                # quadratic) character corresponding to the quadratic
                # extension.
                raise RuntimeError("Can't get here!")

            q = qs[0]
            t = ts[0]
            k = self.newform().weight()
            t *= p**ZZ((k - 2 + self.twist_factor()) / 2)

            X = polygen(self.coefficient_field())
            theta_poly = X**2 - X * t + self.central_character()(q.norm())
            verbose("theta_poly is %s" % theta_poly, level=1)
            if theta_poly.is_irreducible():
                F = self.coefficient_field().extension(theta_poly, "d")
                G = G.base_extend(F)
            c1q, c2q = flatten([[x] * e
                                for x, e in theta_poly.roots(G.base_ring())])

            if len(qs) == 1:
                chi1, chi2 = [
                    G.extend_character(n, self.central_character(), [x])
                    for x in [c1q, c2q]
                ]

            else:
                assert p == 3
                q = qs[1]
                t = ts[1]
                t *= p**ZZ((k - 2 + self.twist_factor()) / 2)

                X = polygen(G.base_ring())
                theta_poly = X**2 - X * t + self.central_character()(q.norm())
                verbose("theta_poly is %s" % theta_poly, level=1)
                if theta_poly.is_irreducible():
                    F = G.base_ring().extension(theta_poly, "e")
                    G = G.base_extend(F)
                c1q2, c2q2 = flatten(
                    [[x] * e for x, e in theta_poly.roots(G.base_ring())])

                pairA = [[c1q, c1q2], [c2q, c2q2]]
                pairB = [[c1q, c2q2], [c2q, c1q2]]

                A_fail = 0
                B_fail = 0
                try:
                    chisA = [
                        G.extend_character(n, self.central_character(), [x, y])
                        for (x, y) in pairA
                    ]
                except ValueError:
                    verbose('A failed to create', level=1)
                    A_fail = 1
                try:
                    chisB = [
                        G.extend_character(n, self.central_character(), [x, y])
                        for (x, y) in pairB
                    ]
                except ValueError:
                    verbose('A failed to create', level=1)
                    B_fail = 1

                if c1q == c2q or c1q2 == c2q2:
                    B_fail = 1

                for u in G.ideal(n).invertible_residues():
                    if A_fail or B_fail:
                        break
                    x = q * u
                    verbose("testing x = %s" % x, level=1)
                    ti = (~T.rho(x.matrix().list())).trace() * p**ZZ(
                        (k - 2 + self.twist_factor()) / 2)
                    verbose("trace of matrix is %s" % ti, level=1)
                    if chisA[0](x) + chisA[1](x) != ti:
                        A_fail = 1
                    if chisB[0](x) + chisB[1](x) != ti:
                        B_fail = 1

                if B_fail and not A_fail:
                    chi1, chi2 = chisA
                elif A_fail and not B_fail:
                    chi1, chi2 = chisB
                else:
                    raise ValueError(
                        "Something went wrong: can't identify the characters")

            # Consistency checks
            assert chi1.restrict_to_Qp() == chi2.restrict_to_Qp(
            ) == self.central_character()
            assert chi1 * chi2 == chi1.parent().compose_with_norm(
                self.central_character())

            return Sequence([chi1, chi2], check=False, cr=True)
Beispiel #45
0
def subexpressions_list(f, pars=None):
    """
    Construct the lists with the intermediate steps on the evaluation of the
    function.

    INPUT:

    - ``f`` -- a symbolic function of several components.

    - ``pars`` -- a list of the parameters that appear in the function
      this should be the symbolic constants that appear in f but are not
      arguments.

    OUTPUT:

    - a list of the intermediate subexpressions that appear in the evaluation
      of f.

    - a list with the operations used to construct each of the subexpressions.
      each element of this list is a tuple, formed by a string describing the
      operation made, and the operands.

    For the trigonometric functions, some extra expressions will be added.
    These extra expressions will be used later to compute their derivatives.


    EXAMPLES::

        sage: from sage.interfaces.tides import subexpressions_list
        sage: var('x,y')
        (x, y)
        sage: f(x,y) = [x^2+y, cos(x)/log(y)]
        sage: subexpressions_list(f)
        ([x^2, x^2 + y, sin(x), cos(x), log(y), cos(x)/log(y)],
        [('mul', x, x),
        ('add', y, x^2),
        ('sin', x),
        ('cos', x),
        ('log', y),
        ('div', log(y), cos(x))])

    ::

        sage: f(a)=[cos(a), arctan(a)]
        sage: from sage.interfaces.tides import subexpressions_list
        sage: subexpressions_list(f)
        ([sin(a), cos(a), a^2, a^2 + 1, arctan(a)],
        [('sin', a), ('cos', a), ('mul', a, a), ('add', 1, a^2), ('atan', a)])

    ::

        sage: from sage.interfaces.tides import subexpressions_list
        sage: var('s,b,r')
        (s, b, r)
        sage: f(t,x,y,z)= [s*(y-x),x*(r-z)-y,x*y-b*z]
        sage: subexpressions_list(f,[s,b,r])
        ([-y,
        x - y,
        s*(x - y),
        -s*(x - y),
        -z,
        r - z,
        (r - z)*x,
        -y,
        (r - z)*x - y,
        x*y,
        b*z,
        -b*z,
        x*y - b*z],
        [('mul', -1, y),
        ('add', -y, x),
        ('mul', x - y, s),
        ('mul', -1, s*(x - y)),
        ('mul', -1, z),
        ('add', -z, r),
        ('mul', x, r - z),
        ('mul', -1, y),
        ('add', -y, (r - z)*x),
        ('mul', y, x),
        ('mul', z, b),
        ('mul', -1, b*z),
        ('add', -b*z, x*y)])

    ::

        sage: var('x, y')
        (x, y)
        sage: f(x,y)=[exp(x^2+sin(y))]
        sage: from sage.interfaces.tides import *
        sage: subexpressions_list(f)
        ([x^2, sin(y), cos(y), x^2 + sin(y), e^(x^2 + sin(y))],
        [('mul', x, x),
        ('sin', y),
        ('cos', y),
        ('add', sin(y), x^2),
        ('exp', x^2 + sin(y))])


    """
    from sage.functions.trig import sin, cos, arcsin, arctan, arccos
    variables = f[0].arguments()
    if not pars:
        parameters = []
    else:
        parameters = pars
    varpar = list(parameters) + list(variables)
    F = symbolic_expression([i(*variables) for i in f]).function(*varpar)
    lis = flatten([fast_callable(i,vars=varpar).op_list() for i in F], max_level=1)
    stack = []
    const =[]
    stackcomp=[]
    detail=[]
    for i in lis:
        if i[0] == 'load_arg':
            stack.append(varpar[i[1]])
        elif i[0] == 'ipow':
            if i[1] in NN:
                basis = stack[-1]
                for j in range(i[1]-1):
                    a=stack.pop(-1)
                    detail.append(('mul', a, basis))
                    stack.append(a*basis)
                    stackcomp.append(stack[-1])
            else:
                detail.append(('pow',stack[-1],i[1]))
                stack[-1]=stack[-1]**i[1]
                stackcomp.append(stack[-1])

        elif i[0] == 'load_const':
            const.append(i[1])
            stack.append(i[1])
        elif i == 'mul':
            a=stack.pop(-1)
            b=stack.pop(-1)
            detail.append(('mul', a, b))
            stack.append(a*b)
            stackcomp.append(stack[-1])

        elif i == 'div':
            a=stack.pop(-1)
            b=stack.pop(-1)
            detail.append(('div', a, b))
            stack.append(b/a)
            stackcomp.append(stack[-1])

        elif i == 'add':
            a=stack.pop(-1)
            b=stack.pop(-1)
            detail.append(('add',a,b))
            stack.append(a+b)
            stackcomp.append(stack[-1])

        elif i == 'pow':
            a=stack.pop(-1)
            b=stack.pop(-1)
            detail.append(('pow', b, a))
            stack.append(b**a)
            stackcomp.append(stack[-1])

        elif i[0] == 'py_call' and str(i[1])=='log':
            a=stack.pop(-1)
            detail.append(('log', a))
            stack.append(log(a))
            stackcomp.append(stack[-1])

        elif i[0] == 'py_call' and str(i[1])=='exp':
            a=stack.pop(-1)
            detail.append(('exp', a))
            stack.append(exp(a))
            stackcomp.append(stack[-1])

        elif i[0] == 'py_call' and str(i[1])=='sin':
            a=stack.pop(-1)
            detail.append(('sin', a))
            detail.append(('cos', a))
            stackcomp.append(sin(a))
            stackcomp.append(cos(a))
            stack.append(sin(a))

        elif i[0] == 'py_call' and str(i[1])=='cos':
            a=stack.pop(-1)
            detail.append(('sin', a))
            detail.append(('cos', a))
            stackcomp.append(sin(a))
            stackcomp.append(cos(a))
            stack.append(cos(a))

        elif i[0] == 'py_call' and str(i[1])=='tan':
            a=stack.pop(-1)
            b = sin(a)
            c = cos(a)
            detail.append(('sin', a))
            detail.append(('cos', a))
            detail.append(('div', b, c))
            stackcomp.append(b)
            stackcomp.append(c)
            stackcomp.append(b/c)
            stack.append(b/c)

        elif i[0] == 'py_call' and str(i[1])=='arctan':
            a=stack.pop(-1)
            detail.append(('mul', a, a))
            detail.append(('add', 1, a*a))
            detail.append(('atan', a))
            stackcomp.append(a*a)
            stackcomp.append(1+a*a)
            stackcomp.append(arctan(a))
            stack.append(arctan(a))

        elif i[0] == 'py_call' and str(i[1])=='arcsin':
            a=stack.pop(-1)
            detail.append(('mul', a, a))
            detail.append(('mul', -1, a*a))
            detail.append(('add', 1, -a*a))
            detail.append(('pow', 1- a*a, 0.5))
            detail.append(('asin', a))
            stackcomp.append(a*a)
            stackcomp.append(-a*a)
            stackcomp.append(1-a*a)
            stackcomp.append(sqrt(1-a*a))
            stackcomp.append(arcsin(a))
            stack.append(arcsin(a))

        elif i[0] == 'py_call' and str(i[1])=='arccos':
            a=stack.pop(-1)
            detail.append(('mul', a, a))
            detail.append(('mul', -1, a*a))
            detail.append(('add', 1, -a*a))
            detail.append(('pow', 1- a*a, 0.5))
            detail.append(('mul', -1, sqrt(1-a*a)))
            detail.append(('acos', a))
            stackcomp.append(a*a)
            stackcomp.append(-a*a)
            stackcomp.append(1-a*a)
            stackcomp.append(sqrt(1-a*a))
            stackcomp.append(-sqrt(1-a*a))
            stackcomp.append(arccos(a))
            stack.append(arccos(a))

        elif i[0] == 'py_call' and 'sqrt' in str(i[1]):
            a=stack.pop(-1)
            detail.append(('pow', a, 0.5))
            stackcomp.append(sqrt(a))
            stack.append(sqrt(a))


        elif i == 'neg':
            a = stack.pop(-1)
            detail.append(('mul', -1, a))
            stack.append(-a)
            stackcomp.append(-a)

    return stackcomp,detail
    def graded_submodule(self, indices, **kwds):
        r"""
        The submodule which contains all elements of given 
        grading values.
        
        INPUT:
            - ``indices`` -- A list or tuple of grading values or a single grading value.
            - ``**kwds``  -- A dictionary of keywords; They will be passed to the
                             submodule constructor.
        
        OUTPUT:
            An instance of :class:~`fourier_expansion_framework.gradedexpansions.gradedexpansion_submodule.GradedExpansionSubmodule_abstract`.

        TESTS::
            sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *
            sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *
            sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_module import *
            sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *
            sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_grading import DegreeGrading
            sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_ring import *
            sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_module import *
            sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))
            sage: ger = GradedExpansionRing_class(None, Sequence([MonoidPowerSeries(mps, {1 : 4, 2 : 3}, mps.monoid().filter(4)), MonoidPowerSeries(mps, {1 : 1, 2 : 3}, mps.monoid().filter(4))]), PolynomialRing(ZZ, ['a', 'b']).ideal(0), DegreeGrading((1,2)))
            sage: sm = ger.graded_submodule(2)
            sage: ger = GradedExpansionRing_class(None, Sequence([MonoidPowerSeries(mps, {1 : 4, 2 : 3}, mps.monoid().filter_all()), MonoidPowerSeries(mps, {1 : 1, 2 : 3}, mps.monoid().filter_all())]), PolynomialRing(ZZ, ['a', 'b']).ideal(0), DegreeGrading((1,2)))
            sage: sm = ger.graded_submodule(3)
            sage: P.<a,b,c> = PolynomialRing(QQ)
            sage: ger = GradedExpansionRing_class(None, Sequence([MonoidPowerSeries(mps, {1 : 4, 2 : 3}, mps.monoid().filter_all()), MonoidPowerSeries(mps, {1 : 1, 2 : 3}, mps.monoid().filter_all()), MonoidPowerSeries(mps, {2 : 1, 3: 6, 4 : 9}, mps.monoid().filter_all())]), P.ideal(b^2 - c), DegreeGrading((1,2)))
            sage: sm = ger.graded_submodule(4)
            sage: m = FreeModule(QQ, 3)
            sage: mpsm = MonoidPowerSeriesModule(m, NNMonoid(False))
            sage: mps = mpsm.base_ring()
            sage: ger = GradedExpansionModule_class(None, Sequence([MonoidPowerSeries(mpsm, {1 : m([1,2,3]), 2 : m([3,-3,2])}, mpsm.monoid().filter(4)), MonoidPowerSeries(mpsm, {1 : m([2,-1,-1]), 2 : m([1,0,0])}, mpsm.monoid().filter(4))]), PolynomialRing(ZZ, ['a', 'b']).ideal(0), DegreeGrading((1,2)))
            sage: ger.graded_submodule(4).rank()
            0
        """
        #=======================================================================
        # if not self.graded_submodules_are_free() :
        #    raise ValueError( "Graded submodules of must be free." )
        #=======================================================================

        if indices in self.grading():
            indices = tuple([indices])
        elif isinstance(indices, list):
            indices = tuple(indices)
        elif not isinstance(indices, tuple):
            raise TypeError("Wrong type of indices.")

        try:
            return self.__graded_submodules[indices]
        except KeyError:
            pass

        module_gens = flatten(map(self._graded_monoms, indices), max_level=1)

        if self.has_relation_free_generators():
            basis = module_gens
        else:
            module_gens_poly = map(lambda g: g.polynomial(), module_gens)
            basis = list()

            I = self.relations().ring().zero_ideal()
            for i, g in enumerate(module_gens_poly):
                rg = I.reduce(g)

                if not rg.is_zero():
                    I = I.ring().ideal([rg] + list(I.gens_reduced()))
                    basis.append(module_gens[i])

        self.__graded_submodules[indices] = self._submodule(
            basis, grading_indices=indices, **kwds)

        return self.__graded_submodules[indices]
Beispiel #47
0
    def __classcall_private__(cls, p):
        r"""
        This function tries to recognize the input (it can be either a list or
        a tuple of pairs, or a fix-point free involution given as a list or as
        a permutation), constructs the parent (enumerated set of
        PerfectMatchings of the ground set) and calls the __init__ function to
        construct our object.

        EXAMPLES::

            sage: m = PerfectMatching([('a','e'),('b','c'),('d','f')]);m
            [('a', 'e'), ('b', 'c'), ('d', 'f')]
            sage: isinstance(m,PerfectMatching)
            True
            sage: n = PerfectMatching([3, 8, 1, 7, 6, 5, 4, 2]);n
            [(1, 3), (2, 8), (4, 7), (5, 6)]
            sage: n.parent()
            Set of perfect matchings of {1, 2, 3, 4, 5, 6, 7, 8}
            sage: PerfectMatching([(1, 4), (2, 3), (5, 6)]).is_non_crossing()
            True

        The function checks that the given list or permutation is a valid perfect
        matching (i.e. a list of pairs with pairwise disjoint elements  or a
        fixpoint-free involution) and raises a ValueError otherwise:

            sage: PerfectMatching([(1, 2, 3), (4, 5)])
            Traceback (most recent call last):
            ...
            ValueError: [(1, 2, 3), (4, 5)] is not a valid perfect matching: all elements of the list must be pairs

        If you know your datas are in a good format, use directly
        ``PerfectMatchings(objects)(data)``.

        TESTS::

             sage: m = PerfectMatching([('a','e'),('b','c'),('d','f')])
             sage: TestSuite(m).run()
             sage: m = PerfectMatching([])
             sage: TestSuite(m).run()
             sage: PerfectMatching(6)
             Traceback (most recent call last):
             ...
             ValueError: cannot convert p (= 6) to a PerfectMatching
             sage: PerfectMatching([(1,2,3)])
             Traceback (most recent call last):
             ...
             ValueError: [(1, 2, 3)] is not a valid perfect matching:
             all elements of the list must be pairs
             sage: PerfectMatching([(1,1)])
             Traceback (most recent call last):
             ...
             ValueError: [(1, 1)] is not a valid perfect matching:
             there are some repetitions
             sage: PerfectMatching(Permutation([4,2,1,3]))
             Traceback (most recent call last):
             ...
             ValueError: The permutation p (= [4, 2, 1, 3]) is not a fixed point free involution
        """
        # we have to extract from the argument p the set of objects of the
        # matching and the list of pairs.
        # First case: p is a list (resp tuple) of lists (resp tuple).
        if (isinstance(p, list) or isinstance(p, tuple)) and (
                all([isinstance(x, list) or isinstance(x, tuple) for x in p])):
            objects = Set(flatten(p))
            data = (map(tuple, p))
            #check if the data are correct
            if not all([len(t) == 2 for t in data]):
                raise ValueError("%s is not a valid perfect matching:\n"
                                 "all elements of the list must be pairs" % p)
            if len(objects) < 2*len(data):
                raise ValueError("%s is not a valid perfect matching:\n"
                                 "there are some repetitions" % p)
        # Second case: p is a permutation or a list of integers, we have to
        # check if it is a fix-point-free involution.
        elif ((isinstance(p, list) and
               all(map(lambda x: (isinstance(x, Integer) or isinstance(x, int)), p)))
              or isinstance(p, Permutation)):
            p = Permutation(p)
            n = len(p)
            if not(p.cycle_type() == [2 for i in range(n//2)]):
                raise ValueError("The permutation p (= %s) is not a "
                                 "fixed point free involution" % p)
            objects = Set(range(1, n+1))
            data = p.to_cycles()
        # Third case: p is already a perfect matching, we return p directly
        elif isinstance(p, PerfectMatching):
            return p
        else:
            raise ValueError("cannot convert p (= %s) to a PerfectMatching" % p)
        # Finally, we create the parent and the element using the element
        # class of the parent. Note: as this function is private, when we
        # create an object via parent.element_class(...), __init__ is directly
        # executed and we do not have an infinite loop.
        return PerfectMatchings(objects)(data)
Beispiel #48
0
    def plot(self, **kwds):
        r"""
        Plot the initial triangulation associated to ``self``.

        INPUT:

        - ``radius`` - the radius of the disk; by default the length of
          the circle is the number of vertices
        - ``points_color`` - the color of the vertices; default 'black'
        - ``points_size`` - the size of the vertices; default 7
        - ``triangulation_color`` - the color of the arcs; default 'black'
        - ``triangulation_thickness`` - the thickness of the arcs; default 0.5
        - ``shading_color`` - the color of the shading used on neuter
          intervals; default 'lightgray'
        - ``reflections_color`` - the color of the reflection axes; default
          'blue'
        - ``reflections_thickness`` - the thickness of the reflection axes;
          default 1

        EXAMPLES::

            sage: Y = SineGordonYsystem('A',(6,4,3));
            sage: Y.plot()      # not tested
        """
        # Set up plotting options
        if 'radius' in kwds:
            radius = kwds['radius']
        else:
            radius = ceil(self.r() / (2 * pi))
        points_opts = {}
        if 'points_color' in kwds:
            points_opts['color'] = kwds['points_color']
        else:
            points_opts['color'] = 'black'
        if 'points_size' in kwds:
            points_opts['size'] = kwds['points_size']
        else:
            points_opts['size'] = 7
        triangulation_opts = {}
        if 'triangulation_color' in kwds:
            triangulation_opts['color'] = kwds['triangulation_color']
        else:
            triangulation_opts['color'] = 'black'
        if 'triangulation_thickness' in kwds:
            triangulation_opts['thickness'] = kwds['triangulation_thickness']
        else:
            triangulation_opts['thickness'] = 0.5
        shading_opts = {}
        if 'shading_color' in kwds:
            shading_opts['color'] = kwds['shading_color']
        else:
            shading_opts['color'] = 'lightgray'
        reflections_opts = {}
        if 'reflections_color' in kwds:
            reflections_opts['color'] = kwds['reflections_color']
        else:
            reflections_opts['color'] = 'blue'
        if 'reflections_thickness' in kwds:
            reflections_opts['thickness'] = kwds['reflections_thickness']
        else:
            reflections_opts['thickness'] = 1
        # Helper functions

        def triangle(x):
            (a, b) = sorted(x[:2])
            for p in self.vertices():
                if (p, a) in self.triangulation() or (a, p) in self.triangulation():
                    if (p, b) in self.triangulation() or (b, p) in self.triangulation():
                        if p < a or p > b:
                            return sorted((a, b, p))

        def plot_arc(radius, p, q, **opts):
            # plot the arc from p to q differently depending on the type of self
            p = ZZ(p)
            q = ZZ(q)
            t = var('t')
            if p - q in [1, -1]:
                def f(t):
                    return (radius * cos(t), radius * sin(t))
                (p, q) = sorted([p, q])
                angle_p = vertex_to_angle(p)
                angle_q = vertex_to_angle(q)
                return parametric_plot(f(t), (t, angle_q, angle_p), **opts)
            if self.type() == 'A':
                angle_p = vertex_to_angle(p)
                angle_q = vertex_to_angle(q)
                if angle_p < angle_q:
                    angle_p += 2 * pi
                internal_angle = angle_p - angle_q
                if internal_angle > pi:
                    (angle_p, angle_q) = (angle_q + 2 * pi, angle_p)
                    internal_angle = angle_p - angle_q
                angle_center = (angle_p+angle_q) / 2
                hypotenuse = radius / cos(internal_angle / 2)
                radius_arc = hypotenuse * sin(internal_angle / 2)
                center = (hypotenuse * cos(angle_center),
                          hypotenuse * sin(angle_center))
                center_angle_p = angle_p + pi / 2
                center_angle_q = angle_q + 3 * pi / 2

                def f(t):
                    return (radius_arc * cos(t) + center[0],
                            radius_arc * sin(t) + center[1])
                return parametric_plot(f(t), (t, center_angle_p,
                                              center_angle_q), **opts)
            elif self.type() == 'D':
                if p >= q:
                    q += self.r()
                px = -2 * pi * p / self.r() + pi / 2
                qx = -2 * pi * q / self.r() + pi / 2
                arc_radius = (px - qx) / 2
                arc_center = qx + arc_radius

                def f(t):
                    return exp(I * ((cos(t) + I * sin(t)) *
                                    arc_radius + arc_center)) * radius
                return parametric_plot((real_part(f(t)), imag_part(f(t))),
                                       (t, 0, pi), **opts)

        def vertex_to_angle(v):
            # v==0 corresponds to pi/2
            return -2 * pi * RR(v) / self.r() + 5 * pi / 2

        # Begin plotting
        P = Graphics()
        # Shade neuter intervals
        neuter_intervals = [x for x in flatten(self.intervals()[:-1],
                                               max_level=1)
                            if x[2] in ["NR", "NL"]]
        shaded_triangles = map(triangle, neuter_intervals)
        for (p, q, r) in shaded_triangles:
            points = list(plot_arc(radius, p, q)[0])
            points += list(plot_arc(radius, q, r)[0])
            points += list(reversed(plot_arc(radius, p, r)[0]))
            P += polygon2d(points, **shading_opts)
        # Disk boundary
        P += circle((0, 0), radius, **triangulation_opts)
        # Triangulation
        for (p, q) in self.triangulation():
            P += plot_arc(radius, p, q, **triangulation_opts)
        if self.type() == 'D':
            s = radius / 50.0
            P += polygon2d([(s, 5 * s), (s, 7 * s),
                            (3 * s, 5 * s), (3 * s, 7 * s)],
                           color=triangulation_opts['color'])
            P += bezier_path([[(0, 0), (2 * s, 1 * s), (2 * s, 6 * s)],
                              [(2 * s, 10 * s), (s, 20 * s)],
                              [(0, 30 * s), (0, radius)]],
                             **triangulation_opts)
            P += bezier_path([[(0, 0), (-2 * s, 1 * s), (-2 * s, 6 * s)],
                              [(-2 * s, 10 * s), (-s, 20 * s)],
                              [(0, 30 * s), (0, radius)]],
                             **triangulation_opts)
            P += point((0, 0), zorder=len(P), **points_opts)
        # Vertices
        v_points = {x: (radius * cos(vertex_to_angle(x)),
                        radius * sin(vertex_to_angle(x)))
                    for x in self.vertices()}
        for v in v_points:
            P += point(v_points[v], zorder=len(P), **points_opts)
        # Reflection axes
        P += line([(0, 1.1 * radius), (0, -1.1 * radius)],
                  zorder=len(P), **reflections_opts)
        axis_angle = vertex_to_angle(-0.5 * (self.rk() + (1, 1))[1])
        (a, b) = (1.1 * radius * cos(axis_angle),
                  1.1 * radius * sin(axis_angle))
        P += line([(a, b), (-a, -b)], zorder=len(P), **reflections_opts)
        # Wrap up
        P.set_aspect_ratio(1)
        P.axes(False)
        return P
Beispiel #49
0
    def _fill(self, shape):
        r"""
        Return the highest weight KR tableau of weight ``shape``.

        INPUT:

        - ``shape`` -- The weight of the highest weight KR tableau (the
          conjugate of the shape of the KR crystal's tableau)

        OUTPUT:

        - A `r \times s` tableau

        EXAMPLES::

            sage: KRT = KirillovReshetikhinTableaux(['D', 4, 1], 2, 1)
            sage: KRT._fill([])
            [[1], [-1]]
            sage: KRT = KirillovReshetikhinTableaux(['D', 14, 1], 12, 7)
            sage: KRT._fill([10,10,8,2,2,2])
            [[1, 1, 1, 1, 1, 7, 1], [2, 2, 2, 2, 2, 8, 2], [3, 3, 7, 9, 7, 9, 3], [4, 4, 8, 10, 8, 10, 4], [5, 5, 9, 11, 9, 11, 5], [6, 6, 10, 12, 10, 12, 6], [7, 7, 11, -12, 11, -12, 7], [8, 8, 12, -11, 12, -11, 8], [9, 9, -12, -10, -12, -10, 9], [10, 10, -11, -9, -11, -9, -9], [-12, 11, -10, -8, -10, -8, -8], [-11, 12, -9, -7, -9, -7, -7]]
            sage: KRT._fill([10,10,6,2,2,2])
            [[1, 1, 1, 1, 1, 5, 1], [2, 2, 2, 2, 2, 6, 2], [3, 3, 9, 7, 9, 7, 3], [4, 4, 10, 8, 10, 8, 4], [5, 5, 11, 9, 11, 9, 5], [6, 6, 12, 10, 12, 10, 6], [7, 7, -12, 11, -12, 11, 7], [8, 8, -11, 12, -11, 12, 8], [9, 9, -10, -12, -10, -12, -8], [10, 10, -9, -11, -9, -11, -7], [-12, 11, -8, -10, -8, -10, -6], [-11, 12, -7, -9, -7, -9, -5]]
        """
        # Add zeros until the shape has length s
        shape_list = list(shape)  # Make sure we have a list
        while len(shape_list) != self._s:
            shape_list.append(0)

        tableau = []
        i = 0
        # Step 0 - Fill first columns of height r
        while i < self._s and shape_list[i] == self._r:
            tableau.append([self._r - j for j in range(self._r)])
            i += 1

        # Step 1 - Add the alternating columns until we hit an odd number of columns
        c = -1
        while i < self._s:
            # If it is an odd number of columns
            if i == self._s - 1 or shape_list[i] != shape_list[i + 1]:
                c = shape_list[i]
                i += 1
                break
            temp_list = [
                -(shape_list[i] + j + 1)
                for j in range(self._r - shape_list[i])
            ]
            for j in range(shape_list[i]):
                temp_list.append(shape_list[i] - j)
            tableau.append(temp_list)
            tableau.append([self._r - j for j in range(self._r)])
            i += 2

        # Step 2 - Add the x dependent columns
        x = c + 1
        while i < self._s:
            temp_list = [-x - j
                         for j in range(self._r - x + 1)]  # +1 for indexing
            for j in range(x - shape_list[i] - 1):  # +1 for indexing
                temp_list.append(self._r - j)
            x = temp_list[-1]  # This is the h+1 entry of the column
            for j in range(shape_list[i]):
                temp_list.append(shape_list[i] - j)

            tableau.append(temp_list)
            i += 1

        # Step 3 - Add the final column
        if c > -1:
            val = (self._r + x - 1) / 2
            temp_list = [-x - j for j in range(self._r - val)]
            for j in range(val):
                temp_list.append(val - j)
            tableau.append(temp_list)

        return self([self.letters(x) for x in flatten(tableau)])
Beispiel #50
0
def OM_tree(Phi):
    r"""
    Return an tree of OM (Okutsu-Montes/Ore-Mac Lane) representations for Phi.

    INPUT:

    - ``Phi`` -- squarefree, monic padic polynomial with fixed precision
      coefficients

    OUTPUT:

    The leaves of the OM tree of ``Phi`` as a list of Frames.

    EXAMPLES::

        sage: from sage.rings.polynomial.padics.factor.factoring import OM_tree
        sage: Phi = ZpFM(2,20,'terse')['x'](x^32+16)
        sage: OM_tree(Phi)
        [Frame with phi (1 + O(2^20))*x^16 + (1048572 + O(2^20))*x^10 + (1048572 + O(2^20))*x^8 + (1048572 + O(2^20))*x^5 + (4 + O(2^20))*x^4 + (8 + O(2^20))*x^2 + (4 + O(2^20))]

    """
    from sage.misc.flatten import flatten

    def followsegment(next,Phi):
        """
        Returns next if it corresponds to an irreducible factor of $\Phi$ 
        and follows every branch if not.

        """
        # Handle the unlikely event that our approximation is actually a factor
        if next.is_first() == False and next.phi == next.prev_frame().phi:
            return [next]
        if next.phi_divides_Phi():
            return [next]+[[followsegment(fact.next_frame(fact.rhoexp+1),Phi)
                            for fact in seg.factors] for seg in next.polygon[1:]]
        # With E potentially increased, Check to see if E*F == deg(Phi)
        # (and thus Phi is irreducible)
        if next.E * next.F * next.polygon[0].Eplus == Phi.degree():
            return next
        # With F potentially increaded, Check to see if E*F == deg(Phi)
        # (and thus Phi is irreducible)
        if (next.E * next.polygon[0].Eplus * 
                next.F * next.polygon[0].factors[0].Fplus) == Phi.degree():
            return next
        # Check if we should begin Single Factor Lifting
        if sum([seg.length for seg in next.polygon]) == 1:
            return next
        return [[followsegment(fact.next_frame(fact.rhoexp+1),Phi)
                 for fact in seg.factors] for seg in next.polygon]

    # Construct and initialize the first frame (phi = x)
    next = Frame(Phi)
    next.seed(Phi.parent().gen())

    # With E potentially increased, Check to see if E*F == deg(Phi)
    # (and thus Phi is irreducible)
    if next.E * next.F * next.polygon[0].Eplus == Phi.degree():
        return [next]

    # With F potentially increaded, Check to see if E*F == deg(Phi)
    # (and thus Phi is irreducible)
    if (next.E * next.polygon[0].Eplus * 
            next.F * next.polygon[0].factors[0].Fplus) == Phi.degree():
        return [next]

    # Handle the special case wherein our initial approximation (phi = x) is a factor
    if next.phi_divides_Phi():
        tree = [next] + [[followsegment(fact.next_frame(fact.rhoexp+1),Phi)
                          for fact in seg.factors] for seg in next.polygon[1:]]

    # Construct the next level of the tree by following every factor of the
    # residual polynomials of every Newton polygon segment in our frame
    else:
        tree = [[followsegment(fact.next_frame(fact.rhoexp+1),Phi)
                 for fact in seg.factors] for seg in next.polygon]

    # tree contains the leaves of the tree of frames and each leaf corresponds
    # to an irreducible factor of Phi, so we flatten the list and start lifting
    return flatten(tree)
Beispiel #51
0
def GL_irreducible_character(n, mu, KK):
    r"""
    Return the character of the irreducible module indexed by ``mu``
    of `GL(n)` over the field ``KK``.

    INPUT:

    - ``n`` -- a positive integer
    - ``mu`` -- a partition of at most ``n`` parts
    - ``KK`` -- a field

    OUTPUT:

    a symmetric function which should be interpreted in ``n``
    variables to be meaningful as a character

    EXAMPLES:

    Over `\QQ`, the irreducible character for `\mu` is the Schur
    function associated to `\mu`, plus garbage terms (Schur
    functions associated to partitions with more than `n` parts)::

        sage: from sage.algebras.schur_algebra import GL_irreducible_character
        sage: sbasis = SymmetricFunctions(QQ).s()
        sage: z = GL_irreducible_character(2, [2], QQ)
        sage: sbasis(z)
        s[2]

        sage: z = GL_irreducible_character(4, [3, 2], QQ)
        sage: sbasis(z)
        -5*s[1, 1, 1, 1, 1] + s[3, 2]

    Over a Galois field, the irreducible character for `\mu` will
    in general be smaller.

    In characteristic `p`, for a one-part partition `(r)`, where
    `r = a_0 + p a_1 + p^2 a_2 + \dots`, the result is (see [Gr2007]_,
    after 5.5d) the product of `h[a_0], h[a_1]( pbasis[p]), h[a_2]
    ( pbasis[p^2]), \dots,` which is consistent with the following ::

        sage: from sage.algebras.schur_algebra import GL_irreducible_character
        sage: GL_irreducible_character(2, [7], GF(3))
        m[4, 3] + m[6, 1] + m[7]
    """
    mbasis = SymmetricFunctions(QQ).m()
    r = sum(mu)
    M = SchurTensorModule(KK, n, r)
    A = M._schur
    SGA = M._sga

    #make ST the superstandard tableau of shape mu
    from sage.combinat.tableau import from_shape_and_word
    ST = from_shape_and_word(mu, list(range(1, r + 1)), convention='English')

    #make ell the reading word of the highest weight tableau of shape mu
    ell = [i + 1 for i, l in enumerate(mu) for dummy in range(l)]

    e = M.basis()[tuple(ell)]  # the element e_l

    # This is the notation `\{X\}` from just before (5.3a) of [Gr2007]_.
    S = SGA._indices
    BracC = SGA._from_dict(
        {S(x.tuple()): x.sign()
         for x in ST.column_stabilizer()},
        remove_zeros=False)
    f = e * BracC  # M.action_by_symmetric_group_algebra(e, BracC)

    # [Green, Theorem 5.3b] says that a basis of the Carter-Lusztig
    # module V_\mu is given by taking this f, and multiplying by all
    # xi_{i,ell} with ell as above and i semistandard.

    carter_lusztig = []
    for T in SemistandardTableaux(mu, max_entry=n):
        i = tuple(flatten(T))
        schur_rep = schur_representative_from_index(i, tuple(ell))
        y = A.basis(
        )[schur_rep] * e  # M.action_by_Schur_alg(A.basis()[schur_rep], e)
        carter_lusztig.append(y.to_vector())

    #Therefore, we now have carter_lusztig as a list giving the basis
    #of `V_\mu`

    #We want to think of expressing this character as a sum of monomial
    #symmetric functions.

    #We will determine a basis element for each m_\lambda in the
    #character, and we want to keep track of them by \lambda.

    #That means that we only want to pick out the basis elements above for
    #those semistandard words whose content is a partition.

    contents = Partitions(r, max_length=n).list()
    # all partitions of r, length at most n

    # JJ will consist of a list for each element of `contents`,
    # recording the list
    # of semistandard tableaux words with that content

    # graded_basis will consist of the a corresponding basis element
    graded_basis = []
    JJ = []
    for i in range(len(contents)):
        graded_basis.append([])
        JJ.append([])
    for T in SemistandardTableaux(mu, max_entry=n):
        i = tuple(flatten(T))
        # Get the content of T
        con = [0] * n
        for a in i:
            con[a - 1] += 1
        try:
            P = Partition(con)
            P_index = contents.index(P)
            JJ[P_index].append(i)
            schur_rep = schur_representative_from_index(i, tuple(ell))
            x = A.basis(
            )[schur_rep] * f  # M.action_by_Schur_alg(A.basis()[schur_rep], f)
            graded_basis[P_index].append(x.to_vector())
        except ValueError:
            pass

    #There is an inner product on the Carter-Lusztig module V_\mu; its
    #maximal submodule is exactly the kernel of the inner product.

    #Now, for each possible partition content, we look at the graded piece of
    #that degree, and we record how these elements pair with each of the
    #elements of carter_lusztig.

    #The kernel of this pairing is the part of this graded piece which is
    #not in the irreducible module for \mu.

    length = len(carter_lusztig)

    phi = mbasis.zero()
    for aa in range(len(contents)):
        mat = []
        for kk in range(len(JJ[aa])):
            temp = []
            for j in range(length):
                temp.append(graded_basis[aa][kk].inner_product(
                    carter_lusztig[j]))
            mat.append(temp)
        angle = Matrix(mat)
        phi += (len(JJ[aa]) - angle.nullity()) * mbasis(contents[aa])
    return phi
Beispiel #52
0
    def plot(self, **kwds):
        r"""
        Plot the initial triangulation associated to ``self``.

        INPUT:

        - ``radius`` - the radius of the disk; by default the length of
          the circle is the number of vertices
        - ``points_color`` - the color of the vertices; default 'black'
        - ``points_size`` - the size of the vertices; default 7
        - ``triangulation_color`` - the color of the arcs; default 'black'
        - ``triangulation_thickness`` - the thickness of the arcs; default 0.5
        - ``shading_color`` - the color of the shading used on neuter
          intervals; default 'lightgray'
        - ``reflections_color`` - the color of the reflection axes; default
          'blue'
        - ``reflections_thickness`` - the thickness of the reflection axes;
          default 1

        EXAMPLES::

            sage: Y = SineGordonYsystem('A',(6,4,3))
            sage: Y.plot()  # long time 2s
            Graphics object consisting of 219 graphics primitives
        """
        # Set up plotting options
        if 'radius' in kwds:
            radius = kwds['radius']
        else:
            radius = ceil(self.r() / (2 * pi))
        points_opts = {}
        if 'points_color' in kwds:
            points_opts['color'] = kwds['points_color']
        else:
            points_opts['color'] = 'black'
        if 'points_size' in kwds:
            points_opts['size'] = kwds['points_size']
        else:
            points_opts['size'] = 7
        triangulation_opts = {}
        if 'triangulation_color' in kwds:
            triangulation_opts['color'] = kwds['triangulation_color']
        else:
            triangulation_opts['color'] = 'black'
        if 'triangulation_thickness' in kwds:
            triangulation_opts['thickness'] = kwds['triangulation_thickness']
        else:
            triangulation_opts['thickness'] = 0.5
        shading_opts = {}
        if 'shading_color' in kwds:
            shading_opts['color'] = kwds['shading_color']
        else:
            shading_opts['color'] = 'lightgray'
        reflections_opts = {}
        if 'reflections_color' in kwds:
            reflections_opts['color'] = kwds['reflections_color']
        else:
            reflections_opts['color'] = 'blue'
        if 'reflections_thickness' in kwds:
            reflections_opts['thickness'] = kwds['reflections_thickness']
        else:
            reflections_opts['thickness'] = 1
        # Helper functions

        def triangle(x):
            (a, b) = sorted(x[:2])
            for p in self.vertices():
                if (p, a) in self.triangulation() or (a, p) in self.triangulation():
                    if (p, b) in self.triangulation() or (b, p) in self.triangulation():
                        if p < a or p > b:
                            return sorted((a, b, p))

        def plot_arc(radius, p, q, **opts):
            # TODO: THIS SHOULD USE THE EXISTING PLOT OF ARCS!
            # plot the arc from p to q differently depending on the type of self
            p = ZZ(p)
            q = ZZ(q)
            t = var('t')
            if p - q in [1, -1]:
                def f(t):
                    return (radius * cos(t), radius * sin(t))
                (p, q) = sorted([p, q])
                angle_p = vertex_to_angle(p)
                angle_q = vertex_to_angle(q)
                return parametric_plot(f(t), (t, angle_q, angle_p), **opts)
            if self.type() == 'A':
                angle_p = vertex_to_angle(p)
                angle_q = vertex_to_angle(q)
                if angle_p < angle_q:
                    angle_p += 2 * pi
                internal_angle = angle_p - angle_q
                if internal_angle > pi:
                    (angle_p, angle_q) = (angle_q + 2 * pi, angle_p)
                    internal_angle = angle_p - angle_q
                angle_center = (angle_p+angle_q) / 2
                hypotenuse = radius / cos(internal_angle / 2)
                radius_arc = hypotenuse * sin(internal_angle / 2)
                center = (hypotenuse * cos(angle_center),
                          hypotenuse * sin(angle_center))
                center_angle_p = angle_p + pi / 2
                center_angle_q = angle_q + 3 * pi / 2

                def f(t):
                    return (radius_arc * cos(t) + center[0],
                            radius_arc * sin(t) + center[1])
                return parametric_plot(f(t), (t, center_angle_p,
                                              center_angle_q), **opts)
            elif self.type() == 'D':
                if p >= q:
                    q += self.r()
                px = -2 * pi * p / self.r() + pi / 2
                qx = -2 * pi * q / self.r() + pi / 2
                arc_radius = (px - qx) / 2
                arc_center = qx + arc_radius

                def f(t):
                    return exp(I * ((cos(t) + I * sin(t)) *
                                    arc_radius + arc_center)) * radius
                return parametric_plot((real_part(f(t)), imag_part(f(t))),
                                       (t, 0, pi), **opts)

        def vertex_to_angle(v):
            # v==0 corresponds to pi/2
            return -2 * pi * RR(v) / self.r() + 5 * pi / 2

        # Begin plotting
        P = Graphics()
        # Shade neuter intervals
        neuter_intervals = [x for x in flatten(self.intervals()[:-1],
                                               max_level=1)
                            if x[2] in ["NR", "NL"]]
        shaded_triangles = map(triangle, neuter_intervals)
        for (p, q, r) in shaded_triangles:
            points = list(plot_arc(radius, p, q)[0])
            points += list(plot_arc(radius, q, r)[0])
            points += list(reversed(plot_arc(radius, p, r)[0]))
            P += polygon2d(points, **shading_opts)
        # Disk boundary
        P += circle((0, 0), radius, **triangulation_opts)
        # Triangulation
        for (p, q) in self.triangulation():
            P += plot_arc(radius, p, q, **triangulation_opts)
        if self.type() == 'D':
            s = radius / 50.0
            P += polygon2d([(s, 5 * s), (s, 7 * s),
                            (3 * s, 5 * s), (3 * s, 7 * s)],
                           color=triangulation_opts['color'])
            P += bezier_path([[(0, 0), (2 * s, 1 * s), (2 * s, 6 * s)],
                              [(2 * s, 10 * s), (s, 20 * s)],
                              [(0, 30 * s), (0, radius)]],
                             **triangulation_opts)
            P += bezier_path([[(0, 0), (-2 * s, 1 * s), (-2 * s, 6 * s)],
                              [(-2 * s, 10 * s), (-s, 20 * s)],
                              [(0, 30 * s), (0, radius)]],
                             **triangulation_opts)
            P += point((0, 0), zorder=len(P), **points_opts)
        # Vertices
        v_points = {x: (radius * cos(vertex_to_angle(x)),
                        radius * sin(vertex_to_angle(x)))
                    for x in self.vertices()}
        for v in v_points:
            P += point(v_points[v], zorder=len(P), **points_opts)
        # Reflection axes
        P += line([(0, 1.1 * radius), (0, -1.1 * radius)],
                  zorder=len(P), **reflections_opts)
        axis_angle = vertex_to_angle(-0.5 * (self.rk() + (1, 1))[1])
        (a, b) = (1.1 * radius * cos(axis_angle),
                  1.1 * radius * sin(axis_angle))
        P += line([(a, b), (-a, -b)], zorder=len(P), **reflections_opts)
        # Wrap up
        P.set_aspect_ratio(1)
        P.axes(False)
        return P
Beispiel #53
0
    def extrude_edge(self, vertex, dart1, dart2):
        r"""
        Return a ribbon graph resulting from extruding an edge from a
        vertex, pulling from it, all darts from ``dart1`` to ``dart2``
        including both.

        INPUT:

        - ``vertex`` -- the position of the vertex in the permutation
          `\sigma`, which must have valency at least 2

        - ``dart1`` -- the position of the first in the
          cycle corresponding to ``vertex``

        - ``dart2`` -- the position of the second dart in the cycle
          corresponding to ``vertex``

        OUTPUT:

        A ribbon graph resulting from extruding a new edge that 
        pulls from ``vertex`` a new vertex that is, now, adjacent
        to all the darts from ``dart1``to ``dart2`` (not including
        ``dart2``) in the cyclic ordering given by the cycle corresponding
        to ``vertex``. Note that ``dart1`` may be equal to ``dart2``
        allowing thus to extrude a contractible edge from a vertex.

        EXAMPLES:

        We try several possibilities in the same graph::

            sage: s1 = PermutationGroupElement('(1,3,5)(2,4,6)')
            sage: r1 = PermutationGroupElement('(1,2)(3,4)(5,6)')
            sage: R1 = RibbonGraph(s1,r1); R1
            Ribbon graph of genus 1 and 1 boundary components
            sage: E1 = R1.extrude_edge(1,1,2); E1
            Ribbon graph of genus 1 and 1 boundary components
            sage: E1.sigma()
            (1,3,5)(2,8,6)(4,7)
            sage: E1.rho()
            (1,2)(3,4)(5,6)(7,8)
            sage: E2 = R1.extrude_edge(1,1,3); E2
            Ribbon graph of genus 1 and 1 boundary components
            sage: E2.sigma()
            (1,3,5)(2,8)(4,6,7)
            sage: E2.rho()
            (1,2)(3,4)(5,6)(7,8)

        We can also extrude a contractible edge from a vertex. This
        new edge will end at a vertex of valency 1::

            sage: E1p = R1.extrude_edge(0,0,0); E1p
            Ribbon graph of genus 1 and 1 boundary components
            sage: E1p.sigma()
            (1,3,5,8)(2,4,6)
            sage: E1p.rho()
            (1,2)(3,4)(5,6)(7,8)

        In the following example we first extrude one edge from a vertex
        of valency 3 generating a new vertex of valency 2. Then we 
        extrude a new edge from this vertex of valency 2::

            sage: s1 = PermutationGroupElement('(1,3,5)(2,4,6)')
            sage: r1 = PermutationGroupElement('(1,2)(3,4)(5,6)')
            sage: R1 = RibbonGraph(s1,r1); R1
            Ribbon graph of genus 1 and 1 boundary components
            sage: E1 = R1.extrude_edge(0,0,1); E1
            Ribbon graph of genus 1 and 1 boundary components
            sage: E1.sigma()
            (1,7)(2,4,6)(3,5,8)
            sage: E1.rho()
            (1,2)(3,4)(5,6)(7,8)
            sage: F1 = E1.extrude_edge(0,0,1); F1
            Ribbon graph of genus 1 and 1 boundary components
            sage: F1.sigma()
            (1,9)(2,4,6)(3,5,8)(7,10)
            sage: F1.rho()
            (1,2)(3,4)(5,6)(7,8)(9,10)
        """
        #We first compute the vertices of valency 1 as in _repr_
        repr_sigma = [list(x) for x in self._sigma.cycle_tuples()]
        repr_rho = [list(x) for x in self._rho.cycle_tuples()]
        darts_rho = flatten(repr_rho)
        darts_sigma = flatten(repr_sigma)
        val_one = [x for x in darts_rho if x not in darts_sigma]
        for val in val_one:
            repr_sigma += [[val]]

        # We find which is the highes value a dart has, in order to
        #   add new darts that do not conflict with previous ones.
        k = max(darts_rho)

        # We create the new vertex and append it to sigma.
        new_vertex = [repr_sigma[vertex][j] for j in range(dart1, dart2)]
        new_vertex.insert(0, k + 1)
        repr_sigma.append(new_vertex)

        # We add the new dart at the vertex from which we are extruding
        #   an edge. Also we delete the darts that have been extruded.
        repr_sigma[vertex].insert(dart1, k + 2)
        del repr_sigma[vertex][dart1 + 1:dart2 + 1]

        #We update rho
        repr_rho.append([k + 1, k + 2])

        perm_group = self._sigma.parent()
        return RibbonGraph(
            PermutationGroupElement([tuple(x) for x in repr_sigma]),
            PermutationGroupElement([tuple(x) for x in repr_rho]))
Beispiel #54
0
def update_stats(verbose=True):
    from data_mgt.utilities.rewrite import update_attribute_stats
    from bson.code import Code
    ec = C.elliptic_curves
    ecdbstats = ec.nfcurves.stats

    # get list of degrees

    degrees = nfcurves.distinct('degree')
    if verbose:
        print("degrees: {}".format(degrees))

    # get list of signatures for each degree.  Note that it would not
    # work to use nfcurves.find({'degree':d}).distinct('signature')
    # since 'signature' is currently a list of integers an mongo would
    # return a list of integers, not a list of lists.  With hindsight
    # it would have been better to store the signature as a string.

    if verbose:
        print("Adding signatures_by_degree")
    reducer = Code("""function(key,values){return Array.sum(values);}""")
    attr = 'signature'
    mapper = Code("""function(){emit(""+this."""+attr+""",1);}""")
    sigs_by_deg = {}
    for d in degrees:
        sigs_by_deg[str(d)] = [ r['_id'] for r in nfcurves.inline_map_reduce(mapper,reducer,query={'degree':d})]
        if verbose:
            print("degree {} has signatures {}".format(d,sigs_by_deg[str(d)]))

    entry = {'_id': 'signatures_by_degree'}
    ecdbstats.delete_one(entry)
    entry.update(sigs_by_deg)
    ecdbstats.insert_one(entry)

    # get list of fields for each signature.  Simple code here faster than map/reduce

    if verbose:
        print("Adding fields_by_signature")
    from sage.misc.flatten import flatten
    sigs = flatten(sigs_by_deg.values())
    fields_by_sig = dict([sig,nfcurves.find({'signature':[int(x) for x in sig.split(",")]}).distinct('field_label')] for sig in sigs)
    entry = {'_id': 'fields_by_signature'}
    ecdbstats.delete_one(entry)
    entry.update(fields_by_sig)
    ecdbstats.insert_one(entry)

    # get list of fields for each degree

    if verbose:
        print("Adding fields_by_degree")
    fields_by_deg = dict([str(d),sorted(nfcurves.find({'degree':d}).distinct('field_label')) ] for d in degrees)
    entry = {'_id': 'fields_by_degree'}
    ecdbstats.delete_one(entry)
    entry.update(fields_by_deg)
    ecdbstats.insert_one(entry)

    fields = flatten(fields_by_deg.values())
    if verbose:
        print("{} fields, {} signatures, {} degrees".format(len(fields),len(sigs),len(degrees)))

    if verbose:
        print("Adding curve counts for torsion order, torsion structure")
    update_attribute_stats(ec, 'nfcurves', ['torsion_order', 'torsion_structure'])

    if verbose:
        print("Adding curve counts by degree, signature and field")
    update_attribute_stats(ec, 'nfcurves', ['degree', 'signature', 'field_label'])

    if verbose:
        print("Adding class counts by degree, signature and field")
    update_attribute_stats(ec, 'nfcurves', ['degree', 'signature', 'field_label'],
                           prefix="classes", filter={'number':int(1)})

    # conductor norm ranges:
    # total:
    if verbose:
        print("Adding curve and class counts and conductor range")
    norms = ec.nfcurves.distinct('conductor_norm')
    data = {'ncurves': ec.nfcurves.count(),
            'nclasses': ec.nfcurves.find({'number':1}).count(),
            'min_norm': min(norms),
            'max_norm': max(norms),
            }
    entry = {'_id': 'conductor_norm'}
    ecdbstats.delete_one(entry)
    entry.update(data)
    ecdbstats.insert_one(entry)

    # by degree:
    if verbose:
        print("Adding curve and class counts and conductor range, by degree")
    degree_data = {}
    for d in degrees:
        query = {'degree':d}
        res = nfcurves.find(query)
        ncurves = res.count()
        Ns = res.distinct('conductor_norm')
        min_norm = min(Ns)
        max_norm = max(Ns)
        query['number'] = 1
        nclasses = nfcurves.count(query)
        degree_data[str(d)] = {'ncurves':ncurves,
                               'nclasses':nclasses,
                               'min_norm':min_norm,
                               'max_norm':max_norm,
        }

    entry = {'_id': 'conductor_norm_by_degree'}
    ecdbstats.delete_one(entry)
    entry.update(degree_data)
    ecdbstats.insert_one(entry)

    # by signature:
    if verbose:
        print("Adding curve and class counts and conductor range, by signature")
    sig_data = {}
    for sig in sigs:
        query = {'signature': [int(c) for c in sig.split(",")]}
        res = nfcurves.find(query)
        ncurves = res.count()
        Ns = res.distinct('conductor_norm')
        min_norm = min(Ns)
        max_norm = max(Ns)
        query['number'] = 1
        nclasses = nfcurves.count(query)
        sig_data[sig] = {'ncurves':ncurves,
                               'nclasses':nclasses,
                               'min_norm':min_norm,
                               'max_norm':max_norm,
        }
    entry = {'_id': 'conductor_norm_by_signature'}
    ecdbstats.delete_one(entry)
    entry.update(sig_data)
    ecdbstats.insert_one(entry)

    # by field:
    if verbose:
        print("Adding curve and class counts and conductor range, by field")
    entry = {'_id': 'conductor_norm_by_field'}
    ecdbstats.delete_one(entry)
    field_data = {}
    for f in fields:
        ff = f.replace(".",":") # mongo does not allow "." in key strings
        query = {'field_label': f}
        res = nfcurves.find(query)
        ncurves = res.count()
        Ns = res.distinct('conductor_norm')
        min_norm = min(Ns)
        max_norm = max(Ns)
        query['number'] = 1
        nclasses = nfcurves.count(query)
        field_data[ff] = {'ncurves':ncurves,
                               'nclasses':nclasses,
                               'min_norm':min_norm,
                               'max_norm':max_norm,
        }
    entry = {'_id': 'conductor_norm_by_field'}
    ecdbstats.delete_one(entry)
    entry.update(field_data)
    ecdbstats.insert_one(entry)
Beispiel #55
0
def Polyhedron(vertices=None,
               rays=None,
               lines=None,
               ieqs=None,
               eqns=None,
               ambient_dim=None,
               base_ring=None,
               minimize=True,
               verbose=False,
               backend=None):
    """
    Construct a polyhedron object.

    You may either define it with vertex/ray/line or
    inequalities/equations data, but not both. Redundant data will
    automatically be removed (unless ``minimize=False``), and the
    complementary representation will be computed.

    INPUT:

    - ``vertices`` -- list of point. Each point can be specified as
      any iterable container of ``base_ring`` elements. If ``rays`` or
      ``lines`` are specified but no ``vertices``, the origin is
      taken to be the single vertex.

    - ``rays`` -- list of rays. Each ray can be specified as any
      iterable container of ``base_ring`` elements.

    - ``lines`` -- list of lines. Each line can be specified as any
      iterable container of ``base_ring`` elements.

    - ``ieqs`` -- list of inequalities. Each line can be specified as any
      iterable container of ``base_ring`` elements. An entry equal to
      ``[-1,7,3,4]`` represents the inequality `7x_1+3x_2+4x_3\geq 1`.

    - ``eqns`` -- list of equalities. Each line can be specified as
      any iterable container of ``base_ring`` elements. An entry equal to
      ``[-1,7,3,4]`` represents the equality `7x_1+3x_2+4x_3= 1`.

    - ``base_ring`` -- a sub-field of the reals implemented in
      Sage. The field over which the polyhedron will be defined. For
      ``QQ`` and algebraic extensions, exact arithmetic will be
      used. For ``RDF``, floating point numbers will be used. Floating
      point arithmetic is faster but might give the wrong result for
      degenerate input.

    - ``ambient_dim`` -- integer. The ambient space dimension. Usually
      can be figured out automatically from the H/Vrepresentation
      dimensions.

    - ``backend`` -- string or ``None`` (default). The backend to use. Valid choices are

      * ``'cdd'``: use cdd
        (:mod:`~sage.geometry.polyhedron.backend_cdd`) with `\QQ` or
        `\RDF` coefficients depending on ``base_ring``.

      * ``'ppl'``: use ppl
        (:mod:`~sage.geometry.polyhedron.backend_ppl`) with `\ZZ` or
        `\QQ` coefficients depending on ``base_ring``.

      * ``'field'``: use python implementation
        (:mod:`~sage.geometry.polyhedron.backend_field`) for any field

    Some backends support further optional arguments:

    - ``minimize`` -- boolean (default: ``True``). Whether to
      immediately remove redundant H/V-representation data. Currently
      not used.

    - ``verbose`` -- boolean (default: ``False``). Whether to print
      verbose output for debugging purposes. Only supported by the cdd
      backends.

    OUTPUT:

    The polyhedron defined by the input data.

    EXAMPLES:

    Construct some polyhedra::

        sage: square_from_vertices = Polyhedron(vertices = [[1, 1], [1, -1], [-1, 1], [-1, -1]])
        sage: square_from_ieqs = Polyhedron(ieqs = [[1, 0, 1], [1, 1, 0], [1, 0, -1], [1, -1, 0]])
        sage: list(square_from_ieqs.vertex_generator())
        [A vertex at (1, -1),
         A vertex at (1, 1),
         A vertex at (-1, 1),
         A vertex at (-1, -1)]
        sage: list(square_from_vertices.inequality_generator())
        [An inequality (1, 0) x + 1 >= 0,
         An inequality (0, 1) x + 1 >= 0,
         An inequality (-1, 0) x + 1 >= 0,
         An inequality (0, -1) x + 1 >= 0]
        sage: p = Polyhedron(vertices = [[1.1, 2.2], [3.3, 4.4]], base_ring=RDF)
        sage: p.n_inequalities()
        2

    The same polyhedron given in two ways::

        sage: p = Polyhedron(ieqs = [[0,1,0,0],[0,0,1,0]])
        sage: p.Vrepresentation()
        (A line in the direction (0, 0, 1),
         A ray in the direction (1, 0, 0),
         A ray in the direction (0, 1, 0),
         A vertex at (0, 0, 0))
        sage: q = Polyhedron(vertices=[[0,0,0]], rays=[[1,0,0],[0,1,0]], lines=[[0,0,1]])
        sage: q.Hrepresentation()
        (An inequality (1, 0, 0) x + 0 >= 0,
         An inequality (0, 1, 0) x + 0 >= 0)

    Finally, a more complicated example. Take `\mathbb{R}_{\geq 0}^6` with
    coordinates `a, b, \dots, f` and

      * The inequality `e+b \geq c+d`
      * The inequality `e+c \geq b+d`
      * The equation `a+b+c+d+e+f = 31`

    ::

        sage: positive_coords = Polyhedron(ieqs=[
        ...       [0, 1, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0],
        ...       [0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 1]])
        sage: P = Polyhedron(ieqs=positive_coords.inequalities() + (
        ...       [0,0,1,-1,-1,1,0], [0,0,-1,1,-1,1,0]), eqns=[[-31,1,1,1,1,1,1]])
        sage: P
        A 5-dimensional polyhedron in QQ^6 defined as the convex hull of 7 vertices
        sage: P.dim()
        5
        sage: P.Vrepresentation()
        (A vertex at (31, 0, 0, 0, 0, 0), A vertex at (0, 0, 0, 0, 0, 31),
         A vertex at (0, 0, 0, 0, 31, 0), A vertex at (0, 0, 31/2, 0, 31/2, 0),
         A vertex at (0, 31/2, 31/2, 0, 0, 0), A vertex at (0, 31/2, 0, 0, 31/2, 0),
         A vertex at (0, 0, 0, 31/2, 31/2, 0))

    .. NOTE::

      * Once constructed, a ``Polyhedron`` object is immutable.

      * Although the option ``field=RDF`` allows numerical data to
        be used, it might not give the right answer for degenerate
        input data - the results can depend upon the tolerance
        setting of cdd.
    """
    # Clean up the arguments
    vertices = _make_listlist(vertices)
    rays = _make_listlist(rays)
    lines = _make_listlist(lines)
    ieqs = _make_listlist(ieqs)
    eqns = _make_listlist(eqns)

    got_Vrep = (len(vertices + rays + lines) > 0)
    got_Hrep = (len(ieqs + eqns) > 0)

    if got_Vrep and got_Hrep:
        raise ValueError('You cannot specify both H- and V-representation.')
    elif got_Vrep:
        deduced_ambient_dim = _common_length_of(vertices, rays, lines)[1]
    elif got_Hrep:
        deduced_ambient_dim = _common_length_of(ieqs, eqns)[1] - 1
    else:
        if ambient_dim is None:
            deduced_ambient_dim = 0
        else:
            deduced_ambient_dim = ambient_dim
        if base_ring is None:
            base_ring = ZZ

    # set ambient_dim
    if ambient_dim is not None and deduced_ambient_dim != ambient_dim:
        raise ValueError(
            'Ambient space dimension mismatch. Try removing the "ambient_dim" parameter.'
        )
    ambient_dim = deduced_ambient_dim

    # figure out base_ring
    from sage.misc.flatten import flatten
    values = flatten(vertices + rays + lines + ieqs + eqns)
    if base_ring is not None:
        try:
            convert = not all(x.parent() is base_ring for x in values)
        except AttributeError:  # No x.parent() method?
            convert = True
    else:
        from sage.rings.integer import is_Integer
        from sage.rings.rational import is_Rational
        from sage.rings.real_double import is_RealDoubleElement
        if all(is_Integer(x) for x in values):
            if got_Vrep:
                base_ring = ZZ
            else:  # integral inequalities usually do not determine a lattice polytope!
                base_ring = QQ
            convert = False
        elif all(is_Rational(x) for x in values):
            base_ring = QQ
            convert = False
        elif all(is_RealDoubleElement(x) for x in values):
            base_ring = RDF
            convert = False
        else:
            try:
                for v in values:
                    ZZ(v)
                if got_Vrep:
                    base_ring = ZZ
                else:
                    base_ring = QQ
                convert = True
            except (TypeError, ValueError):
                from sage.structure.sequence import Sequence
                values = Sequence(values)
                common_ring = values.universe()
                if QQ.has_coerce_map_from(common_ring):
                    base_ring = QQ
                    convert = True
                elif common_ring is RR:  # DWIM: replace with RDF
                    base_ring = RDF
                    convert = True
                else:
                    base_ring = common_ring
                    convert = True

    # Add the origin if necesarry
    if got_Vrep and len(vertices) == 0:
        vertices = [[0] * ambient_dim]

    # Specific backends can override the base_ring
    from sage.geometry.polyhedron.parent import Polyhedra
    parent = Polyhedra(base_ring, ambient_dim, backend=backend)
    base_ring = parent.base_ring()

    # finally, construct the Polyhedron
    Hrep = Vrep = None
    if got_Hrep:
        Hrep = [ieqs, eqns]
    if got_Vrep:
        Vrep = [vertices, rays, lines]
    return parent(Vrep, Hrep, convert=convert, verbose=verbose)
Beispiel #56
0
def GL_irreducible_character(n, mu, KK):
    r"""
    Return the character of the irreducible module indexed by ``mu``
    of `GL(n)` over the field ``KK``.

    INPUT:

    - ``n`` -- a positive integer
    - ``mu`` -- a partition of at most ``n`` parts
    - ``KK`` -- a field

    OUTPUT:

    a symmetric function which should be interpreted in ``n``
    variables to be meaningful as a character

    EXAMPLES:

    Over `\QQ`, the irreducible character for `\mu` is the Schur
    function associated to `\mu`, plus garbage terms (Schur
    functions associated to partitions with more than `n` parts)::

        sage: from sage.algebras.schur_algebra import GL_irreducible_character
        sage: sbasis = SymmetricFunctions(QQ).s()
        sage: z = GL_irreducible_character(2, [2], QQ)
        sage: sbasis(z)
        s[2]

        sage: z = GL_irreducible_character(4, [3, 2], QQ)
        sage: sbasis(z)
        -5*s[1, 1, 1, 1, 1] + s[3, 2]

    Over a Galois field, the irreducible character for `\mu` will
    in general be smaller.

    In characteristic `p`, for a one-part partition `(r)`, where
    `r = a_0 + p a_1 + p^2 a_2 + \dots`, the result is (see [GreenPoly]_,
    after 5.5d) the product of `h[a_0], h[a_1]( pbasis[p]), h[a_2]
    ( pbasis[p^2]), \dots,` which is consistent with the following ::

        sage: from sage.algebras.schur_algebra import GL_irreducible_character
        sage: GL_irreducible_character(2, [7], GF(3))
        m[4, 3] + m[6, 1] + m[7]
    """
    mbasis = SymmetricFunctions(QQ).m()
    r = sum(mu)
    M = SchurTensorModule(KK, n, r)
    A = M._schur
    SGA = M._sga

    # make ST the superstandard tableau of shape mu
    from sage.combinat.tableau import from_shape_and_word

    ST = from_shape_and_word(mu, range(1, r + 1), convention="English")

    # make ell the reading word of the highest weight tableau of shape mu
    ell = [i + 1 for i, l in enumerate(mu) for dummy in range(l)]

    e = M.basis()[tuple(ell)]  # the element e_l

    # This is the notation `\{X\}` from just before (5.3a) of [GreenPoly]_.
    S = SGA._indices
    BracC = SGA._from_dict({S(x.tuple()): x.sign() for x in ST.column_stabilizer()}, remove_zeros=False)
    f = e * BracC  # M.action_by_symmetric_group_algebra(e, BracC)

    # [Green, Theorem 5.3b] says that a basis of the Carter-Lusztig
    # module V_\mu is given by taking this f, and multiplying by all
    # xi_{i,ell} with ell as above and i semistandard.

    carter_lusztig = []
    for T in SemistandardTableaux(mu, max_entry=n):
        i = tuple(flatten(T))
        schur_rep = schur_representative_from_index(i, tuple(ell))
        y = A.basis()[schur_rep] * e  # M.action_by_Schur_alg(A.basis()[schur_rep], e)
        carter_lusztig.append(y.to_vector())

    # Therefore, we now have carter_lusztig as a list giving the basis
    # of `V_\mu`

    # We want to think of expressing this character as a sum of monomial
    # symmetric functions.

    # We will determine a basis element for each m_\lambda in the
    # character, and we want to keep track of them by \lambda.

    # That means that we only want to pick out the basis elements above for
    # those semistandard words whose content is a partition.

    contents = Partitions(r, max_length=n).list()
    # all partitions of r, length at most n

    # JJ will consist of a list for each element of `contents`,
    # recording the list
    # of semistandard tableaux words with that content

    # graded_basis will consist of the a corresponding basis element
    graded_basis = []
    JJ = []
    for i in range(len(contents)):
        graded_basis.append([])
        JJ.append([])
    for T in SemistandardTableaux(mu, max_entry=n):
        i = tuple(flatten(T))
        # Get the content of T
        con = [0] * n
        for a in i:
            con[a - 1] += 1
        try:
            P = Partition(con)
            P_index = contents.index(P)
            JJ[P_index].append(i)
            schur_rep = schur_representative_from_index(i, tuple(ell))
            x = A.basis()[schur_rep] * f  # M.action_by_Schur_alg(A.basis()[schur_rep], f)
            graded_basis[P_index].append(x.to_vector())
        except ValueError:
            pass

    # There is an inner product on the Carter-Lusztig module V_\mu; its
    # maximal submodule is exactly the kernel of the inner product.

    # Now, for each possible partition content, we look at the graded piece of
    # that degree, and we record how these elements pair with each of the
    # elements of carter_lusztig.

    # The kernel of this pairing is the part of this graded piece which is
    # not in the irreducible module for \mu.

    length = len(carter_lusztig)

    phi = mbasis.zero()
    for aa in range(len(contents)):
        mat = []
        for kk in range(len(JJ[aa])):
            temp = []
            for j in range(length):
                temp.append(graded_basis[aa][kk].inner_product(carter_lusztig[j]))
            mat.append(temp)
        angle = Matrix(mat)
        phi += (len(JJ[aa]) - angle.nullity()) * mbasis(contents[aa])
    return phi
Beispiel #57
0
def fundamental_group(f, simplified=True, projective=False):
    r"""
    Return a presentation of the fundamental group of the complement of
    the algebraic set defined by the polynomial ``f``.

    INPUT:

    - ``f`` -- a polynomial in two variables, with coefficients in either
      the rationals or a number field with a fixed embedding in `\QQbar`

    - ``simplified`` -- boolean (default: ``True``); if set to ``True`` the
      presentation will be simplified (see below)

    - ``projective`` -- boolean (default: ``False``); if set to ``True``,
      the fundamental group of the complement of the projective completion
      of the curve will be computed, otherwise, the fundamental group of
      the complement in the affine plane will be computed

    If ``simplified`` is ``False``, the returned presentation has as
    many generators as degree of the polynomial times the points in the
    base used to create the segments that surround the discriminant. In
    this case, the generators are granted to be meridians of the curve.

    OUTPUT:

    A presentation of the fundamental group of the complement of the
    curve defined by ``f``.

    EXAMPLES::

        sage: from sage.schemes.curves.zariski_vankampen import fundamental_group # optional - sirocco
        sage: R.<x,y> = QQ[]
        sage: f = x^2 + y^3
        sage: fundamental_group(f) # optional - sirocco
        Finitely presented group < ... >
        sage: fundamental_group(f, simplified=False) # optional - sirocco
        Finitely presented group < ... >

    ::

        sage: from sage.schemes.curves.zariski_vankampen import fundamental_group # optional - sirocco
        sage: R.<x,y> = QQ[]
        sage: f = y^3 + x^3
        sage: fundamental_group(f) # optional - sirocco
        Finitely presented group < ... >

    It is also possible to have coefficients in a number field with a
    fixed embedding in `\QQbar`::

        sage: from sage.schemes.curves.zariski_vankampen import fundamental_group # optional - sirocco
        sage: zeta = QQbar['x']('x^2+x+1').roots(multiplicities=False)[0]
        sage: zeta
        -0.50000000000000000? - 0.866025403784439?*I
        sage: F = NumberField(zeta.minpoly(), 'zeta', embedding=zeta)
        sage: F.inject_variables()
        Defining zeta
        sage: R.<x,y> = F[]
        sage: f = y^3 + x^3 +zeta *x + 1
        sage: fundamental_group(f) # optional - sirocco
        Finitely presented group < x0 |  >
    """
    (x, y) = f.variables()
    F = f.base_ring()
    g = f.factor().radical().prod()
    d = g.degree(y)
    while not g.coefficient(y**d) in F or (projective and g.total_degree() > d):
        g = g.subs({x: x + y})
        d = g.degree(y)
    disc = discrim(g)
    segs = segments(disc)
    vertices = list(set(flatten(segs)))
    Faux = FreeGroup(d)
    F = FreeGroup(d * len(vertices))
    rels = []
    if projective:
        rels.append(prod(F.gen(i) for i in range(d)))
    braidscomputed = braid_in_segment([(g, seg[0], seg[1]) for seg in segs])
    for braidcomputed in braidscomputed:
        seg = (braidcomputed[0][0][1], braidcomputed[0][0][2])
        b = braidcomputed[1]
        i = vertices.index(seg[0])
        j = vertices.index(seg[1])
        for k in range(d):
            el1 = Faux([k + 1]) * b.inverse()
            el2 = k + 1
            w1 = F([sign(a)*d*i + a for a in el1.Tietze()])
            w2 = F([d*j + el2])
            rels.append(w1/w2)
    G = F / rels
    if simplified:
        return G.simplified()
    else:
        return G
Beispiel #58
0
    def wrapper(*args, **kwds):
        """
        TESTS::

            sage: from sage.rings.qqbar_decorators import handle_AA_and_QQbar
            sage: @handle_AA_and_QQbar
            ....: def return_base_ring(x):
            ....:     return x.base_ring()

            sage: P.<x> = QQbar[]
            sage: return_base_ring(x)
            Rational Field

            sage: P.<y,z> = QQbar[]
            sage: return_base_ring(y)
            Rational Field

            sage: return_base_ring(ideal(y,z))
            Rational Field

        Check that :trac:`29468` is fixed::

            sage: J = QQbar['x,y'].ideal('x^2 - y')
            sage: type(J.groebner_basis())
            <class 'sage.rings.polynomial.multi_polynomial_sequence.PolynomialSequence_generic'>
            sage: J.groebner_basis().is_immutable()
            True

        ::

            sage: @handle_AA_and_QQbar
            ....: def f(x):
            ....:     print(x.ring().base_ring())
            ....:     return x
            sage: R.<x,y> = QQbar[]
            sage: s = Sequence([x, R(sqrt(2)) * y], immutable=True)
            sage: t = f(s)
            Number Field in a with defining polynomial y^2 - 2
            sage: t.ring().base_ring()
            Algebraic Field
            sage: t.is_immutable()
            True
            sage: s == t
            True
        """

        from sage.misc.flatten import flatten
        from sage.rings.polynomial.polynomial_element import Polynomial
        from sage.rings.polynomial.multi_polynomial import MPolynomial
        from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence, is_PolynomialSequence
        from sage.rings.ideal import Ideal, Ideal_generic
        from sage.rings.qqbar import is_AlgebraicField_common, number_field_elements_from_algebraics

        if not any(
                isinstance(a, (Polynomial, MPolynomial, Ideal_generic))
                and is_AlgebraicField_common(a.base_ring())
                or is_PolynomialSequence(a)
                and is_AlgebraicField_common(a.ring().base_ring())
                for a in args):
            return func(*args, **kwds)

        polynomials = []

        for a in flatten(args, ltypes=(list, tuple, set)):
            if isinstance(a, Ideal_generic):
                polynomials.extend(a.gens())
            elif isinstance(a, Polynomial):
                polynomials.append(a)
            elif isinstance(a, MPolynomial):
                polynomials.append(a)

        orig_elems = flatten([p.coefficients() for p in polynomials])

        # We need minimal=True if these elements are over AA, because
        # same_field=True might trigger an exception otherwise.

        numfield, new_elems, morphism = number_field_elements_from_algebraics(
            orig_elems, same_field=True, minimal=True)

        elem_dict = dict(zip(orig_elems, new_elems))

        def forward_map(item):
            if isinstance(item, Ideal_generic):
                return Ideal([forward_map(g) for g in item.gens()])
            elif isinstance(item, Polynomial):
                return item.map_coefficients(elem_dict.__getitem__,
                                             new_base_ring=numfield)
            elif isinstance(item, MPolynomial):
                return item.map_coefficients(elem_dict.__getitem__,
                                             new_base_ring=numfield)
            elif is_PolynomialSequence(item):
                return PolynomialSequence(map(forward_map, item),
                                          immutable=item.is_immutable())
            elif isinstance(item, list):
                return list(map(forward_map, item))
            elif isinstance(item, dict):
                return {k: forward_map(v) for k, v in item.items()}
            elif isinstance(item, tuple):
                return tuple(map(forward_map, item))
            elif isinstance(item, set):
                return set(map(forward_map, list(item)))
            else:
                return item

        def reverse_map(item):
            if isinstance(item, Ideal_generic):
                return Ideal([reverse_map(g) for g in item.gens()])
            elif isinstance(item, Polynomial):
                return item.map_coefficients(morphism)
            elif isinstance(item, MPolynomial):
                return item.map_coefficients(morphism)
            elif is_PolynomialSequence(item):
                return PolynomialSequence(map(reverse_map, item),
                                          immutable=item.is_immutable())
            elif isinstance(item, list):
                return list(map(reverse_map, item))
            elif isinstance(item, tuple):
                return tuple(map(reverse_map, item))
            elif isinstance(item, set):
                return set(map(reverse_map, list(item)))
            else:
                return item

        args = forward_map(args)
        kwds = forward_map(kwds)

        return reverse_map(func(*args, **kwds))