Sage Apollonian and Schmidt Pictures
system:sage


<p><span style="font-size: x-large;"><strong>Worksheet for Computing K-Apollonian and Schmidt Arrangement pictures</strong></span></p>
<p><span style="font-size: medium;">Summer 2017, Version 1.0<br /></span></p>
<p><span style="font-size: medium;">Coding: Katherine E. Stange</span></p>
<p><span style="font-size: medium;">Algorithms: Katherine E. Stange and Daniel Martin</span></p>
<p><span style="font-size: medium;"><a id="license_title_link" href="http://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">Licensed under Attribution-NonCommercial-ShareAlike 4.0 International</a></span></p>

{{{id=19|
################################################
## Colour and Transparency Schemes Setup
################################################

# Transparency schemes
constant_transparency = lambda x, c : x[0]  # parameter is constant
decreasing_transparency = lambda x, c : c/(x[0]) + x[1]  # parameters are upper bound on curvatures, translation
increasing_transparency = lambda x, c : x[1] - c/(x[0])  # parameter is upper bound on curvatures, translation

# Colour schemes
modular_colour = lambda x, c : x[0][ Mod(c*x[1][1] + x[1][2],x[1][0]) ]  # Use residue of curvature
prime_colour = lambda x, c : x[0][ int(ZZ(c).is_prime()) ]  # Two-colours (first two of some scheme)

# 4-colour schemes
colour_cu = [Color('#cfb87c'), Color('#000000'), Color('#565a5c'), Color('#a2a4a3')] # University of Colorado official colours
colour_saul = [Color('#4c3f54'),Color('#d13525'),Color('#f2c057'),Color('#486824')]
colour_antique = [Color('#a4cabc'),Color('#eab364'),Color('#b2473e'),Color('#acbd78')]
colour_green = [Color('#919636'),Color('#524a3a'),Color('#fffae1'),Color('#5a5f37')]
colour_92 = [Color('#fbcd4b'),Color('#a3a599'),Color('#282623'),Color('#88a550')]
colour_golden = [Color('#882426'),Color('#cdbea7'),Color('#323030'),Color('#c29545')]
colour_pool = [Color('#344d90'),Color('#5cc5ef'),Color('#ffb745'),Color('#e7552c')]
colour_distinct = [Color('#52908b'),Color('#e5e2ca'),Color('#ddbc95'),Color('#e7472e')]
colour_nightlife = [Color('#00cffa'),Color('#ff0038'),Color('#ffce38'),Color('#020509')]
colour_a = [Color('#4c3f54'),Color('#d13525'),Color('#f2c057'),Color('#486824')]
colour_b = [Color('#aa3939'),Color('#aa6c39'),Color('#226666'),Color('#2d882d')]
colour_c = [Color('#632770'),Color('#923158'),Color('#6c9b34'),Color('#9aa637')]
palettes_4 = [colour_cu, colour_saul, colour_antique, colour_green, colour_92, colour_golden, colour_pool, colour_distinct, colour_nightlife, colour_a, colour_b, colour_c]

# 5-colour schemes
colour_5 = [Color('#270101'),Color('#720017'),Color('#d8d583'),Color('#d9ac2a'),Color('#763f02')]
palettes_5 = [colour_5]

# 6-colour schemes
colour_6 = [Color('#21B6A8'), Color('#177F75'), Color('#B6212D'), Color('#7F171F'), Color('#B67721'), Color('#7F5417')]
colour_6alt = [Color('#DD1E2F'), Color('#EBB035'), Color('#06A2CB'), Color('#218559'), Color('#D0C6B1'), Color('#192823')]
colour_6seeds = [Color('#B2EEEE'), Color('#7ED6DA'), Color('#3682BC'), Color('#243C5C'), Color('#324E51'), Color('#B8AC7F')]
palettes_6 = [colour_6, colour_6alt, colour_6seeds]

# 24-colour schemes
colour_24 = [Color('#ea4b3d'),Color('#e48022'),Color('#fdce05'),Color('#f0deb5'),Color('#36485e'),Color('#2b2b2b'),Color('#9b59b1'),Color('#376f7e'),Color('#3496d7'),Color('#3396e3'),Color('#2ccc74'),Color('#1bbc9b'),Color('#ebf1ef'),Color('#96a5a5'),Color('#336041'),Color('#735ec5'),Color('#604436'),Color('#60335e'),Color('#ee727c'),Color('#a5c53c'),Color('#f47cc3'),Color('#77302a'),Color('#a28671'),Color('#b7c8f3'),Color('#5165a0')]
palettes_24 = [colour_24]

# Function colour_demo(n) shows all the possible n-colour palettes
def namestr(obj, namespace):
    return [name for name in namespace if namespace[name] is obj]
def colour_demo(n):
    pic = Graphics()
    palettes = []
    if n == 4:
        palettes = palettes_4
    if n == 5:
        palettes = palettes_5
    if n == 6:
        palettes = palettes_6
    if n == 24:
        palettes = palettes_24
    for i in range(len(palettes[0])):
        pic += text(  str(i), (i,-1) )
    for palette in range(len(palettes)):
        pic += text(  namestr(palettes[palette], globals()), (-2, palette) )
        for colour in palettes[palette]:
            pic += disk( (palettes[palette].index(colour), palette), 1/2, (0,2*pi), color=colour )
    pic.show(axes=False)

# Gradient-disk scheme
# Example usage: gradient_disk( (0,0), 1, colour_pool[2], colour_pool[0] )
# fact=100 controls the fineness of the gradient
def gradient_disk( coords, radius, color1, color2, fact=100 ):
    pic = Graphics()
    num_disks = fact*radius
    for i in range(0,num_disks+1):
        pic += disk( coords, radius*(1-i/num_disks), (0,2*pi), color=color1.blend(color2,fraction=i/num_disks) )
    return pic

###############################################
## Main Graphing Functions
###############################################

# The function precompute_circles obtains the coordinates of the circles in a given range
# disc = the root of the field (fundamental-discriminant or fundamental-discriminant/4, e.g. -1 for Gaussian, -2 for Sqrt(2) packing, -3 for Eisenstein etc.)
# curvature_bound = the upper bound on curvatures
# xmin, xmax, ymin, ymax = give bounds on the centre of the circle
def precompute_circles( dis, curvature_bound, xmax, ymax ):
    coords = []
    poly_coeffs = obtain_polycoeffs( dis )
    coord_coeffs = obtain_coords( dis )
    s_lower = 0
    if Mod(dis,4) == Mod(1,4):
        s_lower = -xmax*curvature_bound
    for r in range(curvature_bound):
        r_coords = []
        for s in range(s_lower,xmax*curvature_bound):
            for t in range(-ymax*curvature_bound,ymax*curvature_bound):
                if Mod(s^2 + poly_coeffs[0]*s*t + poly_coeffs[1]*t^2+t,r) == Mod(0,r):
                    curv = coord_coeffs[0]*r
                    xcoord = coord_coeffs[1]*s + coord_coeffs[2]*t
                    ycoord = coord_coeffs[3]*t + 1 
                    if [xcoord,ycoord,curv] not in r_coords:
                        r_coords.append([xcoord,ycoord,curv]) # first and third scaled
                        if xcoord <> 0:
                            r_coords.append([-xcoord,ycoord,curv])
                        if ycoord <> 0:
                            r_coords.append([xcoord,-ycoord,curv])
                        if xcoord <> 0 and ycoord <> 0:
                            r_coords.append([-xcoord,-ycoord,curv])
        coords += r_coords
    return coords
    
# Function filter_circles_rectangular will filter the coordinate list produced by precompute_circles to obtain just those needed for your purposes
# In this case, you can specify the curvature lower and upper bounds, and a rectangular region
# format of output list element is [ center-coordinates, radius, integer-scaled-curvature ]
# the tag filter_down=True will remove all circles contained in others, useful for Apollonian-type circle packings
def filter_circles_rectangular( dis, coords, curvature_lower_bound, curvature_upper_bound, xmin, xmax, ymin, ymax, filter_down=False ):
    rootval = obtain_sqrt(dis)
    curvature_factor = obtain_coords( dis )[0]
    circs = []
    if filter_down:
        coords.sort(key = lambda x: x[2])
    for coord in coords:
        if coord[2] >= curvature_lower_bound*curvature_factor and coord[2] <= curvature_upper_bound*curvature_factor:
            if coord[2] == 0:
                circs.append( [ (0,0), 0, 0 ] )
            if coord[2] > 0 and coord[0]/coord[2] > xmin and coord[0]/coord[2] < xmax:
                if coord[1]/(coord[2]*rootval) > ymin and coord[1]/(coord[2]*rootval) < ymax:
                    new_coord = [ ( coord[0]/(coord[2]), coord[1]/(coord[2]*rootval) ), 1/(coord[2]*rootval), coord[2]/curvature_factor ]
                    if not filter_down or not containment(new_coord, circs):
                        circs.append( new_coord )
    return circs
    
# Another filtering function, this time by curvature lower and upper bound, and a disk region given by center and radius squared
def filter_circles_circular( dis, coords, curvature_lower_bound, curvature_upper_bound, xctr, yctr, radius_squared, filter_down=False ):
    rootval = obtain_sqrt(dis)
    curvature_factor = obtain_coords( dis )[0]
    circs = []
    if filter_down:
        coords.sort(key = lambda x: x[2])
    for coord in coords:
        if coord[2] >= curvature_lower_bound*curvature_factor and coord[2] <= curvature_upper_bound*curvature_factor:
            if coord[2] == 0 and [ (0,0), 0, 0 ] not in circs:
                circs.append( [ (0,0), 0, 0 ] )
            if coord[2] > 0 and (coord[0]/coord[2] - xctr)^2 + (coord[1]/(coord[2]*rootval) - yctr)^2 < radius_squared:
                new_coord = [ ( coord[0]/coord[2], coord[1]/(coord[2]*rootval) ), 1/(coord[2]*rootval), coord[2]/curvature_factor ]
                if not filter_down or not containment( new_coord, circs ):
                    circs.append( new_coord )
    return circs
    
# This command finally plots a picture
# Using disk_colour_scheme = gradient_disk, you must give a parameter list of the form [colour_scheme1, colour_parms1, colour_scheme2, colour_params2, fact]
# If using gradient, disk_transparency_scheme is ignored
def circle_picture( circle_list, object_type="circle", circle_colour_scheme=modular_colour, circle_colour_parameter_list=[colour_cu,[2,0,1]], circle_transparency_scheme=constant_transparency, circle_transparency_parameter_list=[1], disk_colour_scheme=modular_colour, disk_colour_parameter_list=[colour_cu,[1,0,0]], disk_transparency_scheme=constant_transparency, disk_transparency_parameter_list=[1/2], circle_thickness=1, sort_up=True, line_range=0, dis=-1):
    sqrtd = sqrt(-dis)
    if Mod(dis,4) == Mod(1,4):
        sqrtd = sqrtd/2
    pic = Graphics()
    if sort_up == True:
        circle_list.sort(key = lambda x: x[2])
    if sort_up == False:
        circle_list.sort(key = lambda x: -x[2])
    for circ in circle_list:
        if (object_type == "circle" or object_type == "combo") and circ[2] == 0:    
            offset_range = floor(line_range/sqrtd)
            for offset in range(-offset_range, offset_range):
                pic += line( [(-offset_range,offset*sqrtd),(offset_range,offset*sqrtd)], color = circle_colour_scheme(circle_colour_parameter_list, circ[2]), alpha = circle_transparency_scheme(circle_transparency_parameter_list, circ[2]), thickness=circle_thickness )
                if dis == -3:
                    pic += line( [((-1/2)*offset_range, (-sqrtd)*offset_range +offset*sqrtd*2), ( (1/2)*offset_range, (sqrtd)*offset_range +offset*sqrtd*2 )], color = circle_colour_scheme(circle_colour_parameter_list, circ[2]), alpha = circle_transparency_scheme(circle_transparency_parameter_list, circ[2]), thickness=circle_thickness )
                    pic += line( [((-1/2)*offset_range, (sqrtd)*offset_range +offset*sqrtd*2), ( (1/2)*offset_range, (-sqrtd)*offset_range +offset*sqrtd*2 )], color = circle_colour_scheme(circle_colour_parameter_list, circ[2]), alpha = circle_transparency_scheme(circle_transparency_parameter_list, circ[2]), thickness=circle_thickness )
        if circ[2] <> 0:
            if object_type == "disk" or object_type == "combo":
                if disk_colour_scheme == gradient_disk:
                    pic += gradient_disk( circ[0], circ[1], disk_colour_parameter_list[0](disk_colour_parameter_list[1], circ[2]), disk_colour_parameter_list[2](disk_colour_parameter_list[3], circ[2]), disk_colour_parameter_list[4] )
                if disk_colour_scheme <> gradient_disk:
                    pic += disk( circ[0], circ[1], (0,2*pi), color = disk_colour_scheme(disk_colour_parameter_list, circ[2]), alpha = disk_transparency_scheme(disk_transparency_parameter_list, circ[2]) )
            if object_type == "circle" or object_type == "combo":
                pic += circle( circ[0], circ[1], color = circle_colour_scheme(circle_colour_parameter_list, circ[2]), alpha = circle_transparency_scheme(circle_transparency_parameter_list, circ[2]), thickness=circle_thickness )
    return pic

##################################
## Some internal functions
##################################

# Helper function that detects if new circle is contained in some already existing circle
def containment( new_coord, circs ):
    contain_flag = False
    for circ in circs:
        ctrdst = sqrt( (new_coord[0][0]-circ[0][0])^2 + (new_coord[0][1]-circ[0][1])^2 )
        if ctrdst + new_coord[1] <= circ[1]:  # if center distance + small radius < big radius
            contain_flag = True
            break
    return contain_flag

# This internal function determines the appropriate sqrt needed for scaling pictures
def obtain_sqrt( dis ):
    return sqrt( -1*dis )    

# This internal function determines the coefficients of the polynomial based on the field discriminant.
# Use as s^2 + l[0]*s*t + l[1]*t^2 + t
def obtain_polycoeffs( dis ):
    if Mod(dis,4) == Mod(1,4):
        return [1,(1-dis)/4]
    if Mod(dis,4) <> Mod(1,4):
        return [0,-dis]
    
# This internal function determines the coordinates of a circle based on the field discriminant.
# Use as curv = l[0]*r*sqrt, curv-ctr = (l[1]*s*sqrt + l[2]*t*sqrt, (l[3]*t+1) )
def obtain_coords( dis ):
    if Mod(dis,4) == Mod(1,4):
        return [1,1,1/2,(-dis)/2]
    if Mod(dis,4) <> Mod(1,4):
        return [2,2,0,2*(-dis)]
///
}}}

<p><span style="font-size: x-large;"><strong><span style="font-family: andale mono,times;">Usage:</span></strong></span></p>
<p><span style="font-size: medium; font-family: andale mono,times;">Step 1) <strong>Precompute circles.</strong>&nbsp; The entry "dis" is the square root determining the field (-1 = Gaussian, -3 = Eisenstein etc.).&nbsp; The other entries bound the curvature and the absolute value of the centre coordinates.&nbsp; This is a time-intensive step for detailed pictures, so save the resulting list for future use.&nbsp; So do this once and then do Steps 2-5 as desired using the result.<br /></span></p>
<p><span style="font-size: medium; font-family: andale mono,times;">precompute_circles( dis, curvature_bound, xmax, ymax )</span></p>
<p><span style="font-size: medium; font-family: andale mono,times;">Step 2) <strong>Filter circles.&nbsp;</strong> You can either specify a rectangle (using xmin,xmax,ymin,ymax) or a circle by specifying center and radius.&nbsp; The rectangle or circle is used as the region in which <em>circle centres</em> are allowed.&nbsp; You must feed in the output of Step 1 (here as "coords"), as well as "dis" as in Step 1.&nbsp; This will filter the circles produced in Step 1 according to your desires.&nbsp; It won't compute new circles, so curvature_bound should be less than or equal to what you specified in Step 1, for example.<br /></span></p>
<p><span style="font-size: medium; font-family: andale mono,times;">filter_circles_rectangular( dis, coords, curvature_lower_bound, curvature_upper_bound, xmin, xmax, ymin, ymax, filter_down=False )</span></p>
<p><span style="font-size: medium; font-family: andale mono,times;">filter_circles_circular( dis, coords, curvature_lower_bound, curvature_upper_bound, xctr, yctr, radius_squared, filter_down=False )</span></p>
<p><span style="font-size: medium; font-family: andale mono,times;">Step 3) <strong>Create picture object.</strong>&nbsp; </span></p>
<ul>
<li><span style="font-size: medium; font-family: andale mono,times;">You can use either "disk" or "circle" or "combo" by specifying object_type.&nbsp; <br /></span></li>
<li><span style="font-size: medium; font-family: andale mono,times;">If using circles, you can use circle_colour_scheme and its associated parameter list, as well as a circle_transparency_scheme and its associated parameter list.</span></li>
<li><span style="font-size: medium; font-family: andale mono,times;">If using disks, you can use <span style="font-size: medium; font-family: andale mono,times;">disk_colour_scheme and its associated parameter list, as well as a disk_transparency_scheme and its associated parameter list.</span><br /></span></li>
<li><span style="font-size: medium; font-family: andale mono,times;">The parameter list for modular_colour scheme is of the form [ palette, [modulus, multiplier, translation] ].&nbsp; <br /></span></li>
<li><span style="font-size: medium; font-family: andale mono,times;">If using prime_colour, specify just [ palette ] (which should have at least two colours) for the parameter list.&nbsp; <br /></span></li>
<li><span style="font-size: medium; font-family: andale mono,times;">For transparency, you have the option of constant_transparency (then parameters are [alpha] 0=transparent, 1=solid), or increasing_transparency or decreasing_transparency.&nbsp; In the increasing/decreasing case, the parameters are [ upper_bound_on_alpha, translation ] (see the code above for the formula).&nbsp; <br /></span></li>
<li><span style="font-size: medium; font-family: andale mono,times;">If you choose gradient_disk for the disk_colour_scheme, then disk_transparency_schemes are ignored.&nbsp; The gradient_disk needs a parameter list like [colour_scheme1, colour_parms1, colour_scheme2, colour_params2, fact], where fact is a factor controlling how fine the gradient is.&nbsp; Higher fact means smoother gradient.</span></li>
<li><span style="font-size: medium; font-family: andale mono,times;">sort_up can be set to False in order to pile larger disks on smaller disks</span></li>
<li><span style="font-size: medium; font-family: andale mono,times;">circle_thickness can be controlled</span></li>
<li><span style="font-size: medium; font-family: andale mono,times;">line_range is set to a positive number to give more lines (otherwise lines -- curvature 0 -- are not shown).&nbsp; Increase until all the lines needed are appearing. If this is used, dis should be set to the discriminant in order to compute lines correctly.<br /></span></li>
</ul>
<p><span style="font-size: medium; font-family: andale mono,times;">circle_picture( circle_list, object_type="circle", circle_colour_scheme=modular_colour, circle_colour_parameter_list=[colour_cu,[2,0,1]], circle_transparency_scheme=constant_transparency, circle_transparency_parameter_list=[1], disk_colour_scheme=modular_colour, disk_colour_parameter_list=[colour_cu,[1,0,0]], disk_transparency_scheme=constant_transparency, disk_transparency_parameter_list=[1/2], circle_thickness=1, sort_up=True, line_range=0, dis=-1)</span></p>
<p><span style="font-size: medium; font-family: andale mono,times;"><span style="font-size: medium; font-family: andale mono,times;">Step 4) <strong>Display the object.&nbsp;</strong> You can add things like "axes=False" to beautify the output.</span></span></p>
<p><span style="font-size: medium; font-family: andale mono,times;"><span style="font-size: medium; font-family: andale mono,times;">pic.show(axes=False)</span></span></p>
<p><span style="font-size: medium; font-family: andale mono,times;"><span style="font-size: medium; font-family: andale mono,times;">Step 5) <strong>Save your image.</strong>&nbsp; It will save as pdf (vector graphics) if extension is '.pdf', and as .png if you use that extension, etc.<br /></span></span></p>
<p><span style="font-size: medium; font-family: andale mono,times;"><span style="font-size: medium; font-family: andale mono,times;">pic.save('filename-with-path.pdf', axes=False)<br /></span></span></p>
<p><span style="font-size: medium; font-family: andale mono,times;">Have fun!</span></p>

{{{id=45|
# Gaussian (sqrt(-1)) example, showing interior of one circle of the Schmidt arrangement.
gaussian_coords_20 = precompute_circles( -1, 20, 0.5, 1 )  # Precompute up to curvature 20, in a window extending +/- 0.5 horizontally, +/- 1 vertically around the origin
gaussian_circs_20 = filter_circles_circular( -1, gaussian_coords_20, 1, 20, 0, 1/2, 0.25 )  # ask for curvs 1 through 20, inside circle ctrd at (0,1/2) with radius 0.25
black_gaussian_doiley = circle_picture( gaussian_circs_20 )  # default style is for black circles
black_gaussian_doiley.show( axes=False )  # show with no axes
///
}}}

{{{id=67|
# To choose a colour palette, print out the available schemes of a certain size
colour_demo(4)
///
}}}

{{{id=55|
# By adding a few parameters, one can set colour behaviour, in this case modular based on curvature
coloured_gaussian_doiley = circle_picture( gaussian_circs_20, circle_colour_scheme=modular_colour, circle_colour_parameter_list = [colour_pool, [4, 1, 0]] )
coloured_gaussian_doiley.show( axes=False )
///
}}}

{{{id=54|
# One can use gradient-coloured disks instead of circles
# Warning, gradient disks look nicer with a high factor, but it takes a long time
gradient_gaussian_mandala = circle_picture( gaussian_circs_20, object_type="disk", disk_colour_scheme=gradient_disk, disk_colour_parameter_list = [ modular_colour, [colour_pool, [4, 1, 2]], modular_colour, [colour_pool, [4, 1, 1] ], 1000 ] )  # 1000 makes for a nice smooth gradient
gradient_gaussian_mandala.show( axes=False )
///
}}}

{{{id=49|
# Here's a circle-only snapshot of the Gaussian Schmidt arrangement, with circles fading (using a transparency_scheme)
root2val = n(sqrt(2))
gaussian_coords_40 = precompute_circles( -1, 40, 1, 1 )
gaussian_circs_rectangle = filter_circles_rectangular( -1, gaussian_coords_40, 0, 40, -0.1, 1.1, -0.1, 1+0.1 )
gaussian_napkin = circle_picture( gaussian_circs_rectangle, circle_colour_scheme=modular_colour, circle_colour_parameter_list=[colour_saul, [2, 1, 1]], circle_transparency_scheme=increasing_transparency, circle_transparency_parameter_list=[40,1], line_range=3, dis=-1)
gaussian_napkin.show(axes=False, xmin=0, xmax=1, ymin=-0, ymax=1)
///
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "_sage_input_7.py", line 10, in <module>
    exec compile(u'open("___code___.py","w").write("# -*- coding: utf-8 -*-\\n" + _support_.preparse_worksheet_cell(base64.b64decode("IyBIZXJlJ3MgYSBjaXJjbGUtb25seSBzbmFwc2hvdCBvZiB0aGUgR2F1c3NpYW4gU2NobWlkdCBhcnJhbmdlbWVudCwgd2l0aCBjaXJjbGVzIGZhZGluZyAodXNpbmcgYSB0cmFuc3BhcmVuY3lfc2NoZW1lKQpyb290MnZhbCA9IG4oc3FydCgyKSkKZ3Vhc3NpYW5fY29vcmRzXzQwID0gcHJlY29tcHV0ZV9jaXJjbGVzKCAtMSwgNDAsIDEsIDEgKQpnYXVzc2lhbl9jaXJjc19yZWN0YW5nbGUgPSBmaWx0ZXJfY2lyY2xlc19yZWN0YW5ndWxhciggLTEsIGdhdXNzaWFuX2Nvb3Jkc180MCwgMCwgNDAsIC0wLjEsIDEuMSwgLTAuMSwgMSswLjEgKQpnYXVzc2lhbl9uYXBraW4gPSBjaXJjbGVfcGljdHVyZSggZ2F1c3NpYW5fY2lyY3NfcmVjdGFuZ2xlLCBjaXJjbGVfY29sb3VyX3NjaGVtZT1tb2R1bGFyX2NvbG91ciwgY2lyY2xlX2NvbG91cl9wYXJhbWV0ZXJfbGlzdD1bY29sb3VyX3NhdWwsIFsyLCAxLCAxXV0sIGNpcmNsZV90cmFuc3BhcmVuY3lfc2NoZW1lPWluY3JlYXNpbmdfdHJhbnNwYXJlbmN5LCBjaXJjbGVfdHJhbnNwYXJlbmN5X3BhcmFtZXRlcl9saXN0PVs0MCwxXSwgbGluZV9yYW5nZT0zLCBkaXM9LTEpCmdhdXNzaWFuX25hcGtpbi5zaG93KGF4ZXM9RmFsc2UsIHhtaW49MCwgeG1heD0xLCB5bWluPS0wLCB5bWF4PTEp"),globals())+"\\n"); execfile(os.path.abspath("___code___.py"))' + '\n', '', 'single')
  File "", line 1, in <module>
    
  File "/tmp/tmpZ02LP_/___code___.py", line 5, in <module>
    gaussian_circs_rectangle = filter_circles_rectangular( -_sage_const_1 , gaussian_coords_40, _sage_const_0 , _sage_const_40 , -_sage_const_0p1 , _sage_const_1p1 , -_sage_const_0p1 , _sage_const_1 +_sage_const_0p1  )
NameError: name 'gaussian_coords_40' is not defined
}}}

{{{id=23|
# Squareroot(-2) example, showing a rectangular region (fundamental region) of disks
# Colour is curvature mod 2
# Circles fade as radius grows (increasing_transparency)
# For lines, increase line_range until all the lines needed appear in picture; if line_range is used, dis must be set to the discriminant
root2val = n(sqrt(2))
root2_coords_40 = precompute_circles( -2, 40, 1, 1 )
root2_circs_rectangular = filter_circles_rectangular( -2, root2_coords_40, 0, 40, -0.1, 1.1, -0.1, root2val+0.1 )
root2_napkin = circle_picture( root2_circs_rectangular, circle_colour_scheme=modular_colour, circle_colour_parameter_list=[colour_saul, [2, 1, 1]], circle_transparency_scheme=increasing_transparency, circle_transparency_parameter_list=[40,1], line_range=3, dis=-2)
root2_napkin.show(axes=False, xmin=0, xmax=1, ymin=-0, ymax=root2val)
///
}}}

{{{id=31|
# Squareroot(-3) example
# figsize is used to increase the image size
root3val = n(sqrt(3))
eisenstein_coords_10 = precompute_circles( -3, 10, 2, 2 )
eisenstein_circs_strip = filter_circles_rectangular( -3, eisenstein_coords_10, 0, 10, -2.1, 2.1, -root3val-0.1, 2*root3val+0.1 ) # artificially a bit big to capture edges of outside circles
eisenstein_border = circle_picture( eisenstein_circs_strip, circle_colour_scheme=modular_colour, circle_colour_parameter_list=[colour_saul, [2, 1, 1]], circle_transparency_scheme=increasing_transparency, circle_transparency_parameter_list=[10,1], line_range=10, dis=-3)
eisenstein_border.show(axes=False, xmin=-2, xmax=2, ymin=-0, ymax=root3val, figsize = 15)
///
}}}

{{{id=44|
# Squareroot(-15) example, showing a rectangular region (fundamental region) of disks
# This takes a little while
root15val = n(sqrt(15))
root15_coords_20 = precompute_circles( -15, 20, 10, 2 )
root15_circs_rectangular = filter_circles_rectangular( -15, root15_coords_20, 0, 20, -0.1, 5.1, -0.1, root15val+0.1 )
root15_trim = circle_picture( root15_circs_rectangular, object_type="disk", disk_colour_scheme=modular_colour, disk_colour_parameter_list=[colour_saul, [4, 1, 0]], line_range=10, dis=-15 )
root15_trim.show(axes=False, xmin=0, xmax=5, ymin=-0, ymax=root15val/2)
///
}}}

{{{id=50|
# Gaussian Apollonian packing precomputation.  This takes a minute or two to get up to curvature 100
gaussian_coords_100 = precompute_circles( -1, 100, 1, 1 )
///
}}}

{{{id=57|
# Having accomplished precomputing the coordinates, here are the filtered circles; also takes a minute
gaussian_circs_100 = filter_circles_circular( -1, gaussian_coords_100, 2, 100, 0, 1/2, 0.25 )
# This is a version which throws away all circles contained in other circles; useful for Apollonian packings
gaussian_circs_100_filtered_down = filter_circles_circular( -1, gaussian_coords_100, 2, 100, 0, 1/2, 0.25, filter_down=True )
///
}}}

{{{id=26|
# Gaussian Apollonian packing example, using the filtered_down set of circles
# Here you really need to use the lower bound to avoid the outer circle appearing
apollonian_24 = circle_picture( gaussian_circs_100_filtered_down, object_type="disk", disk_colour_scheme=modular_colour, disk_colour_parameter_list=[colour_24, [24, 1, 4]], disk_transparency_parameter_list=[1] )
apollonian_24.show(axes=False)
///
}}}

{{{id=56|
# Same example using the set of circles not filtered down
gaussian_24_pointillism = circle_picture( gaussian_circs_100, sort_up=True, object_type="disk", disk_colour_scheme=modular_colour, disk_colour_parameter_list=[colour_24, [24, 1, 4]], disk_transparency_parameter_list=[1] )
gaussian_24_pointillism.show(axes=False)
///
}}}

{{{id=28|
# Gaussian Apollonian packing example, using the disk overlay method with a constant=1/2 transparency, modulus=1 for constant colour
# This relies on the previous cell for the initial computations of coords and circs
apollonian_yellow = circle_picture( gaussian_circs_100, object_type="disk", disk_colour_scheme=modular_colour, disk_colour_parameter_list=[colour_92, [1, 0, 0]], disk_transparency_scheme=constant_transparency, disk_transparency_parameter_list=[1/2] )
apollonian_yellow.show(axes=False)
///
}}}

{{{id=30|
# Gaussian Apollonian packing example, showing prime curvatures 
# This relies on the previous cell for the initial computations of coords and circs
gaussian_primes = circle_picture( gaussian_circs_100, object_type="disk", disk_colour_scheme=prime_colour, disk_colour_parameter_list=[colour_a] )
gaussian_primes.show(axes=False)
///
}}}

{{{id=27|
# Gaussian Apollonian packing example, using the disk overlay method with a increasing transparency (smaller disks are more transparent)
# This relies on previous cells for the initial computations of coords
gaussian_circs_75 = filter_circles_circular( -1, gaussian_coords_100, 0, 75, 0, 1/2, 0.25 )
transparency_disks = circle_picture( gaussian_circs_75, object_type="disk", disk_colour_scheme=modular_colour, disk_colour_parameter_list=[colour_5, [5, 1, 0]], disk_transparency_scheme=increasing_transparency, disk_transparency_parameter_list=[75/0.7,0.7] )  
transparency_disks.show(axes=False)
///
}}}

{{{id=21|
# Gaussian example, showing interior of one circle of the Schmidt arrangement.
gaussian_circs_35 = filter_circles_circular( -1, gaussian_coords_100, 0, 35, 0, 1/2, 0.25 )
gaussian_glowing_black = circle_picture( gaussian_circs_35, sort_up=False, object_type="combo", circle_colour_scheme=modular_colour, circle_colour_parameter_list=[colour_nightlife, [4,2,0]], circle_transparency_scheme=constant_transparency, circle_transparency_parameter_list=[0.25], disk_transparency_scheme=constant_transparency, disk_transparency_parameter_list=[1/2], disk_colour_scheme=modular_colour, disk_colour_parameter_list=[ ["black"], [1,0,0] ], circle_thickness=1.5 )
gaussian_glowing_black.show(axes=False,xmin=-1/2,xmax=1/2,ymin=0,ymax=1)
///
}}}

{{{id=40|
# CU Colours used for CU Mathematics Lab Logo
gaussian_circs_100 = filter_circles_circular( -1, gaussian_coords_100, 2, 100, 0, 1/2, 0.25 )
gaussian_cu = disk( (0,1/2), 1/2, (0,2*pi), color="black" )  # manually adding a black disk background
gaussian_cu += circle_picture( gaussian_circs_100, sort_up=False, object_type="disk", disk_colour_parameter_list=[colour_cu, [1,1,0]], disk_transparency_parameter_list=[1/2] )
gaussian_cu.show(axes=False,xmin=-1/2,xmax=1/2,ymin=0,ymax=1)
///
}}}