1 | initial version |
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.radius = abs(sqrt(abs(self.center)^2 - C))
self.center.exactify()
self.radius.exactify()
elif A == 0:
self.center = None
self.radius = 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
r = self.radius
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)
def circle(center, radius):
"""returns Circle(A,B,C) with appropriate A, B, C (for simplicity of use)"""
A = AA.one()
B = -conjugate(QQbar(center))
C = abs(QQbar(center))^2 - AA(radius)^2
B.exactify()
C.exactify()
return Circle(A, B, C)
With the above definitions, we get:
sage: c1 = circle(I + 1, 4)
sage: m1 = c1.mobToRealLine()
sage: c2 = m1.imageCircle(c1)
new A, B, C = 0, 4*I, 0