*subtends* the angle $\theta$ in a circle of radius $r$.

In this case, the sides of the polygon must subtend a total angle of measure $2\pi$. This yields an equation that the side lengths $x_1,x_2,\ldots,x_n$ and the radius $r$ must satisfy: $$\sum_k \arccos\left(\frac{2r^2-x_k^2}{2r^2}\right) = 2\pi.$$ As the $x_ks$ are specified, we can find the value of $r$ that works, if there is one.

In code, we're looking for a root of the function `s(r)`

below. Note that `s`

is generally decreasing, so if `s(max(side_lengths)/2)`

is negative, there's no point in trying.

In [1]:

```
import numpy as np
side_lengths = [6,3,3,2,3,4,3]
def x(k): return side_lengths[k]
def theta(r,k): return np.arccos((2*r**2 - x(k)**2)/(2*r**2))
def s(r): return sum([theta(r,k) for k in range(len(side_lengths))]) - 2*np.pi
s(max(side_lengths)/2)
```

Out[1]:

Let's make a simple plot of $s$ to find an interval to pass to numerical rootfinder `brentq`

.

In [2]:

```
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
x_pts = []
y_pts = []
for r in np.linspace(max(side_lengths)/2,max(side_lengths),20):
try:
y = s(r)
y = float(y)
x_pts.append(r)
y_pts.append(y)
except:
pass
plt.plot(x_pts,y_pts)
```

Out[2]:

Looks like there's a root between 3.5 and 6.

In [3]:

```
from scipy.optimize import brentq
r_crit = brentq(s,3.5,6)
r_crit
```

Out[3]:

Let's build the circle!

In [4]:

```
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Circle
r = r_crit
th = 0
xs = [0]
ys = [-r]
for k in range(len(side_lengths)):
th = th + theta(r,k)
ys.append(-r*np.cos(th))
xs.append(r*np.sin(th))
plt.plot(xs,ys, linewidth=1.5, color='black')
plt.plot(xs,ys, 'o', color='black')
ax = plt.gca()
ax.add_patch(Circle((0,0),r, fill=None, alpha=0.5))
ax.set_aspect(1)
ax.set_xlim((-1.1*r,1.1*r))
ax.set_ylim((-1.1*r,1.1*r))
fig = plt.gcf()
fig.set_figwidth(8)
fig.set_figheight(8)
plt.show()
```

This case relies on similar ideas, but the total angle subtended need not be $2\pi$. However, the angle subtended by the greatest side length must be the same as the angle subtended by the remaining sidelengths, as you'll see in the picture we generate soon.

Note that the code below assumes that the largest number occurs *first* in the list of side lengths.

In [5]:

```
import numpy as np
side_lengths = [8,3,3,2,1]
def x(k): return side_lengths[k]
def theta(r,k): return np.arccos((2*r**2 - x(k)**2)/(2*r**2))
def s(r): return sum([theta(r,k) for k in range(1,len(side_lengths))]) - theta(r,0)
s(max(side_lengths)/2)
```

Out[5]:

Again, a plot should help us locate a root.

In [6]:

```
x_pts = []
y_pts = []
for r in np.linspace(max(side_lengths)/2,2*max(side_lengths),20):
try:
y = s(r)
y = float(y)
x_pts.append(r)
y_pts.append(y)
except:
pass
plt.plot(x_pts,y_pts)
plt.plot([x_pts[0],x_pts[len(x_pts)-1]],[0,0])
```

Out[6]:

Looks like it's around 5 - certainly in $[4.5,10]$.

In [7]:

```
from scipy.optimize import brentq
r_crit = brentq(s,4.5,10)
r_crit
```

Out[7]:

Finally, we enjoy an illustration.

In [8]:

```
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Circle
r = r_crit
th = 0
xs = [0]
ys = [-r]
for k in range(len(side_lengths)):
if k == 0:
th = th + theta(r,k)
else:
th = th - theta(r,k)
ys.append(-r*np.cos(th))
xs.append(r*np.sin(th))
plt.plot(xs,ys, linewidth=1.5, color='black')
plt.plot(xs,ys, 'o', color='black')
ax = plt.gca()
ax.add_patch(Circle((0,0),r, fill=None, alpha=0.5))
ax.set_aspect(1)
ax.set_xlim((-1.1*r,1.1*r))
ax.set_ylim((-1.1*r,1.1*r))
fig = plt.gcf()
fig.set_figwidth(8)
fig.set_figheight(8)
plt.show()
```

The ideas above are largely applicable to polygons with infinitely many sides. The main computational complication is that need a way to approximate an infinite sum, as well as a numerical root finder. There is exactly such a tool in sympy's mpmath package.

Let's try it with the series $$\sum_{n=1}^{\infty} \left(\frac{3}{4}\right)^n.$$

In [9]:

```
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import sympy.mpmath as mp
def x(k): return 0.75**k
def theta(r,k): return mp.acos((2*r**2 - x(k)**2)/(2*r**2))
def s(r): return mp.sumap(lambda k: theta(r,k), [1,mp.inf]) - 2*mp.pi
x_pts = []
y_pts = []
for r in np.linspace(0,2,20):
try:
y = s(r)
y = float(y)
x_pts.append(r)
y_pts.append(y)
except:
pass
plt.plot(x_pts,y_pts)
```

Out[9]:

Looks like there's a root around $0.5$ - let's find it!

In [10]:

```
from scipy.optimize import brentq
r_crit = brentq(s,0.4,1)
r_crit
```

Out[10]:

Again, we'll plot the result.

In [11]:

```
from matplotlib.patches import Circle
r = r_crit
xs = [0]
ys = [-r]
th = 0
for k in range(1,50):
th1 = th
th = th + theta(r,k)
ys.append(-r*mp.cos(th))
xs.append(r*mp.sin(th))
plt.plot(xs,ys, linewidth=1.5, color='black')
plt.plot(xs,ys, 'o', color='black')
ax = plt.gca()
ax.add_patch(Circle((0,0),r, fill=None, alpha=0.5))
ax.set_aspect(1)
ax.set_xlim((-1.1*r,1.1*r))
ax.set_ylim((-1.1*r,1.1*r))
ax.axis('off');
fig = plt.gcf()
fig.set_frameon(False)
fig.set_figwidth(8)
fig.set_figheight(8)
```