def ambient(self): r""" Return the ambient space from which ``self`` is a quotient. EXAMPLES:: sage: S = IntegerVectorsModPermutationGroup(PermutationGroup([[(1,2,3,4)]]), 6); S.ambient() Integer vectors that sum to 6 sage: S = IntegerVectorsModPermutationGroup(PermutationGroup([[(1,2,3,4)]]), 6, max_part=12); S.ambient() Integer vectors that sum to 6 with constraints: max_part=12 .. todo:: Integer vectors should accept ``max_part`` as a single argument, and the following should change:: sage: S = IntegerVectorsModPermutationGroup(PermutationGroup([[(1,2,3,4)]]), max_part=12); S.ambient() Integer vectors """ if self._sum is not None: if self._max_part <= -1: return IntegerVectors(n=self._sum) else: return IntegerVectors(n=self._sum, max_part=self._max_part) else: # Fix me once max_part should be accepted as a single # argument for integer vectors return IntegerVectors(max_part=self._max_part)
def homogenous_symmetric_function(j, x): r""" Return a complete homogeneous symmetric polynomial (:wikipedia:`Complete_homogeneous_symmetric_polynomial`). INPUT: - ``j`` -- the degree as a nonnegative integer - ``x`` -- an iterable of variables OUTPUT: A polynomial of the common parent of all entries of ``x`` EXAMPLES:: sage: from sage.rings.polynomial.omega import homogenous_symmetric_function sage: P = PolynomialRing(ZZ, 'X', 3) sage: homogenous_symmetric_function(0, P.gens()) 1 sage: homogenous_symmetric_function(1, P.gens()) X0 + X1 + X2 sage: homogenous_symmetric_function(2, P.gens()) X0^2 + X0*X1 + X1^2 + X0*X2 + X1*X2 + X2^2 sage: homogenous_symmetric_function(3, P.gens()) X0^3 + X0^2*X1 + X0*X1^2 + X1^3 + X0^2*X2 + X0*X1*X2 + X1^2*X2 + X0*X2^2 + X1*X2^2 + X2^3 """ from sage.combinat.integer_vector import IntegerVectors from sage.misc.misc_c import prod return sum( prod(xx**pp for xx, pp in zip(x, p)) for p in IntegerVectors(j, length=len(x)))
def __iter__(self): """ Iterate through the subsets of size ``self._k`` of the multiset ``self._s``. Note that each subset is represented by a list of the elements rather than a set since we can have multiplicities (no multiset data structure yet in sage). EXAMPLES:: sage: S = Subsets([1,2,2,3],2, submultiset=True) sage: S.list() [[1, 2], [1, 3], [2, 2], [2, 3]] Check that :trac:`28588` is fixed:: sage: Subsets([3,2,2], submultiset=True).list() [[], [3], [2], [3, 2], [2, 2], [3, 2, 2]] """ from sage.combinat.integer_vector import IntegerVectors elts = self._keys for iv in IntegerVectors(self._k, len(self._d), outer=[self._d[k] for k in elts]): yield sum([[elts[i]] * iv[i] for i in range(len(iv))], [])
def ambient(self): r""" Return the ambient space from which ``self`` is a quotient. EXAMPLES:: sage: S = IntegerVectorsModPermutationGroup(PermutationGroup([[(1,2,3,4)]]), 6); S.ambient() Integer vectors that sum to 6 sage: S = IntegerVectorsModPermutationGroup(PermutationGroup([[(1,2,3,4)]]), 6, max_part=12); S.ambient() Integer vectors that sum to 6 with constraints: max_part=12 sage: S = IntegerVectorsModPermutationGroup(PermutationGroup([[(1,2,3,4)]]), max_part=12); S.ambient() Integer vectors with constraints: max_part=12 """ if self._sum is not None: if self._max_part <= -1: return IntegerVectors(n=self._sum) else: return IntegerVectors(n=self._sum, max_part=self._max_part) else: return IntegerVectors(max_part=self._max_part)
def ambient(self): r""" Return the ambient space from which ``self`` is a quotient. EXAMPLES:: sage: S = IntegerVectorsModPermutationGroup(PermutationGroup([[(1,2,3,4)]])) sage: S.ambient() Integer vectors of length 4 """ return IntegerVectors(length=self.n)
def ambient(self): r""" Return the ambient space from which ``self`` is a quotient. EXAMPLES:: sage: S = IntegerVectorsModPermutationGroup(PermutationGroup([[(1,2,3,4)]])) sage: S.ambient() Integer vectors """ # TODO: Fix me once 'IntegerVectors(length=bla)' will return # the integer vectors of length bla return IntegerVectors(length=self.n)
def __iter__(self): """ EXAMPLES:: sage: from sage.combinat.words.shuffle_product import ShuffleProduct_overlapping_r sage: w, u = Word([1,2]), Word([3,4]) sage: ShuffleProduct_overlapping_r(w,u,1).list() [word: 424, word: 154, word: 442, word: 136, word: 352, word: 316] sage: w, u = map(Words(range(1,7)), [[1,2], [3,4]]) sage: W = Words(range(1,7)) sage: w, u = W([1,2]), W([3,4]) sage: ShuffleProduct_overlapping_r(w, u, 1).list() #indirect doctest [word: 424, word: 154, word: 442, word: 136, word: 352, word: 316] """ W = self._w1.parent() m = len(self._w1) n = len(self._w2) r = self.r wc1, wc2 = self._w1, self._w2 blank = [0] * (m + n - r) for iv in IntegerVectors(m, m + n - r, max_part=1): w = blank[:] filled_places = [] unfilled_places = [] #Fill in w1 into the iv slots i = 0 for j in range(len(iv)): if iv[j] == 1: w[j] = wc1[i] i += 1 filled_places.append(j) else: unfilled_places.append(j) #Choose r of these filled places for subset in Subsets(filled_places, r): places_to_fill = unfilled_places + list(subset) places_to_fill.sort() #Fill in w2 into the places i = 0 res = w[:] for j in places_to_fill: res[j] += wc2[i] i += 1 yield W(res)
def __iter__(self): """ Iterates through the subsets of size ``self._k`` of the multiset ``self._s``. Note that each subset is represented by a list of the elements rather than a set since we can have multiplicities (no multiset data structure yet in sage). EXAMPLES:: sage: S = Subsets([1,2,2,3],2, submultiset=True) sage: S.list() [[1, 2], [1, 3], [2, 2], [2, 3]] """ from sage.combinat.integer_vector import IntegerVectors for iv in IntegerVectors(self._k, len(self._indices), outer=self._multiplicities): yield sum([ [self._s[self._indices[i]]]*iv[i] for i in range(len(iv))], [])
def ambient(self): r""" Return the ambient space from which ``self`` is a quotient. EXAMPLES:: sage: S = IntegerVectorsModPermutationGroup(PermutationGroup([[(1,2,3,4)]])) sage: S.ambient() Integer vectors """ ## TODO: Fix me once 'IntegerVectors(length=bla)' will return ## the integer vectors of length bla #return IntegerVectors(length=self.n) # (#17927) The previous line was replaced by the following, as # IntegerVectors(length=k) is invalid at the moment. return IntegerVectors()
def __iter__(self): """ Return an iterator for the words in the shuffle product of ``w1`` and ``w2``. EXAMPLES:: sage: from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2 sage: w, u = map(Words("abcd"), ["ab", "cd"]) sage: S = ShuffleProduct_w1w2(w,u) sage: S.list() #indirect test [word: abcd, word: acbd, word: acdb, word: cabd, word: cadb, word: cdab] """ n1 = len(self._w1) n2 = len(self._w2) for iv in IntegerVectors(n1, n1 + n2, max_part=1): yield self._proc(iv)
def __iter__(self): """ TESTS:: sage: LyndonWords(3,3).list() # indirect doctest [word: 112, word: 113, word: 122, word: 123, word: 132, word: 133, word: 223, word: 233] """ for c in IntegerVectors(self._k, self._n): cf = [] nonzero_indices = [] for i, x in enumerate(c): if x: nonzero_indices.append(i) cf.append(x) for lw in LyndonWords_evaluation(Composition(cf)): yield self._words([nonzero_indices[x - 1] + 1 for x in lw], check=False)
def _list_all_decreasing_runs(word, m): """ List all possible decreasing runs into ``m`` factors for ``word`` in a 0-Hecke monoid. EXAMPLES:: sage: from sage.combinat.crystals.fully_commutative_stable_grothendieck import _list_all_decreasing_runs sage: _list_all_decreasing_runs([2, 1, 2, 1], 3) [[2, 2, 1, 1], [3, 2, 1, 1], [3, 3, 1, 1], [3, 3, 2, 1], [3, 3, 2, 2]] """ from sage.combinat.integer_vector import IntegerVectors J = _jumps(word) jump_vector = [1] + [int(j in J) for j in range(1, len(word))] I = sorted(IntegerVectors(m - 1 - len(J), len(word) + 1), reverse=True) P = [[elt[i] + jump_vector[i] for i in range(len(word))] for elt in I] V = [[m + 1 - sum(elt[:i + 1]) for i in range(len(elt))] for elt in P] return V
def homogeneous_monomials(self, fibre_degrees, weights, max_differential_orders=None): fibre_vars = self.fibre_variables() if not len(fibre_degrees) == len(fibre_vars): raise ValueError( 'length of fibre_degrees vector must match number of fibre variables' ) base_vars = self.base_variables() if not len(weights) == len(base_vars): raise ValueError( 'length of weights vector must match number of base variables') monomials = [] fibre_degree = sum(fibre_degrees) fibre_indexes = {} fibre_idx = 0 for i in range(len(fibre_degrees)): for j in range(fibre_degrees[i]): fibre_indexes[fibre_idx] = i fibre_idx += 1 proto = sum([[fibre_vars[i]] * fibre_degrees[i] for i in range(len(fibre_degrees))], []) for V in product(*[IntegerVectors(w, fibre_degree) for w in weights]): total_differential_order = [0 for i in range(fibre_degree)] term = [p for p in proto] skip = False for j in range(fibre_degree): fibre_idx = fibre_indexes[j] for i in range(len(base_vars)): if V[i][j] > 0: total_differential_order[j] += V[i][j] if max_differential_orders is not None and total_differential_order[ j] > max_differential_orders[fibre_idx]: skip = True break term[j] = term[j].total_derivative(*([base_vars[i]] * V[i][j])) if skip: break if not skip: monomials.append(prod(term)) return monomials
def __init__(self, base_ring, fibre_names, base_names, max_differential_orders): self._fibre_names = tuple(fibre_names) self._base_names = tuple(base_names) self._max_differential_orders = tuple(max_differential_orders) base_dim = len(self._base_names) fibre_dim = len(self._fibre_names) jet_names = [] idx_to_name = {} for fibre_idx in range(fibre_dim): u = self._fibre_names[fibre_idx] idx_to_name[(fibre_idx, ) + tuple([0] * base_dim)] = u for d in range(1, max_differential_orders[fibre_idx] + 1): for multi_index in IntegerVectors(d, base_dim): v = '{}_{}'.format( u, ''.join(self._base_names[i] * multi_index[i] for i in range(base_dim))) jet_names.append(v) idx_to_name[(fibre_idx, ) + tuple(multi_index)] = v self._polynomial_ring = PolynomialRing( base_ring, base_names + fibre_names + tuple(jet_names)) self._idx_to_var = { idx: self._polynomial_ring(idx_to_name[idx]) for idx in idx_to_name } self._var_to_idx = { jet: idx for (idx, jet) in self._idx_to_var.items() } # for conversion: base_vars = [var(b) for b in self._base_names] symbolic_functions = [ function(f)(*base_vars) for f in self._fibre_names ] self._subs_jet_vars = SubstituteJetVariables(symbolic_functions) self._subs_tot_ders = SubstituteTotalDerivatives(symbolic_functions)
def invariants_of_degree(self, deg, chi=None, R=None): r""" Return the (relative) invariants of given degree for this group. For this group, compute the invariants of degree ``deg`` with respect to the group character ``chi``. The method is to project each possible monomial of degree ``deg`` via the Reynolds operator. Note that if the polynomial ring ``R`` is specified it's base ring may be extended if the resulting invariant is defined over a bigger field. INPUT: - ``degree`` -- a positive integer - ``chi`` -- (default: trivial character) a linear group character of this group - ``R`` -- (optional) a polynomial ring OUTPUT: list of polynomials EXAMPLES:: sage: Gr = MatrixGroup(SymmetricGroup(2)) sage: sorted(Gr.invariants_of_degree(3)) [x0^2*x1 + x0*x1^2, x0^3 + x1^3] sage: R.<x,y> = QQ[] sage: sorted(Gr.invariants_of_degree(4, R=R)) [x^2*y^2, x^3*y + x*y^3, x^4 + y^4] :: sage: R.<x,y,z> = QQ[] sage: Gr = MatrixGroup(DihedralGroup(3)) sage: ct = Gr.character_table() sage: chi = Gr.character(ct[0]) sage: all(f(*(g.matrix()*vector(R.gens()))) == chi(g)*f ....: for f in Gr.invariants_of_degree(3, R=R, chi=chi) for g in Gr) True :: sage: i = GF(7)(3) sage: G = MatrixGroup([[i^3,0,0,-i^3],[i^2,0,0,-i^2]]) sage: G.invariants_of_degree(25) [] :: sage: G = MatrixGroup(SymmetricGroup(5)) sage: R = QQ['x,y'] sage: G.invariants_of_degree(3, R=R) Traceback (most recent call last): ... TypeError: number of variables in polynomial ring must match size of matrices :: sage: K.<i> = CyclotomicField(4) sage: G = MatrixGroup(CyclicPermutationGroup(3)) sage: chi = G.character(G.character_table()[1]) sage: R.<x,y,z> = K[] sage: sorted(G.invariants_of_degree(2, R=R, chi=chi)) [x*y + (2*izeta3^3 + 3*izeta3^2 + 8*izeta3 + 3)*x*z + (-2*izeta3^3 - 3*izeta3^2 - 8*izeta3 - 4)*y*z, x^2 + (-2*izeta3^3 - 3*izeta3^2 - 8*izeta3 - 4)*y^2 + (2*izeta3^3 + 3*izeta3^2 + 8*izeta3 + 3)*z^2] :: sage: S3 = MatrixGroup(SymmetricGroup(3)) sage: chi = S3.character(S3.character_table()[0]) sage: sorted(S3.invariants_of_degree(5, chi=chi)) [x0^3*x1^2 - x0^2*x1^3 - x0^3*x2^2 + x1^3*x2^2 + x0^2*x2^3 - x1^2*x2^3, x0^4*x1 - x0*x1^4 - x0^4*x2 + x1^4*x2 + x0*x2^4 - x1*x2^4] """ D = self.degree() deg = int(deg) if deg <= 0: raise ValueError("degree must be a positive integer") if R is None: R = PolynomialRing(self.base_ring(), 'x', D) elif R.ngens() != D: raise TypeError( "number of variables in polynomial ring must match size of matrices" ) ms = self.molien_series(prec=deg + 1, chi=chi) if ms[deg].is_zero(): return [] inv = set() for e in IntegerVectors(deg, D): F = self.reynolds_operator(R.monomial(*e), chi=chi) if not F.is_zero(): F = F / F.lc() inv.add(F) if len(inv) == ms[deg]: break return list(inv)
def is_perfect(self, level=1): r""" Checks whether the crystal ``self`` is perfect (of level ``level``). INPUT: - ``level`` -- (default: 1) positive integer A crystal `\mathcal{B}` is perfect of level `\ell` if: #. `\mathcal{B}` is isomorphic to the crystal graph of a finite-dimensional `U_q^{'}(\mathfrak{g})`-module. #. `\mathcal{B}\otimes \mathcal{B}` is connected. #. There exists a `\lambda\in X`, such that `\mathrm{wt}(\mathcal{B}) \subset \lambda + \sum_{i\in I} \mathbb{Z}_{\le 0} \alpha_i` and there is a unique element in `\mathcal{B}` of classical weight `\lambda`. #. `\forall b \in \mathcal{B}, \mathrm{level}(\varepsilon (b)) \geq \ell`. #. `\forall \Lambda` dominant weights of level `\ell`, there exist unique elements `b_{\Lambda}, b^{\Lambda} \in \mathcal{B}`, such that `\varepsilon ( b_{\Lambda}) = \Lambda = \varphi( b^{\Lambda})`. Points (1)-(3) are known to hold. This method checks points (4) and (5). EXAMPLES:: sage: C = CartanType(['C',2,1]) sage: R = RootSystem(C) sage: La = R.weight_space().basis() sage: LS = crystals.ProjectedLevelZeroLSPaths(La[1]) sage: LS.is_perfect() False sage: LS = crystals.ProjectedLevelZeroLSPaths(La[2]) sage: LS.is_perfect() True sage: C = CartanType(['E',6,1]) sage: R = RootSystem(C) sage: La = R.weight_space().basis() sage: LS = crystals.ProjectedLevelZeroLSPaths(La[1]) sage: LS.is_perfect() True sage: LS.is_perfect(2) False sage: C = CartanType(['D',4,1]) sage: R = RootSystem(C) sage: La = R.weight_space().basis() sage: all(crystals.ProjectedLevelZeroLSPaths(La[i]).is_perfect() for i in [1,2,3,4]) True sage: C = CartanType(['A',6,2]) sage: R = RootSystem(C) sage: La = R.weight_space().basis() sage: LS = crystals.ProjectedLevelZeroLSPaths(La[1]+La[2]) sage: LS.is_perfect() True sage: LS.is_perfect(2) False """ MPhi = [] for b in self: p = b.Phi().level() assert p == b.Epsilon().level() if p < level: return False if p == level: MPhi += [b] weights = [] I = self.index_set() rank = len(I) La = self.weight_lattice_realization().basis() from sage.combinat.integer_vector import IntegerVectors for n in range(1, level + 1): for c in IntegerVectors(n, rank): w = sum(c[i] * La[i] for i in I) if w.level() == level: weights.append(w) return sorted([b.Phi() for b in MPhi]) == sorted(weights)
def _linear_system_as_kernel(self, d, pt, m): """ Return a matrix whose kernel consists of the coefficient vectors of the degree d hypersurfaces (wrt lexicographic ordering of its monomials) with multiplicity at least m at pt. INPUT: - ``d`` -- a nonnegative integer - ``pt`` -- a point of self (possibly represented by a list with at \ least one component equal to 1) - ``m`` -- a nonnegative integer OUTPUT: A matrix of size `{m-1+n \choose n}` x `{d+n \choose n}` where n is the relative dimension of self. The base ring of the matrix is a ring that contains the base ring of self and the coefficients of the given point. EXAMPLES: If the degree `d` is 0, then a matrix consisting of the first unit vector is returned:: sage: P = ProjectiveSpace(GF(5), 2, names='x') sage: pt = P([1, 1, 1]) sage: P._linear_system_as_kernel(0, pt, 3) [1] [0] [0] [0] [0] [0] If the multiplcity `m` is 0, then the a matrix with zero rows is returned:: sage: P = ProjectiveSpace(GF(5), 2, names='x') sage: pt = P([1, 1, 1]) sage: M = P._linear_system_as_kernel(2, pt, 0) sage: [M.nrows(), M.ncols()] [0, 6] The base ring does not need to be a field or even an integral domain. In this case, the point can be given by a list:: sage: R = Zmod(4) sage: P = ProjectiveSpace(R, 2, names='x') sage: pt = [R(1), R(3), R(0)] sage: P._linear_system_as_kernel(3, pt, 2) [1 3 0 1 0 0 3 0 0 0] [0 1 0 2 0 0 3 0 0 0] [0 0 1 0 3 0 0 1 0 0] When representing a point by a list at least one component must be 1 (even when the base ring is a field and the list gives a well-defined point in projective space):: sage: R = GF(5) sage: P = ProjectiveSpace(R, 2, names='x') sage: pt = [R(3), R(3), R(0)] sage: P._linear_system_as_kernel(3, pt, 2) Traceback (most recent call last): ... TypeError: At least one component of pt=[3, 3, 0] must be equal to 1 The components of the list do not have to be elements of the base ring of the projective space. It suffices if there exists a common parent. For example, the kernel of the following matrix corresponds to hypersurfaces of degree 2 in 3-space with multiplicity at least 2 at a general point in the third affine patch:: sage: P = ProjectiveSpace(QQ,3,names='x') sage: RPol.<t0,t1,t2,t3> = PolynomialRing(QQ,4) sage: pt = [t0,t1,1,t3] sage: P._linear_system_as_kernel(2,pt,2) [ 2*t0 t1 1 t3 0 0 0 0 0 0] [ 0 t0 0 0 2*t1 1 t3 0 0 0] [ t0^2 t0*t1 t0 t0*t3 t1^2 t1 t1*t3 1 t3 t3^2] [ 0 0 0 t0 0 0 t1 0 1 2*t3] .. TODO:: Use this method as starting point to implement a class LinearSystem for linear systems of hypersurfaces. """ if not isinstance(d, (int, Integer)): raise TypeError('The argument d=%s must be an integer' % d) if d < 0: raise ValueError('The integer d=%s must be nonnegative' % d) if not isinstance(pt, (list, tuple, \ SchemeMorphism_point_projective_ring)): raise TypeError('The argument pt=%s must be a list, tuple, or ' 'point on a projective space' % pt) pt, R = prepare(pt, None) n = self.dimension_relative() if not len(pt) == n + 1: raise TypeError('The sequence pt=%s must have %s ' 'components' % (pt, n + 1)) if not R.has_coerce_map_from(self.base_ring()): raise TypeError('Unable to find a common ring for all elements') try: i = pt.index(1) except Exception: raise TypeError('At least one component of pt=%s must be equal ' 'to 1' % pt) pt = pt[:i] + pt[i + 1:] if not isinstance(m, (int, Integer)): raise TypeError('The argument m=%s must be an integer' % m) if m < 0: raise ValueError('The integer m=%s must be nonnegative' % m) # the components of partials correspond to partial derivatives # of order at most m-1 with respect to n variables partials = IntegerVectors(m - 1, n + 1).list() # the components of monoms correspond to monomials of degree # at most d in n variables monoms = IntegerVectors(d, n + 1).list() M = matrix(R, len(partials), len(monoms)) for row in range(M.nrows()): e = partials[row][:i] + partials[row][i + 1:] for col in range(M.ncols()): f = monoms[col][:i] + monoms[col][i + 1:] if min([f[j] - e[j] for j in range(n)]) >= 0: M[row,col] = prod([binomial(f[j],e[j])*pt[j]**(f[j]-e[j]) \ for j in filter(lambda k: f[k]>e[k], range(n))]) return M
def __iter__(self): """ EXAMPLES:: sage: from sage.combinat.words.shuffle_product import ShuffleProduct_overlapping_r sage: w, u = Word([1,2]), Word([3,4]) sage: ShuffleProduct_overlapping_r(w,u,1).list() [word: 424, word: 154, word: 442, word: 136, word: 352, word: 316] sage: w, u = map(Words(range(1,7)), [[1,2], [3,4]]) sage: W = Words(range(1,7)) sage: w, u = W([1,2]), W([3,4]) sage: ShuffleProduct_overlapping_r(w, u, 1).list() #indirect doctest [word: 424, word: 154, word: 442, word: 136, word: 352, word: 316] sage: I, J = Composition([2, 2]), Composition([1, 1]) sage: S = ShuffleProduct_overlapping_r(I, J, 1) sage: S.list() [[3, 2, 1], [2, 3, 1], [3, 1, 2], [2, 1, 3], [1, 3, 2], [1, 2, 3]] TESTS: Sage is no longer confused by a too-restrictive parent of `I` when shuffling two compositions `I` and `J` (cf. :trac:`15131`):: sage: I, J = Compositions(4)([2, 2]), Composition([1, 1]) sage: S = ShuffleProduct_overlapping_r(I, J, 1) sage: S.list() [[3, 2, 1], [2, 3, 1], [3, 1, 2], [2, 1, 3], [1, 3, 2], [1, 2, 3]] """ W = self.W m = len(self._w1) n = len(self._w2) r = self.r wc1, wc2 = self._w1, self._w2 blank = [0] * (m + n - r) for iv in IntegerVectors(m, m + n - r, max_part=1): w = blank[:] filled_places = [] unfilled_places = [] #Fill in w1 into the iv slots i = 0 for j in range(len(iv)): if iv[j] == 1: w[j] = wc1[i] i += 1 filled_places.append(j) else: unfilled_places.append(j) #Choose r of these filled places for subset in Subsets(filled_places, r): places_to_fill = unfilled_places + list(subset) places_to_fill.sort() #Fill in w2 into the places i = 0 res = w[:] for j in places_to_fill: res[j] += wc2[i] i += 1 yield W(res)
def is_perfect(self, ell=None): r""" Check if ``self`` is a perfect crystal of level ``ell``. A crystal `\mathcal{B}` is perfect of level `\ell` if: #. `\mathcal{B}` is isomorphic to the crystal graph of a finite-dimensional `U_q'(\mathfrak{g})`-module. #. `\mathcal{B} \otimes \mathcal{B}` is connected. #. There exists a `\lambda\in X`, such that `\mathrm{wt}(\mathcal{B}) \subset \lambda + \sum_{i\in I} \ZZ_{\le 0} \alpha_i` and there is a unique element in `\mathcal{B}` of classical weight `\lambda`. #. For all `b \in \mathcal{B}`, `\mathrm{level}(\varepsilon (b)) \geq \ell`. #. For all `\Lambda` dominant weights of level `\ell`, there exist unique elements `b_{\Lambda}, b^{\Lambda} \in \mathcal{B}`, such that `\varepsilon(b_{\Lambda}) = \Lambda = \varphi(b^{\Lambda})`. Points (1)-(3) are known to hold. This method checks points (4) and (5). If ``self`` is the Kirillov-Reshetikhin crystal `B^{r,s}`, then it was proven for non-exceptional types in [FOS2010]_ that it is perfect if and only if `s/c_r` is an integer (where `c_r` is a constant related to the type of the crystal). It is conjectured this is true for all affine types. INPUT: - ``ell`` -- (default: `s / c_r`) integer; the level REFERENCES: [FOS2010]_ EXAMPLES:: sage: K = crystals.KirillovReshetikhin(['A',2,1], 1, 1) sage: K.is_perfect() True sage: K = crystals.KirillovReshetikhin(['C',2,1], 1, 1) sage: K.is_perfect() False sage: K = crystals.KirillovReshetikhin(['C',2,1], 1, 2) sage: K.is_perfect() True sage: K = crystals.KirillovReshetikhin(['E',6,1], 1,3) sage: K.is_perfect() True TESTS: Check that this works correctly for `B^{n,s}` of type `A_{2n}^{(2)\dagger}` (:trac:`24364`):: sage: K = crystals.KirillovReshetikhin(CartanType(['A',6,2]).dual(), 3,1) sage: K.is_perfect() True sage: K.is_perfect(1) True .. TODO:: Implement a version for tensor products of KR crystals. """ if ell is None: if (self.cartan_type().dual().type() == 'BC' and self.cartan_type().rank() - 1 == self.r()): return True ell = self.s() / self.cartan_type().c()[self.r()] if ell not in ZZ: return False if ell not in ZZ: raise ValueError( "perfectness not defined for non-integral levels") # [FOS2010]_ check if self.cartan_type().classical().type() not in ['E', 'F', 'G']: if (self.cartan_type().dual().type() == 'BC' and self.cartan_type().rank() - 1 == self.r()): return ell == self.s() return ell == self.s() / self.cartan_type().c()[self.r()] # Check by definition # TODO: This is duplicated from ProjectedLevelZeroLSPaths, combine the two methods. # TODO: Similarly, don't duplicate in the tensor product category, maybe # move this to the derived affine category? MPhi = [] for b in self: p = b.Phi().level() assert p == b.Epsilon().level() if p < ell: return False if p == ell: MPhi += [b] weights = [] I = self.index_set() rank = len(I) La = self.weight_lattice_realization().basis() from sage.combinat.integer_vector import IntegerVectors for n in range(1, ell + 1): for c in IntegerVectors(n, rank): w = sum(c[i] * La[i] for i in I) if w.level() == ell: weights.append(w) return sorted(b.Phi() for b in MPhi) == sorted(weights)
def __iter__(self): """ EXAMPLES:: sage: from sage.combinat.shuffle import ShuffleProduct_overlapping_r sage: w, u = Word([1,2]), Word([3,4]) sage: ShuffleProduct_overlapping_r(w,u,1).list() [word: 424, word: 154, word: 442, word: 136, word: 352, word: 316] sage: w, u = map(Words(range(1,7)), [[1,2], [3,4]]) sage: W = Words(range(1,7)) sage: w, u = W([1,2]), W([3,4]) sage: ShuffleProduct_overlapping_r(w, u, 1).list() #indirect doctest [word: 424, word: 154, word: 442, word: 136, word: 352, word: 316] sage: I, J = Composition([2, 2]), Composition([1, 1]) sage: S = ShuffleProduct_overlapping_r(I, J, 1) sage: S.list() [[3, 2, 1], [2, 3, 1], [3, 1, 2], [2, 1, 3], [1, 3, 2], [1, 2, 3]] TESTS: We need to be explicitly more generic about the resulting parent when shuffling two compositions `I` and `J` (:trac:`15131`):: sage: I, J = Compositions(4)([2, 2]), Composition([1, 1]) sage: S = ShuffleProduct_overlapping_r(I, J, 1, Compositions()) sage: S.list() [[3, 2, 1], [2, 3, 1], [3, 1, 2], [2, 1, 3], [1, 3, 2], [1, 2, 3]] """ EC = self._element_constructor_ m = len(self._w1) n = len(self._w2) r = self.r add = self.add wc1, wc2 = self._w1, self._w2 blank = [None] * (m+n-r) for iv in IntegerVectors(m, m+n-r, max_part=1): w = blank[:] filled_places = [] unfilled_places = [] #Fill in w1 into the iv slots i = 0 for j in range(len(iv)): if iv[j] == 1: w[j] = wc1[i] i += 1 filled_places.append(j) else: unfilled_places.append(j) #Choose r of these filled places for subset in itertools.combinations(filled_places, r): places_to_fill = sorted(unfilled_places + list(subset)) #Fill in w2 into the places i = 0 res = w[:] for j in places_to_fill: if res[j] is not None: res[j] = add(res[j], wc2[i]) else: res[j] = wc2[i] i += 1 yield EC(res)
def polynomials(self, X=None, Y=None, degree=2, groebner=False): """ Return a list of polynomials satisfying this S-box. First, a simple linear fitting is performed for the given ``degree`` (cf. for example [BC2003]_). If ``groebner=True`` a Groebner basis is also computed for the result of that process. INPUT: - ``X`` - input variables - ``Y`` - output variables - ``degree`` - integer > 0 (default: ``2``) - ``groebner`` - calculate a reduced Groebner basis of the spanning polynomials to obtain more polynomials (default: ``False``) EXAMPLES:: sage: from sage.crypto.sbox import SBox sage: S = SBox(7,6,0,4,2,5,1,3) sage: P = S.ring() By default, this method returns an indirect representation:: sage: S.polynomials() [x0*x2 + x1 + y1 + 1, x0*x1 + x1 + x2 + y0 + y1 + y2 + 1, x0*y1 + x0 + x2 + y0 + y2, x0*y0 + x0*y2 + x1 + x2 + y0 + y1 + y2 + 1, x1*x2 + x0 + x1 + x2 + y2 + 1, x0*y0 + x1*y0 + x0 + x2 + y1 + y2, x0*y0 + x1*y1 + x1 + y1 + 1, x1*y2 + x1 + x2 + y0 + y1 + y2 + 1, x0*y0 + x2*y0 + x1 + x2 + y1 + 1, x2*y1 + x0 + y1 + y2, x2*y2 + x1 + y1 + 1, y0*y1 + x0 + x2 + y0 + y1 + y2, y0*y2 + x1 + x2 + y0 + y1 + 1, y1*y2 + x2 + y0] We can get a direct representation by computing a lexicographical Groebner basis with respect to the right variable ordering, i.e. a variable ordering where the output bits are greater than the input bits:: sage: P.<y0,y1,y2,x0,x1,x2> = PolynomialRing(GF(2),6,order='lex') sage: S.polynomials([x0,x1,x2],[y0,y1,y2], groebner=True) [y0 + x0*x1 + x0*x2 + x0 + x1*x2 + x1 + 1, y1 + x0*x2 + x1 + 1, y2 + x0 + x1*x2 + x1 + x2 + 1] """ def nterms(nvars, deg): """ Return the number of monomials possible up to a given degree. INPUT: - ``nvars`` - number of variables - ``deg`` - degree TESTS:: sage: from sage.crypto.sbox import SBox sage: S = SBox(7,6,0,4,2,5,1,3) sage: F = S.polynomials(degree=3) # indirect doctest """ total = 1 divisor = 1 var_choices = 1 for d in range(1, deg+1): var_choices *= (nvars - d + 1) divisor *= d total += var_choices/divisor return total m = self.m n = self.n F = self._F if X is None and Y is None: P = self.ring() X = P.gens()[:m] Y = P.gens()[m:] else: P = X[0].parent() gens = X+Y bits = [] for i in range(1<<m): bits.append( self.to_bits(i,m) + self(self.to_bits(i,m)) ) ncols = (1<<m)+1 A = Matrix(P, nterms(m+n, degree), ncols) exponents = [] for d in range(degree+1): exponents += IntegerVectors(d, max_length=m+n, min_length=m+n, min_part=0, max_part=1).list() row = 0 for exponent in exponents: A[row,ncols-1] = mul([gens[i]**exponent[i] for i in range(len(exponent))]) for col in range(1<<m): A[row,col] = mul([bits[col][i] for i in range(len(exponent)) if exponent[i]]) row +=1 for c in range(ncols): A[0,c] = 1 RR = A.echelon_form(algorithm='row_reduction') # extract spanning stet gens = (RR.column(ncols-1)[1<<m:]).list() if not groebner: return gens FI = set(FieldIdeal(P).gens()) I = Ideal(gens + list(FI)) gb = I.groebner_basis() gens = [] for f in gb: if f not in FI: # filter out field equations gens.append(f) return gens
def graded_basis(self, k): """ Return the basis for the ``k``-th graded piece of ``self``. EXAMPLES:: sage: L = LieAlgebra(QQ, 'x', 3) sage: Lyn = L.Lyndon() sage: Lyn.graded_basis(1) (x0, x1, x2) sage: Lyn.graded_basis(2) ([x0, x1], [x0, x2], [x1, x2]) sage: Lyn.graded_basis(4) ([x0, [x0, [x0, x1]]], [x0, [x0, [x0, x2]]], [x0, [[x0, x1], x1]], [x0, [x0, [x1, x2]]], [x0, [[x0, x2], x1]], [[x0, x1], [x0, x2]], [x0, [[x0, x2], x2]], [[[x0, x1], x1], x1], [x0, [x1, [x1, x2]]], [[x0, [x1, x2]], x1], [[[x0, x2], x1], x1], [x0, [[x1, x2], x2]], [[x0, x2], [x1, x2]], [[[x0, x2], x2], x1], [[[x0, x2], x2], x2], [x1, [x1, [x1, x2]]], [x1, [[x1, x2], x2]], [[[x1, x2], x2], x2]) TESTS:: sage: L = LieAlgebra(QQ, 'x,y,z', 3) sage: Lyn = L.Lyndon() sage: [Lyn.graded_dimension(i) for i in range(1, 11)] [3, 3, 8, 18, 48, 116, 312, 810, 2184, 5880] sage: [len(Lyn.graded_basis(i)) for i in range(1, 11)] [3, 3, 8, 18, 48, 116, 312, 810, 2184, 5880] """ if k <= 0 or not self._indices: return [] names = self.variable_names() one = self.base_ring().one() if k == 1: return tuple(self.element_class(self, {LieGenerator(n): one}) for n in names) # Slightly modified form of LyndonWords_nk which is 0 indexed, # does not create any temporary objects and simplifies the # combined logic from sage.combinat.integer_vector import IntegerVectors from sage.combinat.necklace import _sfc n = len(self._indices) ret = [] for c in IntegerVectors(k, n): nonzero_indices = [i for i,val in enumerate(c) if val != 0] cf = [c[i] for i in nonzero_indices] for z in _sfc(cf, equality=True): b = self._standard_bracket(tuple([names[nonzero_indices[i]] for i in z])) ret.append(self.element_class(self, {b: one})) return tuple(ret)