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
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()
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 )
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])
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])
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
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)]])
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))
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
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])
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")
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)]),)
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
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)
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)
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])
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)))
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)
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])
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)
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]))
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
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")
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
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
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 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)
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
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)
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)
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"
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)])
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)
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]
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)
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
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)])
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)
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
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
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]))
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)
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)
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
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))