def fixed_point_set(self): #UHP r""" Return the a list or geodesic containing the fixed point set of orientation-preserving isometries. OUTPUT: - a list of hyperbolic points or a hyperbolic geodesic EXAMPLES:: sage: UHP = HyperbolicPlane().UHP() sage: H = UHP.get_isometry(matrix(2, [-2/3,-1/3,-1/3,-2/3])) sage: g = H.fixed_point_set(); g Geodesic in UHP from -1 to 1 sage: H(g.start()) == g.start() True sage: H(g.end()) == g.end() True sage: A = UHP.get_isometry(matrix(2,[0,1,1,0])) sage: A.preserves_orientation() False sage: A.fixed_point_set() Geodesic in UHP from 1 to -1 :: sage: B = UHP.get_isometry(identity_matrix(2)) sage: B.fixed_point_set() Traceback (most recent call last): ... ValueError: the identity transformation fixes the entire hyperbolic plane """ d = sqrt(self._matrix.det() ** 2) M = self._matrix / sqrt(d) tau = M.trace() ** 2 M_cls = self.classification() if M_cls == 'identity': raise ValueError("the identity transformation fixes the entire " "hyperbolic plane") pt = self.domain().get_point if M_cls == 'parabolic': if abs(M[1, 0]) < EPSILON: return [pt(infinity)] else: # boundary point return [pt((M[0,0] - M[1,1]) / (2*M[1,0]))] elif M_cls == 'elliptic': d = sqrt(tau - 4) return [pt((M[0,0] - M[1,1] + sign(M[1,0])*d) / (2*M[1,0]))] elif M_cls == 'hyperbolic': if M[1,0] != 0: #if the isometry doesn't fix infinity d = sqrt(tau - 4) p_1 = (M[0,0] - M[1,1]+d) / (2*M[1,0]) p_2 = (M[0,0] - M[1,1]-d) / (2*M[1,0]) return self.domain().get_geodesic(pt(p_1), pt(p_2)) #else, it fixes infinity. p_1 = M[0,1] / (M[1,1] - M[0,0]) p_2 = infinity return self.domain().get_geodesic(pt(p_1), pt(p_2)) try: p, q = [M.eigenvectors_right()[k][1][0] for k in range(2)] except IndexError: M = M.change_ring(RDF) p, q = [M.eigenvectors_right()[k][1][0] for k in range(2)] pts = [] if p[1] == 0: pts.append(infinity) else: p = p[0] / p[1] if imag(p) >= 0: pts.append(p) if q[1] == 0: pts.append(infinity) else: q = q[0] / q[1] if imag(q) >= 0: pts.append(q) pts = [pt(k) for k in pts] if len(pts) == 2: return self.domain().get_geodesic(*pts) return pts
def fixed_point_set(self): #UHP r""" Return the a list or geodesic containing the fixed point set of orientation-preserving isometries. OUTPUT: - a list of hyperbolic points or a hyperbolic geodesic EXAMPLES:: sage: UHP = HyperbolicPlane().UHP() sage: H = UHP.get_isometry(matrix(2, [-2/3,-1/3,-1/3,-2/3])) sage: g = H.fixed_point_set(); g Geodesic in UHP from -1 to 1 sage: H(g.start()) == g.start() True sage: H(g.end()) == g.end() True sage: A = UHP.get_isometry(matrix(2,[0,1,1,0])) sage: A.preserves_orientation() False sage: A.fixed_point_set() Geodesic in UHP from 1 to -1 :: sage: B = UHP.get_isometry(identity_matrix(2)) sage: B.fixed_point_set() Traceback (most recent call last): ... ValueError: the identity transformation fixes the entire hyperbolic plane """ d = sqrt(self._matrix.det()**2) M = self._matrix / sqrt(d) tau = M.trace()**2 M_cls = self.classification() if M_cls == 'identity': raise ValueError("the identity transformation fixes the entire " "hyperbolic plane") pt = self.domain().get_point if M_cls == 'parabolic': if abs(M[1, 0]) < EPSILON: return [pt(infinity)] else: # boundary point return [pt((M[0, 0] - M[1, 1]) / (2 * M[1, 0]))] elif M_cls == 'elliptic': d = sqrt(tau - 4) return [ pt((M[0, 0] - M[1, 1] + sign(M[1, 0]) * d) / (2 * M[1, 0])) ] elif M_cls == 'hyperbolic': if M[1, 0] != 0: #if the isometry doesn't fix infinity d = sqrt(tau - 4) p_1 = (M[0, 0] - M[1, 1] + d) / (2 * M[1, 0]) p_2 = (M[0, 0] - M[1, 1] - d) / (2 * M[1, 0]) return self.domain().get_geodesic(pt(p_1), pt(p_2)) #else, it fixes infinity. p_1 = M[0, 1] / (M[1, 1] - M[0, 0]) p_2 = infinity return self.domain().get_geodesic(pt(p_1), pt(p_2)) try: p, q = [M.eigenvectors_right()[k][1][0] for k in range(2)] except IndexError: M = M.change_ring(RDF) p, q = [M.eigenvectors_right()[k][1][0] for k in range(2)] pts = [] if p[1] == 0: pts.append(infinity) else: p = p[0] / p[1] if imag(p) >= 0: pts.append(p) if q[1] == 0: pts.append(infinity) else: q = q[0] / q[1] if imag(q) >= 0: pts.append(q) pts = [pt(k) for k in pts] if len(pts) == 2: return self.domain().get_geodesic(*pts) return pts