Skip to content

Commit 43b556b

Browse files
committed
added a RationalAngle type
1 parent bef08dc commit 43b556b

File tree

5 files changed

+292
-261
lines changed

5 files changed

+292
-261
lines changed

src/Mandelbrot.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ export HubbardTree
99
export AngledInternalAddress
1010
export OrientedHubbardTree
1111

12+
export RationalAngle
13+
1214
export parameter
1315

1416
#export HyperbolicComponent

src/sequences/AngleDoubling.jl

Lines changed: 63 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,89 @@
11
include("Sequences.jl")
22

3-
function orbit(angle::Rational)
4-
items = Rational[]
3+
alphabet = ['*','A','B']
4+
5+
struct RationalAngle <: Number
6+
value::Rational
7+
function RationalAngle(theta::Rational)
8+
if theta > 1
9+
@warn "Creating angle from number larger than 1, only the fractional part will be kept."
10+
new(mod(theta,1))
11+
else
12+
new(theta)
13+
end
14+
end
15+
end
16+
17+
import Base: +, *, /, <, >, numerator, denominator
18+
19+
phi::RationalAngle + theta::RationalAngle = RationalAngle(mod(phi.value+theta.value,1))
20+
theta::RationalAngle * s::Number = RationalAngle(mod(theta.value*s,1))
21+
s::Number * theta::RationalAngle = theta * s
22+
theta::RationalAngle / s::Number = RationalAngle(theta.value/s)
23+
phi::RationalAngle > theta::RationalAngle = phi.value > theta.value
24+
phi::RationalAngle < theta::RationalAngle = phi.value < theta.value
25+
26+
denominator(theta::RationalAngle) = denominator(theta.value)
27+
numerator(theta::RationalAngle) = numerator(theta.value)
28+
29+
function orbit(angle::RationalAngle)
30+
items = RationalAngle[]
531

632
while isempty(findall(x->x==angle,items))
733
push!(items,angle)
834
angle = angle*2
9-
angle = angle%1//1
1035
end
1136

1237
preperiod = findall(x->x==angle,items)[1] - 1
1338

14-
return Sequence{Rational}(items,preperiod)
39+
return Sequence{RationalAngle}(items,preperiod)
1540

1641
end
1742

18-
abstract type KneadingSymbol end
43+
struct KneadingSymbol <: Integer
44+
value::Int
45+
function KneadingSymbol(value::Int)
46+
0 <= value <=2 || error("Value must be in range [0, 2]")
47+
new(value)
48+
end
49+
end
1950

20-
struct A <: KneadingSymbol end
21-
struct B <: KneadingSymbol end
22-
struct star <: KneadingSymbol end
51+
#necessary for using kneading sequences as dictionary keys
52+
Base.hash(d::KneadingSymbol,h::UInt64) = hash(d.value,h)
2353

24-
Base.show(io::IO, symb::A) = print(io,'A')
25-
Base.show(io::IO, symb::B) = print(io,'B')
26-
Base.show(io::IO, symb::star) = print(io,'*')
54+
function KneadingSymbol(c::Char)
55+
return KneadingSymbol(first(findall(x->x==c,alphabet))-1)
56+
end
57+
58+
function Base.show(io::IO, symb::KneadingSymbol)
59+
print(io,alphabet[symb.value+1])
60+
end
2761

2862
const KneadingSequence = Sequence{KneadingSymbol}
2963

30-
function KneadingSequence(angle::Rational)
64+
function KneadingSequence(angle::RationalAngle)
3165
orb = orbit(angle)
3266
return thetaitinerary(angle,orb)
3367
end
3468

35-
function thetaitinerary(theta::Rational,angle::Rational)
69+
function thetaitinerary(theta::RationalAngle,angle::RationalAngle)
3670
return thetaitinerary(theta,orbit(angle))
3771
end
3872

39-
function thetaitinerary(theta::Rational,orb::Sequence)
73+
function thetaitinerary(theta::RationalAngle,orb::Sequence)
4074
a = theta/2
41-
b = (theta+1)/2
75+
b = theta/2+RationalAngle(1//2)
4276
itinerary = KneadingSymbol[]
4377

4478
for angle in orb.items
4579
if angle == a
46-
push!(itinerary,star())
80+
push!(itinerary,KneadingSymbol('*'))
4781
elseif angle == b
48-
push!(itinerary,star())
82+
push!(itinerary,KneadingSymbol('*'))
4983
elseif angle > a && angle < b
50-
push!(itinerary,A())
84+
push!(itinerary,KneadingSymbol('A'))
5185
else
52-
push!(itinerary,B())
86+
push!(itinerary,KneadingSymbol('B'))
5387
end
5488
end
5589

@@ -115,15 +149,15 @@ end
115149
function KneadingSequence(intadd::InternalAddress)
116150
address = copy(intadd.addr)
117151
if address == [1]
118-
return Sequence{KneadingSymbol}(KneadingSymbol[A()],0)
152+
return Sequence{KneadingSymbol}(KneadingSymbol[KneadingSymbol('A')],0)
119153
else
120154
s = pop!(address)
121155
K = KneadingSequence(InternalAddress(address))
122156
R = K.items[mod1.(1:s-1,end)]
123-
if K.items[mod1(s,end)] == A()
124-
push!(R,B())
157+
if K.items[mod1(s,end)] == KneadingSymbol('A')
158+
push!(R,KneadingSymbol('B'))
125159
else
126-
push!(R,A())
160+
push!(R,KneadingSymbol('A'))
127161
end
128162
return Sequence{KneadingSymbol}(R,0)
129163
end
@@ -166,19 +200,19 @@ end
166200

167201
struct AngledInternalAddress
168202
addr::Vector{Int}
169-
angles::Vector{Rational}
203+
angles::Vector{RationalAngle}
170204
end
171205

172206
#Lemma 11.14 TreesBook page 146
173-
function AngledInternalAddress(theta::Rational)
207+
function AngledInternalAddress(theta::RationalAngle)
174208
intadd = InternalAddress(KneadingSequence(theta))
175209
denoms = denominators(intadd)
176210
angles = Rational[]
177211

178212
for ii in 1:length(intadd)-1
179213
n = 0
180214
for jj in 1:(denoms[ii] - 1)
181-
if ((2//1)^((jj-1)*intadd[ii])*theta)%1 <= theta
215+
if ((2//1)^((jj-1)*intadd[ii])*theta) <= theta
182216
n += 1
183217
end
184218
end
@@ -323,7 +357,7 @@ Base.Int(d::Digit) = d.value
323357

324358
const BinaryExpansion = Sequence{Digit{2}}
325359

326-
function BinaryExpansion(theta::Rational)
360+
function BinaryExpansion(theta::RationalAngle)
327361
orb = orbit(theta)
328362
itinerary = Digit{2}[]
329363
zero = Digit{2}(0)
@@ -338,7 +372,7 @@ function BinaryExpansion(theta::Rational)
338372
return Sequence{Digit{2}}(collect(itinerary),orb.preperiod)
339373
end
340374

341-
function Rational(bits::BinaryExpansion)
375+
function RationalAngle(bits::BinaryExpansion)
342376
theta = 0//1
343377
k = bits.period
344378
r = 1//(1//1-(2//1)^-k)
@@ -351,5 +385,5 @@ function Rational(bits::BinaryExpansion)
351385
end
352386
end
353387
end
354-
return theta
388+
return RationalAngle(theta)
355389
end

0 commit comments

Comments
 (0)