# Revision history [back]

The code in the question seems to be designed to work with exact algebraic numbers.

In that case, it would seem natural to work with Sage's algebraic numbers, using QQbar (the field of algebraic numbers) and AA (the field of real algebraic numbers).

Below is an adaptation of the code in the question to do that (additionally, this works around the problem of algebraic numbers too deeply nested in Sage's symbolic ring).

The exactify method on elements of QQbar and AA obtained from computations can simplify their internal representation (and thus make them display nicer).

class Circle:
"""Unified line and circle class. If A is zero,
then this represents a line."""

def __init__(self, A, B, C):
self.A = AA(A)
self.B = QQbar(B)
self.C = AA(C)
if A != 0:
self.center = -conjugate(B)
self.center.exactify()
elif A == 0:
self.center = None

def isCircle(self):
"""Am I a geometric circle in the complex plane?"""
return self.A != 0

def isLine(self):
"""Am I a geometric line in the complex plane?"""
return self.A == 0

def mobToRealLine(self):
I = QQbar.gen()
if self.isCircle():
"""Return the Mobius that takes self to the real line. It takes z0 + r to 0, and z0 +- Ir to +-1"""
z0 = self.center
a = 1/sqrt(r) * (1/2 - I/2)
b = -1/sqrt(r) * (1/2 - I/2) * (r+z0)
c = 1/sqrt(r) * (1/2 + I/2)
d = 1/sqrt(r) * (1/2 + I/2) * (r-z0)
a.exactify()
b.exactify()
c.exactify()
d.exactify()
return Mobius(a, b, c, d)
if self.isLine() and imag(self.B) != 0:
# This takes iC/2Im(B), 1/2 +- I(ReB + ImC)/(2ImB) to 0, +-1
B, C = self.B, self.C
a = (1-I)/sqrt(conjugate(B)/imag(B))
b = -(1/2+I/2)*C*sqrt(conjugate(B)/imag(B))/conjugate(B)
c = QQbar.zero()
d = (1/2+I/2)*sqrt(conjugate(B)/imag(B))
a.exactify()
b.exactify()
c.exactify()
d.exactify()
return Mobius(a, b, c, d)
else:
# Vertical line x = x0
B, C = self.B, self.C
x0 = -C/(2*B)
a = -sqrt(2)/2 + I*sqrt(2)/2
b = (sqrt(2)/2 - I*sqrt(2)/2)*x0
c = QQbar.zero()
d = -sqrt(2)/2 - I*sqrt(2)/2
a.exactify()
b.exactify()
c.exactify()
d.exactify()
return Mobius(a, b, c, d)

class Mobius:
"""Mobius transformation class"""
def __init__(self, a, b, c, d):
self.a = QQbar(a)
self.b = QQbar(b)
self.c = QQbar(c)
self.d = QQbar(d)
self.a.exactify()
self.b.exactify()
self.c.exactify()
self.d.exactify()
self.matrix = Matrix(QQbar, [[self.a, self.b], [self.c, self.d]])

def imageCircle(self, circle):  # Seems broken for a vertical line
"""Return the image of circle under self."""
A, B, C = circle.A, circle.B, circle.C
cA, cB, cC = conjugate(A), conjugate(B), conjugate(C)
a, b, c, d = self.a, self.b, self.c, self.d
ca, cb, cc, cd = conjugate(a), conjugate(b), conjugate(c), conjugate(d)
newA = A*abs(d)^2 - cc*d*B - c*cd*cB + C*abs(c)^2
newB = -A*cb*d + ca*d*B + cb*c*cB - ca*c*C
newC = A*abs(b)^2 - ca*b*B - a*cb*cB + abs(a)^2*C
newA.exactify()
newB.exactify()
newC.exactify()
print("new A, B, C = {}, {}, {}".format(newA, newB, newC))
return Circle(newA, newB, newC)

"""returns Circle(A,B,C) with appropriate A, B, C (for simplicity of use)"""
A = AA.one()
B = -conjugate(QQbar(center))

sage: c1 = circle(I + 1, 4)