def jordan_blocks_2(S): ''' S: half integral matrix Returns the instance of JordanBlocks attached to a list of tuples (a, b) `a' is a integer which represents an exponent. `b' corresponds a quadratic form with size <= 2, that is, `b' is in [1, 3, 5, 7] or is equal to strings 'h' or 'y'. If `b' is equal to 'h', then the gram matrix of the corresponding quadratic form is equal to matrix([[0, 1/2], [1/2, 0]]). If `b' is equal to 'y', then the gram matrix of the corresponding quadratic form is equal to matrix([[1, 1/2], [1/2, 1]]). If `b' is in [1, 3, 5, 7], then the corresponding gram matrix is equal to matrix([[b]]). These tuples are sorted so that assumptions of Theorem 4.1 or Theorem 4.2 hold. ''' ls = _jordan_decomposition_2(S) # ls is a list of jordan blocks but it may contain diagonal entries of # units of length >= 3. # We take another jordan blocks by _trans_jordan_dec_2. res = [(a, b) for a, b in ls if isinstance(b, str)] diag_elts = [(a, b) for a, b in ls if not isinstance(b, str)] for a, us_w_idx in list_group_by(diag_elts, lambda x: x[0]): l = _trans_jordan_dec_2([_b for _, _b in us_w_idx]) for b in l: if isinstance(b, str): res.append((a + 1, b)) else: res.append((a, b)) # Sort the result so that assumptions of Theorem 4.1 and 4.2 hold. non_diags = ("h", "y") res1 = [] for _, blcs in sorted(list_group_by(res, lambda x: x[0]), key=lambda x: -x[0]): unit_diags = [(a, qf) for a, qf in blcs if qf not in non_diags] non_unit_diags = [(a, qf) for a, qf in blcs if qf in non_diags] blcs = unit_diags + non_unit_diags res1.extend(blcs) return JordanBlocks(res1, two)
def group_by_reduced_forms(self): ''' In list(self), we define equivalent relation ~ by t1, t2 in list(self), rank(t1) == rank(t2) and if rank(t1) == 0, t1 ~ t2, if and only if t2 == (0, 0, 0) if rank(t1) == 1, t1 ~ t2, if and only if gcd(t1) == gcd(t2), if rank(t1) == 2, t1 ~ t2 if and only if reduced forms of t1 and t2 are equal. Then this function returns a dictionary such that rep => equiv_class where rep is an element of representatives of this equivalent class and equiv_class is a equivalent class that contains rep. ''' r0 = [] r1 = [] r2 = [] for t in self: n, r, m = t if t == (0, 0, 0): r0.append(t) elif 4 * n * m - r ** 2 == 0: r1.append(t) else: r2.append(t) res0 = {(0, 0, 0): set(r0)} res1 = {ls[0]: ls for k, ls in list_group_by(r1, lambda t: gcd([QQ(x) for x in t]))} res2 = {ls[0]: ls for k, ls in list_group_by(r2, lambda x: reduced_form_with_sign(x)[0])} res = {} for dct in [res0, res1, res2]: res.update(dct) return res
def group_by_reduced_forms_with_sgn(self): ''' Returns a dictionary whose keys are representatives of equivalent class of list(self.pos_defs()). Its value at (n, r, m) is the list of ((n1, r1, m1), sgn) where (n1, r1, m1) is unimodular equivalent to (n, r, m) and sgn is 1 if reduced_form_with_sign((n, r, m))[0] is (n1, r1, m1) and reduced_form_with_sign((n, r, m))[1] == 1 otherwise -1. ''' pos_forms = [] for t in self.pos_defs(): rdf, sgn = reduced_form_with_sign(t) pos_forms.append((t, rdf, sgn)) grpd_by_rdf = list_group_by(pos_forms, lambda x: x[1]) res = {} for _, ls in grpd_by_rdf: a_tupl, _, a_sgn = ls[0] res[a_tupl] = [(t, _sgn * a_sgn) for t, _, _sgn in ls] return res
def _inverse(self): a = self[(0, 0, 0)] if a == 0: raise ZeroDivisionError prec = self.prec R = self.base_ring if a != R(1): return (self * a ** (-1))._inverse() * a ** (-1) res_dict = {(0, 0, 0): R(1)} def norm(t): return t[0] + t[2] prec_dict = dict(list_group_by(list(prec), norm)) prec_d_keys = sorted(prec_dict.keys())[1:] for a in prec_d_keys: for t in prec_dict[a]: l = list(_spos_def_mats_lt(t)) l.remove(t) res_dict[t] = - sum([res_dict[u] * self[(t[0] - u[0], t[1] - u[1], t[2] - u[2])] for u in l]) return QexpLevel1(res_dict, prec, base_ring=self.base_ring)