Example #1
0
 def __init__(self, polygon, involutions, z, w):
     self._poly = polygon
     self._cur_poly = []
     self._involutions = involutions
     self._w = w
     self._z = z
     self._line = None
     self._decomposition = []
     self._mul_dec = Matrix()
     self._previous_edge = None
     self._involution_dict = None
     self._crossing = True
Example #2
0
 def gen_reprs(self):
     # Generating set of orbit representatives
     # of action $\Gamma_1(N)$ on $\Gamma_0(N)$
     self.reprs = []
     for a in range(1, self.N // 2 + 1):
         if gcd(a, self.N) == 1:
             self.reprs.append(Matrix(a, 0, 0, inv_element(a, self.N)))
Example #3
0
    def decompose_matrix(self, matrix_str):
        try:
            matrix = Matrix.from_str(matrix_str)
        except Exception:
            raise ApiError('Matrix should be in following format: a, b, c, d')

        if not self.is_in_subgroup(matrix):
            raise ApiError('Matrix does not belong to subgroup')

        z = Field(0.5+1.5j)
        w = matrix.moe(z)
        decomposer = Decomposer(polygon=self._domain, involutions=self._involutions, z=z, w=w)

        try:
            self._decomposition = decomposer.decompose()
        except Exception:
            raise ApiError('unexpected algorithm error occurred.')
Example #4
0
    def is_in_subgroup(self, matrix: Matrix):
        if matrix.det() != 1:
            return False

        a, b, c, d = matrix.a, matrix.b, matrix.c, matrix.d
        n = self._n

        if self._subgroup_name is ClassicalSubgroups.GammaBotZero:
            return c % n == 0
        elif self._subgroup_name is ClassicalSubgroups.GammaTopZero:
            return b % n == 0
        elif self._subgroup_name is ClassicalSubgroups.GammaBotOne:
            return a % n == 1 and d % n == 1 and c % n == 0
        elif self._subgroup_name is ClassicalSubgroups.GammaTopOne:
            return a % n == 1 and d % n == 1 and b % n == 0
        elif self._subgroup_name is ClassicalSubgroups.Gamma:
            return a % n == 1 and d % n == 1 and b % n == 0 and c % n == 0

        return False
Example #5
0
    def decompose(self):
        if self._w == self._z:
            return [Matrix(1, 0, 0, 1)]

        self._line = Geodesic(self._w, self._z)

        self.prepare_involutions()

        self._poly = cyclic_sorted(self._poly)
        self._cur_poly = self._poly[::]

        previous_edges = get_cross_edges(self._cur_poly, self._line)

        if len(previous_edges) != 1:
            raise Exception('Number of crossed edges is not equal to 1')

        self._previous_edge = previous_edges[0]

        while self._crossing:
            self._iteration()

        return self._decomposition
Example #6
0
 def not_cached_reduced(self, mat):
     a, b = mat.a, mat.b
     a, b = self.pair_reduced(a, b)[0:2]
     d, c = list(map(lambda x: x % self.N, get_xy(a, b, self.N)))
     return Matrix(a, b, -c, d) % self.N
Example #7
0
 def gen_reprs(self):
     for a, b, N in self.pair_reprs:
         self.reprs.append(self.reduced(Matrix(a, b, 0, 0)))
Example #8
0
 def gen_reprs(self):
     self.reprs = []
     for a, b, N in self.pair_reprs:
         self.reprs.append(self.reduced(Matrix(0, 0, a, b)))
Example #9
0
 def reduced(self, mat: Matrix):
     a, b = mat._a, mat._d
     if a > self.N // 2:
         a = (-a) % self.N
         b = (-b) % self.N
     return Matrix(a, 0, 0, b)
Example #10
0
 def gen_reprs(self):
     for a in range(self.N):
         self.reprs.append(Matrix(1, a, 0, 1))
Example #11
0
class Decomposer(object):
    def __init__(self, polygon, involutions, z, w):
        self._poly = polygon
        self._cur_poly = []
        self._involutions = involutions
        self._w = w
        self._z = z
        self._line = None
        self._decomposition = []
        self._mul_dec = Matrix()
        self._previous_edge = None
        self._involution_dict = None
        self._crossing = True

    def decompose(self):
        if self._w == self._z:
            return [Matrix(1, 0, 0, 1)]

        self._line = Geodesic(self._w, self._z)

        self.prepare_involutions()

        self._poly = cyclic_sorted(self._poly)
        self._cur_poly = self._poly[::]

        previous_edges = get_cross_edges(self._cur_poly, self._line)

        if len(previous_edges) != 1:
            raise Exception('Number of crossed edges is not equal to 1')

        self._previous_edge = previous_edges[0]

        while self._crossing:
            self._iteration()

        return self._decomposition

    def _iteration(self):
        _g_i = self._get_involution(self._previous_edge).inv()
        g_i = self._mul_dec * _g_i * self._mul_dec.inv()

        self._decomposition.append(_g_i)
        self._mul_dec = g_i * self._mul_dec

        for i in range(len(self._cur_poly)):
            self._cur_poly[i] = g_i.moe(self._cur_poly[i])

        # geo_drawer.draw(self._cur_poly, color='grey')

        crossed = get_cross_edges(self._cur_poly, self._line)
        crossed = list(
            filter(lambda e: not undirected_eq(e, self._previous_edge),
                   crossed))

        if not crossed:
            self._crossing = False

        elif len(crossed) == 1:
            self._previous_edge = crossed[0]

        elif len(crossed) == 2:
            # Decision: which way should we go
            # Trying first
            first_poly = self._cur_poly[::]
            for i in range(len(first_poly)):
                first_poly[i] = g_i.moe(first_poly[i])
            _crossed = get_cross_edges(self._cur_poly, self._line)
            _crossed = list(
                filter(lambda e: not undirected_eq(e, crossed[0]), _crossed))

            if _crossed:
                self._previous_edge = crossed[0]
            else:
                self._previous_edge = crossed[1]

        else:
            raise Exception('there are more than 2 crossing edges')

    def prepare_involutions(self):
        self._involution_dict = dict()

        for a, b, g in self._involutions:
            self._involution_dict[a] = g
            self._involution_dict[b] = g.inv()

    def _get_involution(self, edge):
        edge_ = self._poly[self._cur_poly.index(edge)]
        return self._involution_dict[edge_]
Example #12
0
 def get_decomposition(self):
     return Matrix.beautify(self._decomposition)
Example #13
0
 def get_generators_str(self):
     return Matrix.beautify(self._generators)