def __init__(self, data, coxeter=None, mutation_type=None, depth=infinity): data = copy(data) if isinstance(data, Matrix): if not data.is_skew_symmetrizable(): raise ValueError( "The input must be a skew symmetrizable integer matrix") self.B0 = data self.rk = self.B0.ncols() elif isinstance(data, CartanType_abstract): self.rk = data.rank() if Set(data.index_set()) != Set(range(self.rk)): relabelling = dict(zip(data.index_set(), range(self.rk))) data = data.relabel(relabelling) self.cartan_type.set_cache(data) if coxeter == None: coxeter = range(self.rk) if Set(coxeter) != Set(data.index_set()): raise ValueError( "The Coxeter element need to be a list permuting the entries of the index set of the Cartan type" ) self.coxeter.set_cache(copy(coxeter)) self.cartan_companion.set_cache(data.cartan_matrix()) self.B0 = 2 - self.cartan_companion() for i in range(self.rk): for j in range(i, self.rk): a = coxeter[j] b = coxeter[i] self.B0[a, b] = -self.B0[a, b] elif type(data) in [ QuiverMutationType_Irreducible, QuiverMutationType_Reducible ]: self.__init__(data.b_matrix(), mutation_type=data, depth=depth) elif type(data) == list: self.__init__(CartanType(data), coxeter=coxeter, depth=depth) else: raise ValueError("Input is not valid") # this is a hack to deal with type ['D', n, 1] since mutation_type() # can't distinguish it if mutation_type: self.mutation_type.set_cache(QuiverMutationType(mutation_type)) self._depth = depth
def small_prime_value(self, Bmax=1000): r""" Returns a prime represented by this (primitive positive definite) binary form. INPUT: - ``Bmax`` -- a positive bound on the representing integers. OUTPUT: A prime number represented by the form. .. NOTE:: This is a very elementary implementation which just substitutes values until a prime is found. EXAMPLES:: sage: [Q.small_prime_value() for Q in BinaryQF_reduced_representatives(-23, primitive_only=True)] [23, 2, 2] sage: [Q.small_prime_value() for Q in BinaryQF_reduced_representatives(-47, primitive_only=True)] [47, 2, 2, 3, 3] """ from sage.sets.all import Set from sage.arith.srange import xsrange B = 10 while True: llist = list(Set([self(x,y) for x in xsrange(-B,B) for y in xsrange(B)])) llist = sorted([l for l in llist if l.is_prime()]) if llist: return llist[0] if B >= Bmax: raise ValueError("Unable to find a prime value of %s" % self) B += 10
def _tube_nbh(self, alpha): sup_a = self._tube_support(alpha) nbh_a = [self.tau_c(x) for x in sup_a if self.tau_c(x) not in sup_a] nbh_a += [ self.tau_c_inverse(x) for x in sup_a if self.tau_c_inverse(x) not in sup_a ] nbh_a = Set(nbh_a) return tuple(nbh_a)
def clusters(self, depth=None): r""" FIXME: handle error id depth is not set """ if depth == None: depth = self._depth if self._clusters[0] != depth: def compatible_following(l): out = [] while l: x = l.pop() comp_with_x = [ y for y in l if self.compatibility_degree(x, y) == 0 ] if comp_with_x != []: out.append((x, comp_with_x)) else: out.append((x, )) return out d_vectors = self.d_vectors(depth=depth) clusters = compatible_following(d_vectors) done = False while not done: new = [] done = True for clus in clusters: if type(clus[-1]) == list: done = False for y in compatible_following(clus[-1]): new.append(clus[:-1] + y) else: new.append(clus) clusters = copy(new) self._clusters = [ depth, [Set(x) for x in clusters if len(x) == self._n] ] return copy(self._clusters[1])
def _global_relation_matrix(precision, S, weight_parity): r""" Deduce restrictions on the coefficients of a Jacobi form based on the specialization to Jacobi form of scalar index. INPUT: - ``precision`` -- An instance of JacobiFormD1Filter. - `S` -- A list of vectors. - ``weight_parity`` -- The parity of the weight of the considered Jacobi forms. """ L = precision.jacobi_index() weight_parity = weight_parity % 2 (mat, row_groups, row_labels, column_labels) = _global_restriction_matrix(precision, S, weight_parity, find_relations=True) reduced_index_indices = dict((m, JacobiFormD1NNIndices(m)) for m in Set( m for (_, m, _, _) in row_groups)) relations = list() for (s, m, start, length) in row_groups: row_labels_dict = row_labels[m] for (l, i) in row_labels_dict.iteritems(): (lred, sign) = reduced_index_indices[m].reduce(l) if lred == l: continue relations.append( mat.row(start + row_labels_dict[lred]) - (1 if weight_parity == 0 else sign) * mat.row(start + i)) return (matrix(len(relations), len(column_labels), relations), column_labels)
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 _global_restriction_matrix(precision, S, weight_parity, find_relations=False): r""" A matrix that maps the Fourier expansion of a Jacobi form of given precision to their restrictions with respect to the elements of S. INPUT: - ``precision`` -- An instance of JacobiFormD1Filter. - `S` -- A list of vectors. - ``weight_parity`` -- The parity of the weight of the considered Jacobi forms. - ``find_relation`` -- A boolean. If ``True``, then the restrictions to nonreduced indices will also be computed. TESTS:: sage: from psage.modform.jacobiforms.jacobiformd1_fourierexpansion import * sage: from psage.modform.jacobiforms.jacobiformd1_fegenerators import _global_restriction_matrix sage: precision = JacobiFormD1Filter(5, QuadraticForm(matrix(2, [2,1,1,2]))) sage: (global_restriction_matrix, row_groups, row_labels, column_labels) = _global_restriction_matrix(precision, [vector((1,0))], 12) sage: global_restriction_matrix [1 0 0 0 0 0 0 0 0] [0 1 2 0 0 0 0 0 0] [2 0 2 0 0 0 0 0 0] [0 0 2 1 2 0 0 0 0] [0 2 0 0 2 0 0 0 0] [2 0 0 0 2 1 2 0 0] [0 0 2 2 0 0 2 0 0] [0 2 0 0 0 0 2 1 2] [0 0 0 0 2 2 0 0 2] sage: (row_groups, row_labels, column_labels) ([((1, 0), 1, 0, 9)], {1: {(0, 0): 0, (3, 0): 5, (3, 1): 6, (2, 1): 4, (2, 0): 3, (1, 0): 1, (4, 1): 8, (1, 1): 2, (4, 0): 7}}, [(0, (0, 0)), (1, (0, 0)), (1, (1, 1)), (2, (0, 0)), (2, (1, 1)), (3, (0, 0)), (3, (1, 1)), (4, (0, 0)), (4, (1, 1))]) """ L = precision.jacobi_index() weight_parity = weight_parity % 2 jacobi_indices = [L(s) for s in S] index_filters = dict( (m, list( JacobiFormD1NNFilter( precision.index(), m, reduced=not find_relations))) for m in Set(jacobi_indices)) column_labels = list(precision) reductions = dict((l, list()) for l in column_labels) for l in precision.monoid_filter(): (lred, sign) = precision.monoid().reduce(l) reductions[lred].append((l, sign)) row_groups = [len(index_filters[m]) for m in jacobi_indices] row_groups = [(s, m, sum(row_groups[:i]), row_groups[i]) for ((i, s), m) in zip(enumerate(S), jacobi_indices)] row_labels = dict((m, dict((l, i) for (i, l) in enumerate(index_filters[m]))) for m in Set(jacobi_indices)) dot_products = [ cython_lambda( ' , '.join(['int x{0}'.format(i) for i in range(len(s))]), ' + '.join(['{0} * x{1}'.format(s[i], i) for i in range(len(s))])) for (s, _, _, _) in row_groups ] restriction_matrix = zero_matrix(ZZ, row_groups[-1][2] + row_groups[-1][3], len(column_labels)) for (cind, l) in enumerate(column_labels): for ((n, r), sign) in reductions[l]: for ((s, m, start, length), dot_product) in zip(row_groups, dot_products): row_labels_dict = row_labels[m] try: restriction_matrix[start + row_labels_dict[(n, dot_product(*r))], cind] \ += 1 if weight_parity == 0 else sign except KeyError: pass return (restriction_matrix, row_groups, row_labels, column_labels)
def _find_complete_set_of_restriction_vectors(L, R, additional_s=0, reduction_function=None): r""" Given a set R of elements in L^# (e.g. representatives for ( L^# / L ) / \pm 1) find a complete set of restriction vectors. (See [GKR]) INPUT: - `L` -- A quadratic form. - `R` -- A list of tuples or vectors in L \otimes QQ (with given coordinates). - ``additional_s`` -- A non-negative integer; Number of additional elements of `L` that should be returned. - ``reduction_function`` -- A function that takes a tuple representing an element in `L^\#` and returs a pair of a reduced element in `L^\#` and a sign. OUTPUT: - A set S of pairs, the first of which is a vector corresponding to an element in L, and the second of which is an integer. TESTS:: sage: from psage.modform.jacobiforms.jacobiformd1_fegenerators import _find_complete_set_of_restriction_vectors sage: from psage.modform.jacobiforms.jacobiformd1_fourierexpansion import * sage: indices = JacobiFormD1Indices(QuadraticForm(matrix(2, [2,1,1,2]))) sage: _find_complete_set_of_restriction_vectors(indices.jacobi_index(), indices._r_representatives) [((1, 0), 0), ((1, 0), 1), ((-2, 1), 1)] sage: _find_complete_set_of_restriction_vectors(indices.jacobi_index(), indices._r_representatives, reduction_function = indices.reduce_r) [((1, 0), 0), ((1, 0), 1), ((-2, 1), 1)] :: sage: from psage.modform.jacobiforms.jacobiformd1_fegenerators import _local_restriction_matrix sage: indices = JacobiFormD1Indices(QuadraticForm(matrix(4, [2,0,0,1, 0,2,0,1, 0,0,2,1, 1,1,1,2]))) sage: S = _find_complete_set_of_restriction_vectors(indices.jacobi_index(), indices._r_representatives) sage: _local_restriction_matrix(indices._r_representatives, S).rank() 4 """ R = [map(vector, rs) for rs in R] length_inc = 5 max_length = 5 cur_length = 1 short_vectors = L.short_vector_list_up_to_length(max_length, True) S = list() restriction_space = FreeModule(QQ, len(R)).span([]) while (len(S) < len(R) + additional_s): while len(short_vectors[cur_length]) == 0: cur_length += 1 if max_length >= cur_length: max_length += length_inc short_vectors = L.short_vector_list_up_to_length( max_length, True) s = vector(short_vectors[cur_length].pop()) rcands = Set([s.dot_product(r) for rs in R for r in rs]) for r in rcands: v = _eval_restriction_vector(R, s, r, reduction_function) if len(S) - restriction_space.rank() < additional_s \ or v not in restriction_space : S.append((s, r)) restriction_space = restriction_space + FreeModule( QQ, len(R)).span([v]) if len(S) == len(R) + additional_s: break return S
row_groups__small): row_labels_dict = row_labels__small[L(s)] row_indices__sub = length_small * [None] for (l, (i, i_pre)) in row_labels_dict.iteritems(): row_indices__sub[i] = start + i_pre row_indices__small += row_indices__sub global_restriction_matrix = global_restriction_matrix__big.matrix_from_rows_and_columns( row_indices__small, [column_labels.index(l) for l in column_labels_relations]) else: global_restriction_matrix = global_restriction_matrix__big jacobi_indices = [m for (_, m, _, _) in row_groups] index_filters = dict((m, JacobiFormD1NNFilter(precision.index(), m)) for m in Set(jacobi_indices)) jacobi_forms = dict( (m, JacobiFormsD1NN(QQ, JacobiFormD1NNGamma(k, m), prec)) for (m, prec) in index_filters.iteritems()) forms = list() nmb_forms_coords = row_groups[-1][2] + row_groups[-1][3] ch1 = JacobiFormD1WeightCharacter(k) for (s, m, start, length) in row_groups: row_labels_dict = row_labels[m] for f in jacobi_forms[m].graded_submodule(None).basis(): f = f.fourier_expansion() v = vector(ZZ, len(row_labels_dict)) for (l, i) in row_labels_dict.iteritems(): v[i] = f[(ch1, l)]
def cartan_type(self): r""" Returns the Cartan type of the Cartan companion of self.b_matrix() Only crystallographic types are implemented Warning: this function is redundant but the corresonding method in CartanType does not recognize all the types """ A = self.cartan_companion() n = self.rk degrees_dict = dict(zip(range(n), map(sum, 2 - A))) degrees_set = Set(degrees_dict.values()) types_to_check = [["A", n]] if n > 1: types_to_check.append(["B", n]) if n > 2: types_to_check.append(["C", n]) if n > 3: types_to_check.append(["D", n]) if n >= 6 and n <= 8: types_to_check.append(["E", n]) if n == 4: types_to_check.append(["F", n]) if n == 2: types_to_check.append(["G", n]) if n > 1: types_to_check.append(["A", n - 1, 1]) types_to_check.append(["B", n - 1, 1]) types_to_check.append(["BC", n - 1, 2]) types_to_check.append(["A", 2 * n - 2, 2]) types_to_check.append(["A", 2 * n - 3, 2]) if n > 2: types_to_check.append(["C", n - 1, 1]) types_to_check.append(["D", n, 2]) if n > 3: types_to_check.append(["D", n - 1, 1]) if n >= 7 and n <= 9: types_to_check.append(["E", n - 1, 1]) if n == 5: types_to_check.append(["F", 4, 1]) if n == 3: types_to_check.append(["G", n - 1, 1]) types_to_check.append(["D", 4, 3]) if n == 5: types_to_check.append(["E", 6, 2]) for ct_name in types_to_check: ct = CartanType(ct_name) if 0 not in ct.index_set(): ct = ct.relabel(dict(zip(range(1, n + 1), range(n)))) ct_matrix = ct.cartan_matrix() ct_degrees_dict = dict(zip(range(n), map(sum, 2 - ct_matrix))) if Set(ct_degrees_dict.values()) != degrees_set: continue for p in Permutations(range(n)): relabeling = dict(zip(range(n), p)) ct_new = ct.relabel(relabeling) if ct_new.cartan_matrix() == A: return copy(ct_new) raise ValueError("Type not recognized")