This notebook performs a few analytical integrations in order to have functions to compare against for testing purposes with the numerical integration.

```python
from sage.all import *
import pickle

sx, sy = var('sx, sy')

ox, oy = var('ox, oy')

dx = ox - sx
dy = oy - sy
r2 = (dx ** 2) + (dy ** 2)

r = sqrt(r2)
G = (1 / (2 * pi)) * log(r)
```

Because we're integrating over a 2D domain, we need to integrate first over `sx`, then over `sy`. The first integral over `sx` can be done without many assumptions.

```python
forget()
# assume that the solution is not singular. this assumption isn't strictly
# correct, but it convinces sage to do the integration.
assume(sy-oy>0)

# these two assumptions are also not correct in light of the later integration
# of sy from -1 to 1. however, the integral will be the same regardless of which
# subdomain we specify. so, this is essentially a hack to convince sage to
# compute the integral for us.
assume(sy > 0)
assume(sy < 1)
Ia = integral(G, sx, -1, 1)
```

The second integral requires assuming a location for the observation point. First, we assume a point inside the domain of integration.

```python
assume(ox > -1)
assume(ox < 1)
assume(oy > -1)
coincident = integral(Ia, sy, -1, 1)
```

Below, we assume `ox > 1` and `oy > 1`. This would imply that the observation point is outside the domain of integration to the upper right.

```python
forget()
assume(ox > 1)
assume(oy > 1)
nearfield = integral(Ia, sy, -1, 1)
```

```python
import sympy
sympy.__version__
```

    '1.9'

```python
import pickle
with open('data/constant_test_integral.pkl', 'wb') as f:
    pickle.dump([coincident._sympy_(), nearfield._sympy_()], f)
```

```python
forget()
assume(sy-oy>0)
assume(sy > 0)
assume(sy < 1)
Ia = integral(G * (1 - (1 - sx) ** 3) * (1 - (sy + 1) ** 2), sx, -1, 1)
```

```python
assume(ox > -1)
assume(ox < 1)
assume(oy > -1)
coincident = integral(Ia, sy, -1, 1)
```

```python
forget()
assume(ox > 1)
assume(oy > 1)
nearfield = integral(Ia, sy, -1, 1)
```

```python
import pickle
with open('data/xy_test_integral.pkl', 'wb') as f:
    pickle.dump([coincident._sympy_(), nearfield._sympy_()], f)
```

```python
for integrand, name in [(G, 'constant'), (G * (1 - sx) * (1 - sy ** 2), 'xy')]:

    transformed_nearfield = []
    for mult in [1, 2, 4, 8, 16]:
        forget()
        src_c = [0, 0]
        src_half_size = mult / 8
        assume(sy-oy > 0)
        Ia = integral(integrand, sx, src_c[0] - src_half_size, src_c[0] + src_half_size)
        assume(ox - (src_c[0] + src_half_size) > 0)
        assume(oy - (src_c[1] + src_half_size) > 0)

        transformed_nearfield.append(integral(Ia, sy, src_c[1] - src_half_size, src_c[1] + src_half_size))

    import pickle
    with open(f'data/{name}_transformed_test_integral.pkl', 'wb') as f:
        pickle.dump([I._sympy_() for I in transformed_nearfield], f)
```

```python
N = 7
chebyshev_pts = [cos(pi * i / (N - 1)) for i in range(N)][::-1]
x = var("x")
```

```python
basis_functions = []
for i in range(N):
    xi = chebyshev_pts[i]
    prod = 1
    # The definition of the Lagrange interpolating polynomial.
    # In a numerical context, this definition is troublesome
    # and it's better to use the barycentric Lagrange formulas.
    # But this simple definition works fantastically well in
    # a symbolic setting.
    for j in range(N):
        if j == i:
            continue
        xj = chebyshev_pts[j]
        prod *= (x - xj) / (xi - xj)
    basis_functions.append(prod.simplify().expand())
```

```python
basis_functions
```

    [-8/3*x^6/((sqrt(3) + 2)*(sqrt(3) - 2)) + 8/3*x^5/((sqrt(3) + 2)*(sqrt(3) - 2)) + 8/3*x^4/((sqrt(3) + 2)*(sqrt(3) - 2)) - 8/3*x^3/((sqrt(3) + 2)*(sqrt(3) - 2)) - 1/2*x^2/((sqrt(3) + 2)*(sqrt(3) - 2)) + 1/2*x/((sqrt(3) + 2)*(sqrt(3) - 2)),
     32/3*x^6/((sqrt(3) + 2)*(sqrt(3) + 1)*(sqrt(3) - 1)*(sqrt(3) - 2)) - 16/3*sqrt(3)*x^5/((sqrt(3) + 2)*(sqrt(3) + 1)*(sqrt(3) - 1)*(sqrt(3) - 2)) - 40/3*x^4/((sqrt(3) + 2)*(sqrt(3) + 1)*(sqrt(3) - 1)*(sqrt(3) - 2)) + 20/3*sqrt(3)*x^3/((sqrt(3) + 2)*(sqrt(3) + 1)*(sqrt(3) - 1)*(sqrt(3) - 2)) + 8/3*x^2/((sqrt(3) + 2)*(sqrt(3) + 1)*(sqrt(3) - 1)*(sqrt(3) - 2)) - 4/3*sqrt(3)*x/((sqrt(3) + 2)*(sqrt(3) + 1)*(sqrt(3) - 1)*(sqrt(3) - 2)),
     32/3*x^6/((sqrt(3) + 1)*(sqrt(3) - 1)) - 16/3*x^5/((sqrt(3) + 1)*(sqrt(3) - 1)) - 56/3*x^4/((sqrt(3) + 1)*(sqrt(3) - 1)) + 28/3*x^3/((sqrt(3) + 1)*(sqrt(3) - 1)) + 8*x^2/((sqrt(3) + 1)*(sqrt(3) - 1)) - 4*x/((sqrt(3) + 1)*(sqrt(3) - 1)),
     -16/3*x^6 + 32/3*x^4 - 19/3*x^2 + 1,
     32/3*x^6/((sqrt(3) + 1)*(sqrt(3) - 1)) + 16/3*x^5/((sqrt(3) + 1)*(sqrt(3) - 1)) - 56/3*x^4/((sqrt(3) + 1)*(sqrt(3) - 1)) - 28/3*x^3/((sqrt(3) + 1)*(sqrt(3) - 1)) + 8*x^2/((sqrt(3) + 1)*(sqrt(3) - 1)) + 4*x/((sqrt(3) + 1)*(sqrt(3) - 1)),
     32/3*x^6/((sqrt(3) + 2)*(sqrt(3) + 1)*(sqrt(3) - 1)*(sqrt(3) - 2)) + 16/3*sqrt(3)*x^5/((sqrt(3) + 2)*(sqrt(3) + 1)*(sqrt(3) - 1)*(sqrt(3) - 2)) - 40/3*x^4/((sqrt(3) + 2)*(sqrt(3) + 1)*(sqrt(3) - 1)*(sqrt(3) - 2)) - 20/3*sqrt(3)*x^3/((sqrt(3) + 2)*(sqrt(3) + 1)*(sqrt(3) - 1)*(sqrt(3) - 2)) + 8/3*x^2/((sqrt(3) + 2)*(sqrt(3) + 1)*(sqrt(3) - 1)*(sqrt(3) - 2)) + 4/3*sqrt(3)*x/((sqrt(3) + 2)*(sqrt(3) + 1)*(sqrt(3) - 1)*(sqrt(3) - 2)),
     -8/3*x^6/((sqrt(3) + 2)*(sqrt(3) - 2)) - 8/3*x^5/((sqrt(3) + 2)*(sqrt(3) - 2)) + 8/3*x^4/((sqrt(3) + 2)*(sqrt(3) - 2)) + 8/3*x^3/((sqrt(3) + 2)*(sqrt(3) - 2)) - 1/2*x^2/((sqrt(3) + 2)*(sqrt(3) - 2)) - 1/2*x/((sqrt(3) + 2)*(sqrt(3) - 2))]

```python
Kb = (basis_functions[0].subs(x==sx) * basis_functions[1].subs(x == sy)).full_simplify() * G
```

```python
Isx = integral(Kb, sx, -1, 1)
```

```python
Isx_simp = Isx.full_simplify()
```

    1/793800*(806400*(12*oy + sqrt(3))*sy^11 - 1612800*sy^12 + 26880*(900*ox^2 - 900*oy^2 - 180*sqrt(3)*oy - 350*ox + 11)*sy^10 + 13440*(2400*oy^3 - 900*sqrt(3)*ox^2 + 900*sqrt(3)*oy^2 - 4*(1800*ox^2 - 700*ox + 97)*oy + 350*sqrt(3)*ox - 11*sqrt(3))*sy^9 - 6720*(3600*ox^4 + 3600*oy^4 + 2400*sqrt(3)*oy^3 - 2800*ox^3 - 12*(1800*ox^2 - 700*ox + 247)*oy^2 + 2964*ox^2 - 4*(1800*sqrt(3)*ox^2 - 700*sqrt(3)*ox + 97*sqrt(3))*oy - 770*ox - 219)*sy^8 + 3360*(2880*oy^5 + 3600*sqrt(3)*ox^4 + 3600*sqrt(3)*oy^4 - 32*(900*ox^2 - 350*ox + 311)*oy^3 - 2800*sqrt(3)*ox^3 - 12*(1800*sqrt(3)*ox^2 - 700*sqrt(3)*ox + 247*sqrt(3))*oy^2 + 2964*sqrt(3)*ox^2 + 4*(3600*ox^4 - 2800*ox^3 + 7464*ox^2 - 2520*ox - 419)*oy - 770*sqrt(3)*ox - 219*sqrt(3))*sy^7 + 16*(100800*ox^6 - 100800*oy^6 - 302400*sqrt(3)*oy^5 - 117600*ox^5 + 1680*(900*ox^2 - 350*ox + 1061)*oy^4 + 1782480*ox^4 + 3360*(900*sqrt(3)*ox^2 - 350*sqrt(3)*ox + 311*sqrt(3))*oy^3 - 1332800*ox^3 - 420*(3600*ox^4 - 2800*ox^3 + 25464*ox^2 - 9520*ox - 979)*oy^2 - 411180*ox^2 - 420*(3600*sqrt(3)*ox^4 - 2800*sqrt(3)*ox^3 + 7464*sqrt(3)*ox^2 - 2520*sqrt(3)*ox - 419*sqrt(3))*oy + 336630*ox - 4479)*sy^6 - 8*(100800*sqrt(3)*ox^6 - 100800*sqrt(3)*oy^6 - 117600*sqrt(3)*ox^5 + 1680*(900*sqrt(3)*ox^2 - 350*sqrt(3)*ox + 1061*sqrt(3))*oy^4 + 1512000*oy^5 + 1782480*sqrt(3)*ox^4 - 33600*(450*ox^2 - 175*ox - 2)*oy^3 - 1332800*sqrt(3)*ox^3 - 420*(3600*sqrt(3)*ox^4 - 2800*sqrt(3)*ox^3 + 25464*sqrt(3)*ox^2 - 9520*sqrt(3)*ox - 979*sqrt(3))*oy^2 - 411180*sqrt(3)*ox^2 + 420*(18000*ox^4 - 14000*ox^3 - 480*ox^2 + 2100*ox - 307)*oy + 336630*sqrt(3)*ox - 4479*sqrt(3))*sy^5 - 40*(50400*ox^6 - 50400*oy^6 - 151200*sqrt(3)*oy^5 - 58800*ox^5 + 1680*(450*ox^2 - 175*ox + 58)*oy^4 + 97440*ox^4 + 3360*(450*sqrt(3)*ox^2 - 175*sqrt(3)*ox - 2*sqrt(3))*oy^3 - 49000*ox^3 - 42*(18000*ox^4 - 14000*ox^3 + 13920*ox^2 - 3500*ox - 1331)*oy^2 - 55902*ox^2 - 42*(18000*sqrt(3)*ox^4 - 14000*sqrt(3)*ox^3 - 480*sqrt(3)*ox^2 + 2100*sqrt(3)*ox - 307*sqrt(3))*oy + 25725*ox + 2160)*sy^4 + 20*(50400*sqrt(3)*ox^6 - 50400*sqrt(3)*oy^6 - 58800*sqrt(3)*ox^5 + 1680*(450*sqrt(3)*ox^2 - 175*sqrt(3)*ox + 58*sqrt(3))*oy^4 + 120960*oy^5 + 97440*sqrt(3)*ox^4 - 2688*(450*ox^2 - 175*ox - 32)*oy^3 - 49000*sqrt(3)*ox^3 - 42*(18000*sqrt(3)*ox^4 - 14000*sqrt(3)*ox^3 + 13920*sqrt(3)*ox^2 - 3500*sqrt(3)*ox - 1331*sqrt(3))*oy^2 - 55902*sqrt(3)*ox^2 + 168*(3600*ox^4 - 2800*ox^3 - 1536*ox^2 + 980*ox + 41)*oy + 25725*sqrt(3)*ox + 2160*sqrt(3))*sy^3 + 8*(50400*ox^6 - 50400*oy^6 - 151200*sqrt(3)*oy^5 - 58800*ox^5 + 1680*(450*ox^2 - 175*ox - 32)*oy^4 - 53760*ox^4 + 3360*(450*sqrt(3)*ox^2 - 175*sqrt(3)*ox - 32*sqrt(3))*oy^3 + 68600*ox^3 - 210*(3600*ox^4 - 2800*ox^3 - 1536*ox^2 + 980*ox + 41)*oy^2 + 8610*ox^2 - 210*(3600*sqrt(3)*ox^4 - 2800*sqrt(3)*ox^3 - 1536*sqrt(3)*ox^2 + 980*sqrt(3)*ox + 41*sqrt(3))*oy - 15435*ox + 438)*sy^2 - 4*(50400*sqrt(3)*ox^6 - 50400*sqrt(3)*oy^6 - 58800*sqrt(3)*ox^5 + 1680*(450*sqrt(3)*ox^2 - 175*sqrt(3)*ox - 32*sqrt(3))*oy^4 - 53760*sqrt(3)*ox^4 + 68600*sqrt(3)*ox^3 - 210*(3600*sqrt(3)*ox^4 - 2800*sqrt(3)*ox^3 - 1536*sqrt(3)*ox^2 + 980*sqrt(3)*ox + 41*sqrt(3))*oy^2 + 8610*sqrt(3)*ox^2 - 15435*sqrt(3)*ox + 438*sqrt(3))*sy + 420*(960*(14*oy + sqrt(3))*sy^12 - 1920*sy^13 + 96*(420*ox^2 - 420*oy^2 - 70*sqrt(3)*oy - 140*ox - 3)*sy^11 + 48*(1400*oy^3 - 420*sqrt(3)*ox^2 + 420*sqrt(3)*oy^2 - 70*(60*ox^2 - 20*ox + 1)*oy + 140*sqrt(3)*ox + 3*sqrt(3))*sy^10 - 40*(1680*ox^4 + 1680*oy^4 + 840*sqrt(3)*oy^3 - 1120*ox^3 - 84*(120*ox^2 - 40*ox + 7)*oy^2 + 588*ox^2 - 42*(60*sqrt(3)*ox^2 - 20*sqrt(3)*ox + sqrt(3))*oy - 84*ox - 51)*sy^9 + 20*(2016*oy^5 + 1680*sqrt(3)*ox^4 + 1680*sqrt(3)*oy^4 - 168*(120*ox^2 - 40*ox + 17)*oy^3 - 1120*sqrt(3)*ox^3 - 84*(120*sqrt(3)*ox^2 - 40*sqrt(3)*ox + 7*sqrt(3))*oy^2 + 588*sqrt(3)*ox^2 + 42*(240*ox^4 - 160*ox^3 + 204*ox^2 - 52*ox - 13)*oy - 84*sqrt(3)*ox - 51*sqrt(3))*sy^8 + 14*(960*ox^6 - 960*oy^6 - 1440*sqrt(3)*oy^5 - 960*ox^5 + 240*(60*ox^2 - 20*ox + 21)*oy^4 + 5040*ox^4 + 120*(120*sqrt(3)*ox^2 - 40*sqrt(3)*ox + 17*sqrt(3))*oy^3 - 3040*ox^3 - 60*(240*ox^4 - 160*ox^3 + 504*ox^2 - 152*ox - 25)*oy^2 - 1500*ox^2 - 30*(240*sqrt(3)*ox^4 - 160*sqrt(3)*ox^3 + 204*sqrt(3)*ox^2 - 52*sqrt(3)*ox - 13*sqrt(3))*oy + 780*ox + 27)*sy^7 + (1920*oy^7 - 6720*sqrt(3)*ox^6 + 6720*sqrt(3)*oy^6 - 672*(60*ox^2 - 20*ox + 71)*oy^5 + 6720*sqrt(3)*ox^5 - 1680*(60*sqrt(3)*ox^2 - 20*sqrt(3)*ox + 21*sqrt(3))*oy^4 - 35280*sqrt(3)*ox^4 + 280*(240*ox^4 - 160*ox^3 + 1704*ox^2 - 552*ox - 57)*oy^3 + 21280*sqrt(3)*ox^3 + 420*(240*sqrt(3)*ox^4 - 160*sqrt(3)*ox^3 + 504*sqrt(3)*ox^2 - 152*sqrt(3)*ox - 25*sqrt(3))*oy^2 + 10500*sqrt(3)*ox^2 - 210*(64*ox^6 - 64*ox^5 + 1136*ox^4 - 736*ox^3 - 228*ox^2 + 148*ox - 1)*oy - 5460*sqrt(3)*ox - 189*sqrt(3))*sy^6 - (960*sqrt(3)*oy^7 + 16800*ox^6 - 336*(60*sqrt(3)*ox^2 - 20*sqrt(3)*ox + 71*sqrt(3))*oy^5 - 16800*oy^6 - 16800*ox^5 + 84000*(3*ox^2 - ox)*oy^4 + 140*(240*sqrt(3)*ox^4 - 160*sqrt(3)*ox^3 + 1704*sqrt(3)*ox^2 - 552*sqrt(3)*ox - 57*sqrt(3))*oy^3 + 5600*ox^3 - 210*(1200*ox^4 - 800*ox^3 + 80*ox - 17)*oy^2 - 3570*ox^2 - 105*(64*sqrt(3)*ox^6 - 64*sqrt(3)*ox^5 + 1136*sqrt(3)*ox^4 - 736*sqrt(3)*ox^3 - 228*sqrt(3)*ox^2 + 148*sqrt(3)*ox - sqrt(3))*oy + 210*ox + 210)*sy^5 - 5*(480*oy^7 - 1680*sqrt(3)*ox^6 + 1680*sqrt(3)*oy^6 - 672*(15*ox^2 - 5*ox + 2)*oy^5 + 1680*sqrt(3)*ox^5 - 8400*(3*sqrt(3)*ox^2 - sqrt(3)*ox)*oy^4 + 14*(1200*ox^4 - 800*ox^3 + 960*ox^2 - 240*ox - 81)*oy^3 - 560*sqrt(3)*ox^3 + 21*(1200*sqrt(3)*ox^4 - 800*sqrt(3)*ox^3 + 80*sqrt(3)*ox - 17*sqrt(3))*oy^2 + 357*sqrt(3)*ox^2 - 42*(80*ox^6 - 80*ox^5 + 160*ox^4 - 80*ox^3 - 81*ox^2 + 33*ox + 3)*oy - 21*sqrt(3)*ox - 21*sqrt(3))*sy^4 + 5*(240*sqrt(3)*oy^7 + 672*ox^6 - 336*(15*sqrt(3)*ox^2 - 5*sqrt(3)*ox + 2*sqrt(3))*oy^5 - 672*oy^6 - 672*ox^5 + 672*(15*ox^2 - 5*ox - 1)*oy^4 - 672*ox^4 + 7*(1200*sqrt(3)*ox^4 - 800*sqrt(3)*ox^3 + 960*sqrt(3)*ox^2 - 240*sqrt(3)*ox - 81*sqrt(3))*oy^3 + 672*ox^3 - 42*(240*ox^4 - 160*ox^3 - 96*ox^2 + 48*ox + 3)*oy^2 + 126*ox^2 - 21*(80*sqrt(3)*ox^6 - 80*sqrt(3)*ox^5 + 160*sqrt(3)*ox^4 - 80*sqrt(3)*ox^3 - 81*sqrt(3)*ox^2 + 33*sqrt(3)*ox + 3*sqrt(3))*oy - 126*ox)*sy^3 + (480*oy^7 - 1680*sqrt(3)*ox^6 + 1680*sqrt(3)*oy^6 - 672*(15*ox^2 - 5*ox - 1)*oy^5 + 1680*sqrt(3)*ox^5 - 1680*(15*sqrt(3)*ox^2 - 5*sqrt(3)*ox - sqrt(3))*oy^4 + 1680*sqrt(3)*ox^4 + 70*(240*ox^4 - 160*ox^3 - 96*ox^2 + 48*ox + 3)*oy^3 - 1680*sqrt(3)*ox^3 + 105*(240*sqrt(3)*ox^4 - 160*sqrt(3)*ox^3 - 96*sqrt(3)*ox^2 + 48*sqrt(3)*ox + 3*sqrt(3))*oy^2 - 315*sqrt(3)*ox^2 - 210*(16*ox^6 - 16*ox^5 - 16*ox^4 + 16*ox^3 + 3*ox^2 - 3*ox)*oy + 315*sqrt(3)*ox)*sy^2 - (240*sqrt(3)*oy^7 - 336*(15*sqrt(3)*ox^2 - 5*sqrt(3)*ox - sqrt(3))*oy^5 + 35*(240*sqrt(3)*ox^4 - 160*sqrt(3)*ox^3 - 96*sqrt(3)*ox^2 + 48*sqrt(3)*ox + 3*sqrt(3))*oy^3 - 105*(16*sqrt(3)*ox^6 - 16*sqrt(3)*ox^5 - 16*sqrt(3)*ox^4 + 16*sqrt(3)*ox^3 + 3*sqrt(3)*ox^2 - 3*sqrt(3)*ox)*oy)*sy)*arctan((ox + 1)/(oy - sy)) - 420*(960*(14*oy + sqrt(3))*sy^12 - 1920*sy^13 + 96*(420*ox^2 - 420*oy^2 - 70*sqrt(3)*oy - 140*ox - 3)*sy^11 + 48*(1400*oy^3 - 420*sqrt(3)*ox^2 + 420*sqrt(3)*oy^2 - 70*(60*ox^2 - 20*ox + 1)*oy + 140*sqrt(3)*ox + 3*sqrt(3))*sy^10 - 40*(1680*ox^4 + 1680*oy^4 + 840*sqrt(3)*oy^3 - 1120*ox^3 - 84*(120*ox^2 - 40*ox + 7)*oy^2 + 588*ox^2 - 42*(60*sqrt(3)*ox^2 - 20*sqrt(3)*ox + sqrt(3))*oy - 84*ox - 51)*sy^9 + 20*(2016*oy^5 + 1680*sqrt(3)*ox^4 + 1680*sqrt(3)*oy^4 - 168*(120*ox^2 - 40*ox + 17)*oy^3 - 1120*sqrt(3)*ox^3 - 84*(120*sqrt(3)*ox^2 - 40*sqrt(3)*ox + 7*sqrt(3))*oy^2 + 588*sqrt(3)*ox^2 + 42*(240*ox^4 - 160*ox^3 + 204*ox^2 - 52*ox - 13)*oy - 84*sqrt(3)*ox - 51*sqrt(3))*sy^8 + 14*(960*ox^6 - 960*oy^6 - 1440*sqrt(3)*oy^5 - 960*ox^5 + 240*(60*ox^2 - 20*ox + 21)*oy^4 + 5040*ox^4 + 120*(120*sqrt(3)*ox^2 - 40*sqrt(3)*ox + 17*sqrt(3))*oy^3 - 3040*ox^3 - 60*(240*ox^4 - 160*ox^3 + 504*ox^2 - 152*ox - 25)*oy^2 - 1500*ox^2 - 30*(240*sqrt(3)*ox^4 - 160*sqrt(3)*ox^3 + 204*sqrt(3)*ox^2 - 52*sqrt(3)*ox - 13*sqrt(3))*oy + 780*ox + 27)*sy^7 + (1920*oy^7 - 6720*sqrt(3)*ox^6 + 6720*sqrt(3)*oy^6 - 672*(60*ox^2 - 20*ox + 71)*oy^5 + 6720*sqrt(3)*ox^5 - 1680*(60*sqrt(3)*ox^2 - 20*sqrt(3)*ox + 21*sqrt(3))*oy^4 - 35280*sqrt(3)*ox^4 + 280*(240*ox^4 - 160*ox^3 + 1704*ox^2 - 552*ox - 57)*oy^3 + 21280*sqrt(3)*ox^3 + 420*(240*sqrt(3)*ox^4 - 160*sqrt(3)*ox^3 + 504*sqrt(3)*ox^2 - 152*sqrt(3)*ox - 25*sqrt(3))*oy^2 + 10500*sqrt(3)*ox^2 - 210*(64*ox^6 - 64*ox^5 + 1136*ox^4 - 736*ox^3 - 228*ox^2 + 148*ox - 1)*oy - 5460*sqrt(3)*ox - 189*sqrt(3))*sy^6 - (960*sqrt(3)*oy^7 + 16800*ox^6 - 336*(60*sqrt(3)*ox^2 - 20*sqrt(3)*ox + 71*sqrt(3))*oy^5 - 16800*oy^6 - 16800*ox^5 + 84000*(3*ox^2 - ox)*oy^4 + 140*(240*sqrt(3)*ox^4 - 160*sqrt(3)*ox^3 + 1704*sqrt(3)*ox^2 - 552*sqrt(3)*ox - 57*sqrt(3))*oy^3 + 5600*ox^3 - 210*(1200*ox^4 - 800*ox^3 + 80*ox - 17)*oy^2 - 3570*ox^2 - 105*(64*sqrt(3)*ox^6 - 64*sqrt(3)*ox^5 + 1136*sqrt(3)*ox^4 - 736*sqrt(3)*ox^3 - 228*sqrt(3)*ox^2 + 148*sqrt(3)*ox - sqrt(3))*oy + 210*ox + 210)*sy^5 - 5*(480*oy^7 - 1680*sqrt(3)*ox^6 + 1680*sqrt(3)*oy^6 - 672*(15*ox^2 - 5*ox + 2)*oy^5 + 1680*sqrt(3)*ox^5 - 8400*(3*sqrt(3)*ox^2 - sqrt(3)*ox)*oy^4 + 14*(1200*ox^4 - 800*ox^3 + 960*ox^2 - 240*ox - 81)*oy^3 - 560*sqrt(3)*ox^3 + 21*(1200*sqrt(3)*ox^4 - 800*sqrt(3)*ox^3 + 80*sqrt(3)*ox - 17*sqrt(3))*oy^2 + 357*sqrt(3)*ox^2 - 42*(80*ox^6 - 80*ox^5 + 160*ox^4 - 80*ox^3 - 81*ox^2 + 33*ox + 3)*oy - 21*sqrt(3)*ox - 21*sqrt(3))*sy^4 + 5*(240*sqrt(3)*oy^7 + 672*ox^6 - 336*(15*sqrt(3)*ox^2 - 5*sqrt(3)*ox + 2*sqrt(3))*oy^5 - 672*oy^6 - 672*ox^5 + 672*(15*ox^2 - 5*ox - 1)*oy^4 - 672*ox^4 + 7*(1200*sqrt(3)*ox^4 - 800*sqrt(3)*ox^3 + 960*sqrt(3)*ox^2 - 240*sqrt(3)*ox - 81*sqrt(3))*oy^3 + 672*ox^3 - 42*(240*ox^4 - 160*ox^3 - 96*ox^2 + 48*ox + 3)*oy^2 + 126*ox^2 - 21*(80*sqrt(3)*ox^6 - 80*sqrt(3)*ox^5 + 160*sqrt(3)*ox^4 - 80*sqrt(3)*ox^3 - 81*sqrt(3)*ox^2 + 33*sqrt(3)*ox + 3*sqrt(3))*oy - 126*ox)*sy^3 + (480*oy^7 - 1680*sqrt(3)*ox^6 + 1680*sqrt(3)*oy^6 - 672*(15*ox^2 - 5*ox - 1)*oy^5 + 1680*sqrt(3)*ox^5 - 1680*(15*sqrt(3)*ox^2 - 5*sqrt(3)*ox - sqrt(3))*oy^4 + 1680*sqrt(3)*ox^4 + 70*(240*ox^4 - 160*ox^3 - 96*ox^2 + 48*ox + 3)*oy^3 - 1680*sqrt(3)*ox^3 + 105*(240*sqrt(3)*ox^4 - 160*sqrt(3)*ox^3 - 96*sqrt(3)*ox^2 + 48*sqrt(3)*ox + 3*sqrt(3))*oy^2 - 315*sqrt(3)*ox^2 - 210*(16*ox^6 - 16*ox^5 - 16*ox^4 + 16*ox^3 + 3*ox^2 - 3*ox)*oy + 315*sqrt(3)*ox)*sy^2 - (240*sqrt(3)*oy^7 - 336*(15*sqrt(3)*ox^2 - 5*sqrt(3)*ox - sqrt(3))*oy^5 + 35*(240*sqrt(3)*ox^4 - 160*sqrt(3)*ox^3 - 96*sqrt(3)*ox^2 + 48*sqrt(3)*ox + 3*sqrt(3))*oy^3 - 105*(16*sqrt(3)*ox^6 - 16*sqrt(3)*ox^5 - 16*sqrt(3)*ox^4 + 16*sqrt(3)*ox^3 + 3*sqrt(3)*ox^2 - 3*sqrt(3)*ox)*oy)*sy)*arctan((ox - 1)/(oy - sy)) - 5565*(8*sy^6 - 4*sqrt(3)*sy^5 - 10*sy^4 + 5*sqrt(3)*sy^3 + 2*sy^2 - sqrt(3)*sy)*log(ox^2 + oy^2 - 2*oy*sy + sy^2 + 2*ox + 1) + 1785*(8*sy^6 - 4*sqrt(3)*sy^5 - 10*sy^4 + 5*sqrt(3)*sy^3 + 2*sy^2 - sqrt(3)*sy)*log(ox^2 + oy^2 - 2*oy*sy + sy^2 - 2*ox + 1) + 105*(4480*(6*ox - 1)*sy^12 - 2240*(12*(6*ox - 1)*oy + 6*sqrt(3)*ox - sqrt(3))*sy^11 - 1120*(120*ox^3 - 60*(6*ox - 1)*oy^2 - 60*ox^2 - 12*(6*sqrt(3)*ox - sqrt(3))*oy + 6*ox + 1)*sy^10 - 560*(160*(6*ox - 1)*oy^3 - 120*sqrt(3)*ox^3 + 60*(6*sqrt(3)*ox - sqrt(3))*oy^2 + 60*sqrt(3)*ox^2 - 12*(80*ox^3 - 40*ox^2 + 14*ox - 1)*oy - 6*sqrt(3)*ox - sqrt(3))*sy^9 + 280*(288*ox^5 + 240*(6*ox - 1)*oy^4 - 240*ox^4 + 160*(6*sqrt(3)*ox - sqrt(3))*oy^3 + 408*ox^3 - 12*(240*ox^3 - 120*ox^2 + 102*ox - 13)*oy^2 - 156*ox^2 - 12*(80*sqrt(3)*ox^3 - 40*sqrt(3)*ox^2 + 14*sqrt(3)*ox - sqrt(3))*oy - 78*ox + 17)*sy^8 - 140*(192*(6*ox - 1)*oy^5 + 288*sqrt(3)*ox^5 + 240*(6*sqrt(3)*ox - sqrt(3))*oy^4 - 240*sqrt(3)*ox^4 - 32*(120*ox^3 - 60*ox^2 + 126*ox - 19)*oy^3 + 408*sqrt(3)*ox^3 - 12*(240*sqrt(3)*ox^3 - 120*sqrt(3)*ox^2 + 102*sqrt(3)*ox - 13*sqrt(3))*oy^2 - 156*sqrt(3)*ox^2 + 12*(96*ox^5 - 80*ox^4 + 336*ox^3 - 152*ox^2 - 50*ox + 13)*oy - 78*sqrt(3)*ox + 17*sqrt(3))*sy^7 - 2*(1920*ox^7 - 2240*(6*ox - 1)*oy^6 - 2240*ox^6 - 6720*(6*sqrt(3)*ox - sqrt(3))*oy^5 + 47712*ox^5 + 1680*(40*ox^3 - 20*ox^2 + 142*ox - 23)*oy^4 - 38640*ox^4 + 1120*(120*sqrt(3)*ox^3 - 60*sqrt(3)*ox^2 + 126*sqrt(3)*ox - 19*sqrt(3))*oy^3 - 15960*ox^3 - 420*(96*ox^5 - 80*ox^4 + 1136*ox^3 - 552*ox^2 - 114*ox + 37)*oy^2 + 15540*ox^2 - 420*(96*sqrt(3)*ox^5 - 80*sqrt(3)*ox^4 + 336*sqrt(3)*ox^3 - 152*sqrt(3)*ox^2 - 50*sqrt(3)*ox + 13*sqrt(3))*oy - 210*ox - 735)*sy^6 + (1920*sqrt(3)*ox^7 - 2240*(6*sqrt(3)*ox - sqrt(3))*oy^6 - 2240*sqrt(3)*ox^6 + 33600*(6*ox - 1)*oy^5 + 47712*sqrt(3)*ox^5 + 1680*(40*sqrt(3)*ox^3 - 20*sqrt(3)*ox^2 + 142*sqrt(3)*ox - 23*sqrt(3))*oy^4 - 38640*sqrt(3)*ox^4 - 11200*(60*ox^3 - 30*ox^2 + 1)*oy^3 - 15960*sqrt(3)*ox^3 - 420*(96*sqrt(3)*ox^5 - 80*sqrt(3)*ox^4 + 1136*sqrt(3)*ox^3 - 552*sqrt(3)*ox^2 - 114*sqrt(3)*ox + 37*sqrt(3))*oy^2 + 15540*sqrt(3)*ox^2 + 420*(480*ox^5 - 400*ox^4 + 80*ox^2 - 34*ox + 1)*oy - 210*sqrt(3)*ox - 735*sqrt(3))*sy^5 + 10*(480*ox^7 - 560*(6*ox - 1)*oy^6 - 560*ox^6 - 1680*(6*sqrt(3)*ox - sqrt(3))*oy^5 + 1344*ox^5 + 840*(20*ox^3 - 10*ox^2 + 8*ox - 1)*oy^4 - 840*ox^4 + 560*(60*sqrt(3)*ox^3 - 30*sqrt(3)*ox^2 + sqrt(3))*oy^3 - 1134*ox^3 - 21*(480*ox^5 - 400*ox^4 + 640*ox^3 - 240*ox^2 - 162*ox + 33)*oy^2 + 693*ox^2 - 21*(480*sqrt(3)*ox^5 - 400*sqrt(3)*ox^4 + 80*sqrt(3)*ox^2 - 34*sqrt(3)*ox + sqrt(3))*oy + 126*ox - 63)*sy^4 - 5*(480*sqrt(3)*ox^7 - 560*(6*sqrt(3)*ox - sqrt(3))*oy^6 - 560*sqrt(3)*ox^6 + 1344*(6*ox - 1)*oy^5 + 1344*sqrt(3)*ox^5 + 840*(20*sqrt(3)*ox^3 - 10*sqrt(3)*ox^2 + 8*sqrt(3)*ox - sqrt(3))*oy^4 - 840*sqrt(3)*ox^4 - 1344*(20*ox^3 - 10*ox^2 - 4*ox + 1)*oy^3 - 1134*sqrt(3)*ox^3 - 21*(480*sqrt(3)*ox^5 - 400*sqrt(3)*ox^4 + 640*sqrt(3)*ox^3 - 240*sqrt(3)*ox^2 - 162*sqrt(3)*ox + 33*sqrt(3))*oy^2 + 693*sqrt(3)*ox^2 + 84*(96*ox^5 - 80*ox^4 - 64*ox^3 + 48*ox^2 + 6*ox - 3)*oy + 126*sqrt(3)*ox - 63*sqrt(3))*sy^3 - 2*(480*ox^7 - 560*(6*ox - 1)*oy^6 - 560*ox^6 - 1680*(6*sqrt(3)*ox - sqrt(3))*oy^5 - 672*ox^5 + 840*(20*ox^3 - 10*ox^2 - 4*ox + 1)*oy^4 + 840*ox^4 + 1680*(20*sqrt(3)*ox^3 - 10*sqrt(3)*ox^2 - 4*sqrt(3)*ox + sqrt(3))*oy^3 + 210*ox^3 - 105*(96*ox^5 - 80*ox^4 - 64*ox^3 + 48*ox^2 + 6*ox - 3)*oy^2 - 315*ox^2 - 105*(96*sqrt(3)*ox^5 - 80*sqrt(3)*ox^4 - 64*sqrt(3)*ox^3 + 48*sqrt(3)*ox^2 + 6*sqrt(3)*ox - 3*sqrt(3))*oy)*sy^2 + (480*sqrt(3)*ox^7 - 560*(6*sqrt(3)*ox - sqrt(3))*oy^6 - 560*sqrt(3)*ox^6 - 672*sqrt(3)*ox^5 + 840*(20*sqrt(3)*ox^3 - 10*sqrt(3)*ox^2 - 4*sqrt(3)*ox + sqrt(3))*oy^4 + 840*sqrt(3)*ox^4 + 210*sqrt(3)*ox^3 - 105*(96*sqrt(3)*ox^5 - 80*sqrt(3)*ox^4 - 64*sqrt(3)*ox^3 + 48*sqrt(3)*ox^2 + 6*sqrt(3)*ox - 3*sqrt(3))*oy^2 - 315*sqrt(3)*ox^2)*sy)*log(abs(ox^2 + oy^2 - 2*oy*sy + sy^2 + 2*ox + 1)) - 105*(4480*(6*ox - 1)*sy^12 - 2240*(12*(6*ox - 1)*oy + 6*sqrt(3)*ox - sqrt(3))*sy^11 - 1120*(120*ox^3 - 60*(6*ox - 1)*oy^2 - 60*ox^2 - 12*(6*sqrt(3)*ox - sqrt(3))*oy + 6*ox + 1)*sy^10 - 560*(160*(6*ox - 1)*oy^3 - 120*sqrt(3)*ox^3 + 60*(6*sqrt(3)*ox - sqrt(3))*oy^2 + 60*sqrt(3)*ox^2 - 12*(80*ox^3 - 40*ox^2 + 14*ox - 1)*oy - 6*sqrt(3)*ox - sqrt(3))*sy^9 + 280*(288*ox^5 + 240*(6*ox - 1)*oy^4 - 240*ox^4 + 160*(6*sqrt(3)*ox - sqrt(3))*oy^3 + 408*ox^3 - 12*(240*ox^3 - 120*ox^2 + 102*ox - 13)*oy^2 - 156*ox^2 - 12*(80*sqrt(3)*ox^3 - 40*sqrt(3)*ox^2 + 14*sqrt(3)*ox - sqrt(3))*oy - 78*ox + 17)*sy^8 - 140*(192*(6*ox - 1)*oy^5 + 288*sqrt(3)*ox^5 + 240*(6*sqrt(3)*ox - sqrt(3))*oy^4 - 240*sqrt(3)*ox^4 - 32*(120*ox^3 - 60*ox^2 + 126*ox - 19)*oy^3 + 408*sqrt(3)*ox^3 - 12*(240*sqrt(3)*ox^3 - 120*sqrt(3)*ox^2 + 102*sqrt(3)*ox - 13*sqrt(3))*oy^2 - 156*sqrt(3)*ox^2 + 12*(96*ox^5 - 80*ox^4 + 336*ox^3 - 152*ox^2 - 50*ox + 13)*oy - 78*sqrt(3)*ox + 17*sqrt(3))*sy^7 - 2*(1920*ox^7 - 2240*(6*ox - 1)*oy^6 - 2240*ox^6 - 6720*(6*sqrt(3)*ox - sqrt(3))*oy^5 + 47712*ox^5 + 1680*(40*ox^3 - 20*ox^2 + 142*ox - 23)*oy^4 - 38640*ox^4 + 1120*(120*sqrt(3)*ox^3 - 60*sqrt(3)*ox^2 + 126*sqrt(3)*ox - 19*sqrt(3))*oy^3 - 15960*ox^3 - 420*(96*ox^5 - 80*ox^4 + 1136*ox^3 - 552*ox^2 - 114*ox + 37)*oy^2 + 15540*ox^2 - 420*(96*sqrt(3)*ox^5 - 80*sqrt(3)*ox^4 + 336*sqrt(3)*ox^3 - 152*sqrt(3)*ox^2 - 50*sqrt(3)*ox + 13*sqrt(3))*oy - 210*ox - 735)*sy^6 + (1920*sqrt(3)*ox^7 - 2240*(6*sqrt(3)*ox - sqrt(3))*oy^6 - 2240*sqrt(3)*ox^6 + 33600*(6*ox - 1)*oy^5 + 47712*sqrt(3)*ox^5 + 1680*(40*sqrt(3)*ox^3 - 20*sqrt(3)*ox^2 + 142*sqrt(3)*ox - 23*sqrt(3))*oy^4 - 38640*sqrt(3)*ox^4 - 11200*(60*ox^3 - 30*ox^2 + 1)*oy^3 - 15960*sqrt(3)*ox^3 - 420*(96*sqrt(3)*ox^5 - 80*sqrt(3)*ox^4 + 1136*sqrt(3)*ox^3 - 552*sqrt(3)*ox^2 - 114*sqrt(3)*ox + 37*sqrt(3))*oy^2 + 15540*sqrt(3)*ox^2 + 420*(480*ox^5 - 400*ox^4 + 80*ox^2 - 34*ox + 1)*oy - 210*sqrt(3)*ox - 735*sqrt(3))*sy^5 + 10*(480*ox^7 - 560*(6*ox - 1)*oy^6 - 560*ox^6 - 1680*(6*sqrt(3)*ox - sqrt(3))*oy^5 + 1344*ox^5 + 840*(20*ox^3 - 10*ox^2 + 8*ox - 1)*oy^4 - 840*ox^4 + 560*(60*sqrt(3)*ox^3 - 30*sqrt(3)*ox^2 + sqrt(3))*oy^3 - 1134*ox^3 - 21*(480*ox^5 - 400*ox^4 + 640*ox^3 - 240*ox^2 - 162*ox + 33)*oy^2 + 693*ox^2 - 21*(480*sqrt(3)*ox^5 - 400*sqrt(3)*ox^4 + 80*sqrt(3)*ox^2 - 34*sqrt(3)*ox + sqrt(3))*oy + 126*ox - 63)*sy^4 - 5*(480*sqrt(3)*ox^7 - 560*(6*sqrt(3)*ox - sqrt(3))*oy^6 - 560*sqrt(3)*ox^6 + 1344*(6*ox - 1)*oy^5 + 1344*sqrt(3)*ox^5 + 840*(20*sqrt(3)*ox^3 - 10*sqrt(3)*ox^2 + 8*sqrt(3)*ox - sqrt(3))*oy^4 - 840*sqrt(3)*ox^4 - 1344*(20*ox^3 - 10*ox^2 - 4*ox + 1)*oy^3 - 1134*sqrt(3)*ox^3 - 21*(480*sqrt(3)*ox^5 - 400*sqrt(3)*ox^4 + 640*sqrt(3)*ox^3 - 240*sqrt(3)*ox^2 - 162*sqrt(3)*ox + 33*sqrt(3))*oy^2 + 693*sqrt(3)*ox^2 + 84*(96*ox^5 - 80*ox^4 - 64*ox^3 + 48*ox^2 + 6*ox - 3)*oy + 126*sqrt(3)*ox - 63*sqrt(3))*sy^3 - 2*(480*ox^7 - 560*(6*ox - 1)*oy^6 - 560*ox^6 - 1680*(6*sqrt(3)*ox - sqrt(3))*oy^5 - 672*ox^5 + 840*(20*ox^3 - 10*ox^2 - 4*ox + 1)*oy^4 + 840*ox^4 + 1680*(20*sqrt(3)*ox^3 - 10*sqrt(3)*ox^2 - 4*sqrt(3)*ox + sqrt(3))*oy^3 + 210*ox^3 - 105*(96*ox^5 - 80*ox^4 - 64*ox^3 + 48*ox^2 + 6*ox - 3)*oy^2 - 315*ox^2 - 105*(96*sqrt(3)*ox^5 - 80*sqrt(3)*ox^4 - 64*sqrt(3)*ox^3 + 48*sqrt(3)*ox^2 + 6*sqrt(3)*ox - 3*sqrt(3))*oy)*sy^2 + (480*sqrt(3)*ox^7 - 560*(6*sqrt(3)*ox - sqrt(3))*oy^6 - 560*sqrt(3)*ox^6 - 672*sqrt(3)*ox^5 + 840*(20*sqrt(3)*ox^3 - 10*sqrt(3)*ox^2 - 4*sqrt(3)*ox + sqrt(3))*oy^4 + 840*sqrt(3)*ox^4 + 210*sqrt(3)*ox^3 - 105*(96*sqrt(3)*ox^5 - 80*sqrt(3)*ox^4 - 64*sqrt(3)*ox^3 + 48*sqrt(3)*ox^2 + 6*sqrt(3)*ox - 3*sqrt(3))*oy^2 - 315*sqrt(3)*ox^2)*sy)*log(abs(ox^2 + oy^2 - 2*oy*sy + sy^2 - 2*ox + 1)))/pi

```python
If = integral(Isx_simp, sy, -1, 1)
```

```python
If
```

    1/85816130400*sqrt(3)*(1209600*(sqrt(3)*arctan((oy - 1)/(ox + 1)) - sqrt(3)*arctan((oy - 1)/(ox - 1)))*oy^14 - 4233600*oy^13*(arctan((oy - 1)/(ox + 1)) - arctan((oy - 1)/(ox - 1))) - 20160*(91*(60*sqrt(3)*ox^2 - 20*sqrt(3)*ox + sqrt(3))*arctan((oy - 1)/(ox + 1)) - 91*(60*sqrt(3)*ox^2 - 20*sqrt(3)*ox + sqrt(3))*arctan((oy - 1)/(ox - 1)) - 240*sqrt(3))*oy^12 + 4838400*sqrt(3)*ox^12 + 211680*(13*(120*ox^2 - 40*ox + 7)*arctan((oy - 1)/(ox + 1)) - 13*(120*ox^2 - 40*ox + 7)*arctan((oy - 1)/(ox - 1)) - 80)*oy^11 - 11289600*sqrt(3)*ox^11 - 5040*(63360*sqrt(3)*ox^2 - 1001*(240*sqrt(3)*ox^4 - 160*sqrt(3)*ox^3 + 24*sqrt(3)*ox^2 + 8*sqrt(3)*ox - sqrt(3))*arctan((oy - 1)/(ox + 1)) + 1001*(240*sqrt(3)*ox^4 - 160*sqrt(3)*ox^3 + 24*sqrt(3)*ox^2 + 8*sqrt(3)*ox - sqrt(3))*arctan((oy - 1)/(ox - 1)) - 24640*sqrt(3)*ox + 1456*sqrt(3))*oy^10 + 7338240*sqrt(3)*ox^10 + 17640*(52800*ox^2 - 715*(240*ox^4 - 160*ox^3 + 84*ox^2 - 12*ox + 3)*arctan((oy - 1)/(ox + 1)) + 715*(240*ox^4 - 160*ox^3 + 84*ox^2 - 12*ox + 3)*arctan((oy - 1)/(ox - 1)) - 20800*ox + 4368)*oy^9 + 14676480*sqrt(3)*ox^9 + 1260*(1900800*sqrt(3)*ox^4 - 1478400*sqrt(3)*ox^3 + 262080*sqrt(3)*ox^2 - 3003*(960*sqrt(3)*ox^6 - 960*sqrt(3)*ox^5 + 240*sqrt(3)*ox^4 + 160*sqrt(3)*ox^3 - 60*sqrt(3)*ox^2 - 20*sqrt(3)*ox - sqrt(3))*arctan((oy - 1)/(ox + 1)) + 3003*(960*sqrt(3)*ox^6 - 960*sqrt(3)*ox^5 + 240*sqrt(3)*ox^4 + 160*sqrt(3)*ox^3 - 60*sqrt(3)*ox^2 - 20*sqrt(3)*ox - sqrt(3))*arctan((oy - 1)/(ox - 1)) + 104832*sqrt(3)*ox - 21136*sqrt(3))*oy^8 - 26631360*sqrt(3)*ox^8 - 1260*(4435200*ox^4 - 3494400*ox^3 + 2201472*ox^2 + 34320*(16*sqrt(3) - 21)*arctan((ox + 1)/(oy - 1)) - 34320*(16*sqrt(3) - 21)*arctan((ox - 1)/(oy - 1)) - 9009*(640*ox^6 - 640*ox^5 + 560*ox^4 - 160*ox^3 + 120*ox^2 - 40*ox - 17)*arctan((oy - 1)/(ox + 1)) + 9009*(640*ox^6 - 640*ox^5 + 560*ox^4 - 160*ox^3 + 120*ox^2 - 40*ox - 17)*arctan((oy - 1)/(ox - 1)) - 384384*ox + 102200)*oy^7 - 18580800*sqrt(3)*ox^7 - 5880*(760320*sqrt(3)*ox^6 - 887040*sqrt(3)*ox^5 + 262080*sqrt(3)*ox^4 + 209664*sqrt(3)*ox^3 - 126816*sqrt(3)*ox^2 - 102960*(7*sqrt(3) - 12)*arctan((ox + 1)/(oy - 1)) + 102960*(7*sqrt(3) - 12)*arctan((ox - 1)/(oy - 1)) - 429*(1440*sqrt(3)*ox^8 - 1920*sqrt(3)*ox^7 + 672*sqrt(3)*ox^6 + 672*sqrt(3)*ox^5 - 420*sqrt(3)*ox^4 - 280*sqrt(3)*ox^3 - 42*sqrt(3)*ox^2 + 978*sqrt(3)*ox + 873*sqrt(3))*arctan((oy - 1)/(ox + 1)) + 429*(1440*sqrt(3)*ox^8 - 1920*sqrt(3)*ox^7 + 672*sqrt(3)*ox^6 + 672*sqrt(3)*ox^5 - 420*sqrt(3)*ox^4 - 280*sqrt(3)*ox^3 - 42*sqrt(3)*ox^2 + 114*sqrt(3)*ox + 9*sqrt(3))*arctan((oy - 1)/(ox - 1)) - 22120*sqrt(3)*ox - 580814*sqrt(3))*oy^6 - 3415186320*sqrt(3)*ox^6 + 8820*(887040*ox^6 - 1048320*ox^5 + 1100736*ox^4 - 384384*ox^3 + 306600*ox^2 + 6864*(15*ox^2*(16*sqrt(3) - 21) - 5*ox*(16*sqrt(3) - 21) - 192*sqrt(3) + 336)*arctan((ox + 1)/(oy - 1)) - 6864*(15*ox^2*(16*sqrt(3) - 21) - 5*ox*(16*sqrt(3) - 21) - 192*sqrt(3) + 336)*arctan((ox - 1)/(oy - 1)) - 1287*(480*ox^8 - 640*ox^7 + 784*ox^6 - 336*ox^5 + 420*ox^4 - 280*ox^3 - 357*ox^2 + 445*ox + 305)*arctan((oy - 1)/(ox + 1)) + 1287*(480*ox^8 - 640*ox^7 + 784*ox^6 - 336*ox^5 + 420*ox^4 - 280*ox^3 - 357*ox^2 + 157*ox + 17)*arctan((oy - 1)/(ox - 1)) - 121160*ox + 2660164)*oy^5 - 362631360*sqrt(3)*ox^5 + 840*(2851200*sqrt(3)*ox^8 - 4435200*sqrt(3)*ox^7 + 1834560*sqrt(3)*ox^6 + 2201472*sqrt(3)*ox^5 - 2219280*sqrt(3)*ox^4 - 774200*sqrt(3)*ox^3 - 60985470*sqrt(3)*ox^2 - 360360*(30*ox^2*(7*sqrt(3) - 12) - 10*ox*(7*sqrt(3) - 12) - 63*sqrt(3) + 112)*arctan((ox + 1)/(oy - 1)) + 360360*(30*ox^2*(7*sqrt(3) - 12) - 10*ox*(7*sqrt(3) - 12) - 63*sqrt(3) + 112)*arctan((ox - 1)/(oy - 1)) - 15015*(96*sqrt(3)*ox^10 - 160*sqrt(3)*ox^9 + 72*sqrt(3)*ox^8 + 96*sqrt(3)*ox^7 - 84*sqrt(3)*ox^6 - 84*sqrt(3)*ox^5 - 21*sqrt(3)*ox^4 + 978*sqrt(3)*ox^3 + 2619*sqrt(3)*ox^2 + 2907*sqrt(3)*ox + 1181*sqrt(3))*arctan((oy - 1)/(ox + 1)) + 15015*(96*sqrt(3)*ox^10 - 160*sqrt(3)*ox^9 + 72*sqrt(3)*ox^8 + 96*sqrt(3)*ox^7 - 84*sqrt(3)*ox^6 - 84*sqrt(3)*ox^5 - 21*sqrt(3)*ox^4 + 114*sqrt(3)*ox^3 + 27*sqrt(3)*ox^2 - 93*sqrt(3)*ox + 37*sqrt(3))*arctan((oy - 1)/(ox - 1)) - 2158520*sqrt(3)*ox + 24203164*sqrt(3))*oy^4 + 20330657760*sqrt(3)*ox^4 - 2940*(950400*ox^8 - 1497600*ox^7 + 2201472*ox^6 - 1153152*ox^5 + 1533000*ox^4 - 1211600*ox^3 + 79804920*ox^2 + 39*(13200*ox^4*(16*sqrt(3) - 21) - 8800*ox^3*(16*sqrt(3) - 21) - 253440*ox^2*(4*sqrt(3) - 7) + 880*ox*(400*sqrt(3) - 693) + 173392*sqrt(3) - 308385)*arctan((ox + 1)/(oy - 1)) - 39*(13200*ox^4*(16*sqrt(3) - 21) - 8800*ox^3*(16*sqrt(3) - 21) - 253440*ox^2*(4*sqrt(3) - 7) + 880*ox*(400*sqrt(3) - 693) + 173392*sqrt(3) - 308385)*arctan((ox - 1)/(oy - 1)) - 2145*(192*ox^10 - 320*ox^9 + 504*ox^8 - 288*ox^7 + 504*ox^6 - 504*ox^5 - 1071*ox^4 + 2670*ox^3 + 5490*ox^2 + 5880*ox + 2575)*arctan((oy - 1)/(ox + 1)) + 2145*(192*ox^10 - 320*ox^9 + 504*ox^8 - 288*ox^7 + 504*ox^6 - 504*ox^5 - 1071*ox^4 + 942*ox^3 + 306*ox^2 - 336*ox + 71)*arctan((oy - 1)/(ox - 1)) - 39457704*ox - 29517360)*oy^3 - 43119647200*sqrt(3)*ox^3 - 168*(1900800*sqrt(3)*ox^10 - 3696000*sqrt(3)*ox^9 + 1965600*sqrt(3)*ox^8 + 3144960*sqrt(3)*ox^7 - 4438560*sqrt(3)*ox^6 - 2322600*sqrt(3)*ox^5 - 304927350*sqrt(3)*ox^4 - 21585200*sqrt(3)*ox^3 + 726094920*sqrt(3)*ox^2 - 4095*(13200*ox^4*(7*sqrt(3) - 12) - 8800*ox^3*(7*sqrt(3) - 12) - 18480*ox^2*(9*sqrt(3) - 16) + 1760*ox*(35*sqrt(3) - 62) + 19019*sqrt(3) - 33788)*arctan((ox + 1)/(oy - 1)) + 4095*(13200*ox^4*(7*sqrt(3) - 12) - 8800*ox^3*(7*sqrt(3) - 12) - 18480*ox^2*(9*sqrt(3) - 16) + 1760*ox*(35*sqrt(3) - 62) + 19019*sqrt(3) - 33788)*arctan((ox - 1)/(oy - 1)) - 1365*(480*sqrt(3)*ox^12 - 960*sqrt(3)*ox^11 + 528*sqrt(3)*ox^10 + 880*sqrt(3)*ox^9 - 990*sqrt(3)*ox^8 - 1320*sqrt(3)*ox^7 - 462*sqrt(3)*ox^6 + 32274*sqrt(3)*ox^5 + 144045*sqrt(3)*ox^4 + 319770*sqrt(3)*ox^3 + 389730*sqrt(3)*ox^2 + 247188*sqrt(3)*ox + 64501*sqrt(3))*arctan((oy - 1)/(ox + 1)) + 1365*(480*sqrt(3)*ox^12 - 960*sqrt(3)*ox^11 + 528*sqrt(3)*ox^10 + 880*sqrt(3)*ox^9 - 990*sqrt(3)*ox^8 - 1320*sqrt(3)*ox^7 - 462*sqrt(3)*ox^6 + 3762*sqrt(3)*ox^5 + 1485*sqrt(3)*ox^4 - 10230*sqrt(3)*ox^3 + 12210*sqrt(3)*ox^2 - 6948*sqrt(3)*ox + 1565*sqrt(3))*arctan((oy - 1)/(ox - 1)) - 769993700*sqrt(3)*ox - 295847916*sqrt(3))*oy^2 - 49702449888*sqrt(3)*ox^2 + 1764*(105600*ox^10 - 208000*ox^9 + 393120*ox^8 - 274560*ox^7 + 511000*ox^6 - 605800*ox^5 + 66504100*ox^4 - 65762840*ox^3 - 147586800*ox^2 + 5*(34320*ox^6*(16*sqrt(3) - 21) - 34320*ox^5*(16*sqrt(3) - 21) - 1647360*ox^4*(4*sqrt(3) - 7) + 11440*ox^3*(400*sqrt(3) - 693) + 39*ox^2*(173392*sqrt(3) - 308385) - 13*ox*(209648*sqrt(3) - 370755) - 564464*sqrt(3) + 999999)*arctan((ox + 1)/(oy - 1)) - 5*(34320*ox^6*(16*sqrt(3) - 21) - 34320*ox^5*(16*sqrt(3) - 21) - 1647360*ox^4*(4*sqrt(3) - 7) + 11440*ox^3*(400*sqrt(3) - 693) + 39*ox^2*(173392*sqrt(3) - 308385) - 13*ox*(209648*sqrt(3) - 370755) - 564464*sqrt(3) + 999999)*arctan((ox - 1)/(oy - 1)) - 195*(160*ox^12 - 320*ox^11 + 616*ox^10 - 440*ox^9 + 990*ox^8 - 1320*ox^7 - 3927*ox^6 + 14685*ox^5 + 50325*ox^4 + 107800*ox^3 + 141625*ox^2 + 96883*ox + 27499)*arctan((oy - 1)/(ox + 1)) + 195*(160*ox^12 - 320*ox^11 + 616*ox^10 - 440*ox^9 + 990*ox^8 - 1320*ox^7 - 3927*ox^6 + 5181*ox^5 + 2805*ox^4 - 6160*ox^3 + 3905*ox^2 - 2173*ox + 683)*arctan((oy - 1)/(ox - 1)) + 35451000*ox + 6760104)*oy - 1260*(34320*oy^7*(16*sqrt(3) + 21) - 480480*ox^6*(7*sqrt(3) + 12) + 480480*oy^6*(7*sqrt(3) + 12) - 48048*(15*ox^2*(16*sqrt(3) + 21) - 5*ox*(16*sqrt(3) + 21) - 192*sqrt(3) - 336)*oy^5 + 480480*ox^5*(7*sqrt(3) + 12) - 240240*(30*ox^2*(7*sqrt(3) + 12) - 10*ox*(7*sqrt(3) + 12) - 63*sqrt(3) - 112)*oy^4 + 1681680*ox^4*(9*sqrt(3) + 16) + 91*(13200*ox^4*(16*sqrt(3) + 21) - 8800*ox^3*(16*sqrt(3) + 21) - 253440*ox^2*(4*sqrt(3) + 7) + 880*ox*(400*sqrt(3) + 693) + 173392*sqrt(3) + 308385)*oy^3 - 320320*ox^3*(35*sqrt(3) + 62) + 546*(13200*ox^4*(7*sqrt(3) + 12) - 8800*ox^3*(7*sqrt(3) + 12) - 18480*ox^2*(9*sqrt(3) + 16) + 1760*ox*(35*sqrt(3) + 62) + 19019*sqrt(3) + 33788)*oy^2 - 546*ox^2*(19019*sqrt(3) + 33788) - 7*(34320*ox^6*(16*sqrt(3) + 21) - 34320*ox^5*(16*sqrt(3) + 21) - 1647360*ox^4*(4*sqrt(3) + 7) + 11440*ox^3*(400*sqrt(3) + 693) + 39*ox^2*(173392*sqrt(3) + 308385) - 13*ox*(209648*sqrt(3) + 370755) - 564464*sqrt(3) - 999999)*oy + 546*ox*(8547*sqrt(3) + 15164) + 661947*sqrt(3) + 1167432)*arctan((ox + 1)/(oy + 1)) + 1260*(34320*oy^7*(16*sqrt(3) + 21) - 480480*ox^6*(7*sqrt(3) + 12) + 480480*oy^6*(7*sqrt(3) + 12) - 48048*(15*ox^2*(16*sqrt(3) + 21) - 5*ox*(16*sqrt(3) + 21) - 192*sqrt(3) - 336)*oy^5 + 480480*ox^5*(7*sqrt(3) + 12) - 240240*(30*ox^2*(7*sqrt(3) + 12) - 10*ox*(7*sqrt(3) + 12) - 63*sqrt(3) - 112)*oy^4 + 1681680*ox^4*(9*sqrt(3) + 16) + 91*(13200*ox^4*(16*sqrt(3) + 21) - 8800*ox^3*(16*sqrt(3) + 21) - 253440*ox^2*(4*sqrt(3) + 7) + 880*ox*(400*sqrt(3) + 693) + 173392*sqrt(3) + 308385)*oy^3 - 320320*ox^3*(35*sqrt(3) + 62) + 546*(13200*ox^4*(7*sqrt(3) + 12) - 8800*ox^3*(7*sqrt(3) + 12) - 18480*ox^2*(9*sqrt(3) + 16) + 1760*ox*(35*sqrt(3) + 62) + 19019*sqrt(3) + 33788)*oy^2 - 546*ox^2*(19019*sqrt(3) + 33788) - 7*(34320*ox^6*(16*sqrt(3) + 21) - 34320*ox^5*(16*sqrt(3) + 21) - 1647360*ox^4*(4*sqrt(3) + 7) + 11440*ox^3*(400*sqrt(3) + 693) + 39*ox^2*(173392*sqrt(3) + 308385) - 13*ox*(209648*sqrt(3) + 370755) - 564464*sqrt(3) - 999999)*oy + 546*ox*(8547*sqrt(3) + 15164) + 661947*sqrt(3) + 1167432)*arctan((ox - 1)/(oy + 1)) + 420*(2880*sqrt(3)*ox^14 - 2880*sqrt(3)*oy^14 - 6720*sqrt(3)*ox^13 + 4368*(60*sqrt(3)*ox^2 - 20*sqrt(3)*ox + sqrt(3))*oy^12 + 10080*oy^13 + 4368*sqrt(3)*ox^12 - 6552*(120*ox^2 - 40*ox + 7)*oy^11 + 8736*sqrt(3)*ox^11 - 12012*(240*sqrt(3)*ox^4 - 160*sqrt(3)*ox^3 + 24*sqrt(3)*ox^2 + 8*sqrt(3)*ox - sqrt(3))*oy^10 - 12012*sqrt(3)*ox^10 + 30030*(240*ox^4 - 160*ox^3 + 84*ox^2 - 12*ox + 3)*oy^9 - 20020*sqrt(3)*ox^9 + 9009*(960*sqrt(3)*ox^6 - 960*sqrt(3)*ox^5 + 240*sqrt(3)*ox^4 + 160*sqrt(3)*ox^3 - 60*sqrt(3)*ox^2 - 20*sqrt(3)*ox - sqrt(3))*oy^8 - 9009*sqrt(3)*ox^8 - 27027*(640*ox^6 - 640*ox^5 + 560*ox^4 - 160*ox^3 + 120*ox^2 - 40*ox - 17)*oy^7 + 839124*sqrt(3)*ox^7 - 6006*(1440*sqrt(3)*ox^8 - 1920*sqrt(3)*ox^7 + 672*sqrt(3)*ox^6 + 672*sqrt(3)*ox^5 - 420*sqrt(3)*ox^4 - 280*sqrt(3)*ox^3 - 42*sqrt(3)*ox^2 + 978*sqrt(3)*ox + 873*sqrt(3))*oy^6 + 5243238*sqrt(3)*ox^6 + 27027*(480*ox^8 - 640*ox^7 + 784*ox^6 - 336*ox^5 + 420*ox^4 - 280*ox^3 - 357*ox^2 + 445*ox + 305)*oy^5 + 17459442*sqrt(3)*ox^5 + 30030*(96*sqrt(3)*ox^10 - 160*sqrt(3)*ox^9 + 72*sqrt(3)*ox^8 + 96*sqrt(3)*ox^7 - 84*sqrt(3)*ox^6 - 84*sqrt(3)*ox^5 - 21*sqrt(3)*ox^4 + 978*sqrt(3)*ox^3 + 2619*sqrt(3)*ox^2 + 2907*sqrt(3)*ox + 1181*sqrt(3))*oy^4 + 35465430*sqrt(3)*ox^4 - 15015*(192*ox^10 - 320*ox^9 + 504*ox^8 - 288*ox^7 + 504*ox^6 - 504*ox^5 - 1071*ox^4 + 2670*ox^3 + 5490*ox^2 + 5880*ox + 2575)*oy^3 + 44988216*sqrt(3)*ox^3 - 546*(480*sqrt(3)*ox^12 - 960*sqrt(3)*ox^11 + 528*sqrt(3)*ox^10 + 880*sqrt(3)*ox^9 - 990*sqrt(3)*ox^8 - 1320*sqrt(3)*ox^7 - 462*sqrt(3)*ox^6 + 32274*sqrt(3)*ox^5 + 144045*sqrt(3)*ox^4 + 319770*sqrt(3)*ox^3 + 389730*sqrt(3)*ox^2 + 247188*sqrt(3)*ox + 64501*sqrt(3))*oy^2 + 35217546*sqrt(3)*ox^2 + 819*(160*ox^12 - 320*ox^11 + 616*ox^10 - 440*ox^9 + 990*ox^8 - 1320*ox^7 - 3927*ox^6 + 14685*ox^5 + 50325*ox^4 + 107800*ox^3 + 141625*ox^2 + 96883*ox + 27499)*oy + 15692502*sqrt(3)*ox + 3048839*sqrt(3))*arctan((oy + 1)/(ox + 1)) - 420*(2880*sqrt(3)*ox^14 - 2880*sqrt(3)*oy^14 - 6720*sqrt(3)*ox^13 + 4368*(60*sqrt(3)*ox^2 - 20*sqrt(3)*ox + sqrt(3))*oy^12 + 10080*oy^13 + 4368*sqrt(3)*ox^12 - 6552*(120*ox^2 - 40*ox + 7)*oy^11 + 8736*sqrt(3)*ox^11 - 12012*(240*sqrt(3)*ox^4 - 160*sqrt(3)*ox^3 + 24*sqrt(3)*ox^2 + 8*sqrt(3)*ox - sqrt(3))*oy^10 - 12012*sqrt(3)*ox^10 + 30030*(240*ox^4 - 160*ox^3 + 84*ox^2 - 12*ox + 3)*oy^9 - 20020*sqrt(3)*ox^9 + 9009*(960*sqrt(3)*ox^6 - 960*sqrt(3)*ox^5 + 240*sqrt(3)*ox^4 + 160*sqrt(3)*ox^3 - 60*sqrt(3)*ox^2 - 20*sqrt(3)*ox - sqrt(3))*oy^8 - 9009*sqrt(3)*ox^8 - 27027*(640*ox^6 - 640*ox^5 + 560*ox^4 - 160*ox^3 + 120*ox^2 - 40*ox - 17)*oy^7 + 97812*sqrt(3)*ox^7 - 6006*(1440*sqrt(3)*ox^8 - 1920*sqrt(3)*ox^7 + 672*sqrt(3)*ox^6 + 672*sqrt(3)*ox^5 - 420*sqrt(3)*ox^4 - 280*sqrt(3)*ox^3 - 42*sqrt(3)*ox^2 + 114*sqrt(3)*ox + 9*sqrt(3))*oy^6 + 54054*sqrt(3)*ox^6 + 27027*(480*ox^8 - 640*ox^7 + 784*ox^6 - 336*ox^5 + 420*ox^4 - 280*ox^3 - 357*ox^2 + 157*ox + 17)*oy^5 - 558558*sqrt(3)*ox^5 + 30030*(96*sqrt(3)*ox^10 - 160*sqrt(3)*ox^9 + 72*sqrt(3)*ox^8 + 96*sqrt(3)*ox^7 - 84*sqrt(3)*ox^6 - 84*sqrt(3)*ox^5 - 21*sqrt(3)*ox^4 + 114*sqrt(3)*ox^3 + 27*sqrt(3)*ox^2 - 93*sqrt(3)*ox + 37*sqrt(3))*oy^4 + 1111110*sqrt(3)*ox^4 - 15015*(192*ox^10 - 320*ox^9 + 504*ox^8 - 288*ox^7 + 504*ox^6 - 504*ox^5 - 1071*ox^4 + 942*ox^3 + 306*ox^2 - 336*ox + 71)*oy^3 - 1264536*sqrt(3)*ox^3 - 546*(480*sqrt(3)*ox^12 - 960*sqrt(3)*ox^11 + 528*sqrt(3)*ox^10 + 880*sqrt(3)*ox^9 - 990*sqrt(3)*ox^8 - 1320*sqrt(3)*ox^7 - 462*sqrt(3)*ox^6 + 3762*sqrt(3)*ox^5 + 1485*sqrt(3)*ox^4 - 10230*sqrt(3)*ox^3 + 12210*sqrt(3)*ox^2 - 6948*sqrt(3)*ox + 1565*sqrt(3))*oy^2 + 854490*sqrt(3)*ox^2 + 819*(160*ox^12 - 320*ox^11 + 616*ox^10 - 440*ox^9 + 990*ox^8 - 1320*ox^7 - 3927*ox^6 + 5181*ox^5 + 2805*ox^4 - 6160*ox^3 + 3905*ox^2 - 2173*ox + 683)*oy - 305130*sqrt(3)*ox + 42535*sqrt(3))*arctan((oy + 1)/(ox - 1)) - 1260*(480480*ox^6*(7*sqrt(3) - 12) - 480480*ox^5*(7*sqrt(3) - 12) - 1681680*ox^4*(9*sqrt(3) - 16) + 320320*ox^3*(35*sqrt(3) - 62) + 546*ox^2*(19019*sqrt(3) - 33788) - 546*ox*(8547*sqrt(3) - 15164) - 661947*sqrt(3) + 1167432)*arctan((ox + 1)/(oy - 1)) + 1260*(480480*ox^6*(7*sqrt(3) - 12) - 480480*ox^5*(7*sqrt(3) - 12) - 1681680*ox^4*(9*sqrt(3) - 16) + 320320*ox^3*(35*sqrt(3) - 62) + 546*ox^2*(19019*sqrt(3) - 33788) - 546*ox*(8547*sqrt(3) - 15164) - 661947*sqrt(3) + 1167432)*arctan((ox - 1)/(oy - 1)) - 420*(2880*sqrt(3)*ox^14 - 6720*sqrt(3)*ox^13 + 4368*sqrt(3)*ox^12 + 8736*sqrt(3)*ox^11 - 12012*sqrt(3)*ox^10 - 20020*sqrt(3)*ox^9 - 9009*sqrt(3)*ox^8 + 839124*sqrt(3)*ox^7 + 5243238*sqrt(3)*ox^6 + 17459442*sqrt(3)*ox^5 + 35465430*sqrt(3)*ox^4 + 44988216*sqrt(3)*ox^3 + 35217546*sqrt(3)*ox^2 + 15692502*sqrt(3)*ox + 3048839*sqrt(3))*arctan((oy - 1)/(ox + 1)) + 420*(2880*sqrt(3)*ox^14 - 6720*sqrt(3)*ox^13 + 4368*sqrt(3)*ox^12 + 8736*sqrt(3)*ox^11 - 12012*sqrt(3)*ox^10 - 20020*sqrt(3)*ox^9 - 9009*sqrt(3)*ox^8 + 97812*sqrt(3)*ox^7 + 54054*sqrt(3)*ox^6 - 558558*sqrt(3)*ox^5 + 1111110*sqrt(3)*ox^4 - 1264536*sqrt(3)*ox^3 + 854490*sqrt(3)*ox^2 - 305130*sqrt(3)*ox + 42535*sqrt(3))*arctan((oy - 1)/(ox - 1)) + 105*(13440*(6*sqrt(3)*ox - sqrt(3))*oy^13 - 20160*ox^13 - 43680*(6*ox - 1)*oy^12 + 43680*ox^12 - 17472*(120*sqrt(3)*ox^3 - 60*sqrt(3)*ox^2 + 6*sqrt(3)*ox + sqrt(3))*oy^11 - 91728*ox^11 + 72072*(80*ox^3 - 40*ox^2 + 14*ox - 1)*oy^10 + 72072*ox^10 + 40040*(288*sqrt(3)*ox^5 - 240*sqrt(3)*ox^4 + 48*sqrt(3)*ox^3 + 24*sqrt(3)*ox^2 - 6*sqrt(3)*ox - sqrt(3))*oy^9 - 180180*ox^9 - 270270*(96*ox^5 - 80*ox^4 + 56*ox^3 - 12*ox^2 + 6*ox - 1)*oy^8 + 270270*ox^8 - 10296*(1920*sqrt(3)*ox^7 - 2240*sqrt(3)*ox^6 + 672*sqrt(3)*ox^5 + 560*sqrt(3)*ox^4 - 280*sqrt(3)*ox^3 - 140*sqrt(3)*ox^2 - 14*sqrt(3)*ox + 163*sqrt(3))*oy^7 + 2574*ox^7*(1280*sqrt(3) + 2037) + 3003*(11520*ox^7 - 13440*ox^6 + 14112*ox^5 - 5040*ox^4 + 5040*ox^3 - 2520*ox^2 - 6*ox*(1280*sqrt(3) + 2037) + 1280*sqrt(3) + 3015)*oy^6 - 15015*ox^6*(256*sqrt(3) + 603) + 36036*(320*sqrt(3)*ox^9 - 480*sqrt(3)*ox^8 + 192*sqrt(3)*ox^7 + 224*sqrt(3)*ox^6 - 168*sqrt(3)*ox^5 - 140*sqrt(3)*ox^4 - 28*sqrt(3)*ox^3 + 978*sqrt(3)*ox^2 - 6*ox*(269*sqrt(3) + 960) + 1529*sqrt(3) + 960)*oy^5 - 54054*ox^5*(1024*sqrt(3) + 2097) - 15015*(960*ox^9 - 1440*ox^8 + 2016*ox^7 - 1008*ox^6 + 1512*ox^5 - 1260*ox^4 - 6*ox^3*(1280*sqrt(3) + 2037) + 15*ox^2*(256*sqrt(3) + 603) + 18*ox*(1024*sqrt(3) + 2097) - 3200*sqrt(3) - 2604)*oy^4 + 60060*ox^4*(800*sqrt(3) + 651) - 2184*(960*sqrt(3)*ox^11 - 1760*sqrt(3)*ox^10 + 880*sqrt(3)*ox^9 + 1320*sqrt(3)*ox^8 - 1320*sqrt(3)*ox^7 - 1540*sqrt(3)*ox^6 - 462*sqrt(3)*ox^5 + 26895*sqrt(3)*ox^4 - 330*ox^3*(269*sqrt(3) + 960) + 165*ox^2*(1529*sqrt(3) + 960) + 110*ox*(2693*sqrt(3) + 2688) + 10398*sqrt(3) - 54560)*oy^3 + 4368*ox^3*(21674*sqrt(3) + 20845) + 273*(5760*ox^11 - 10560*ox^10 + 18480*ox^9 - 11880*ox^8 + 23760*ox^7 - 27720*ox^6 - 198*ox^5*(1280*sqrt(3) + 2037) + 825*ox^4*(256*sqrt(3) + 603) + 1980*ox^3*(1024*sqrt(3) + 2097) - 1320*ox^2*(800*sqrt(3) + 651) - 48*ox*(21674*sqrt(3) + 20845) + 209648*sqrt(3) + 661404)*oy^2 - 1092*ox^2*(52412*sqrt(3) + 165351) + 84*(960*sqrt(3)*ox^13 - 2080*sqrt(3)*ox^12 + 1248*sqrt(3)*ox^11 + 2288*sqrt(3)*ox^10 - 2860*sqrt(3)*ox^9 - 4290*sqrt(3)*ox^8 - 1716*sqrt(3)*ox^7 + 139854*sqrt(3)*ox^6 - 2574*ox^5*(269*sqrt(3) + 960) + 2145*ox^4*(1529*sqrt(3) + 960) + 2860*ox^3*(2693*sqrt(3) + 2688) + 156*ox^2*(5199*sqrt(3) - 27280) + 104*ox*(1861*sqrt(3) - 25341) + 706964*sqrt(3) + 591396)*oy - 168*ox*(141116*sqrt(3) + 518115) + 6362176*sqrt(3) + 19152)*log(ox^2 + oy^2 + 2*ox + 2*oy + 2) + 2387385*(16*sqrt(3) - 21)*log(ox^2 + oy^2 + 2*ox - 2*oy + 2) - 765765*(16*sqrt(3) + 21)*log(ox^2 + oy^2 - 2*ox + 2*oy + 2) - 765765*(16*sqrt(3) - 21)*log(ox^2 + oy^2 - 2*ox - 2*oy + 2) - 105*(13440*(6*sqrt(3)*ox - sqrt(3))*oy^13 - 20160*ox^13 - 43680*(6*ox - 1)*oy^12 + 43680*ox^12 - 17472*(120*sqrt(3)*ox^3 - 60*sqrt(3)*ox^2 + 6*sqrt(3)*ox + sqrt(3))*oy^11 - 91728*ox^11 + 72072*(80*ox^3 - 40*ox^2 + 14*ox - 1)*oy^10 + 72072*ox^10 + 40040*(288*sqrt(3)*ox^5 - 240*sqrt(3)*ox^4 + 48*sqrt(3)*ox^3 + 24*sqrt(3)*ox^2 - 6*sqrt(3)*ox - sqrt(3))*oy^9 - 180180*ox^9 - 270270*(96*ox^5 - 80*ox^4 + 56*ox^3 - 12*ox^2 + 6*ox - 1)*oy^8 + 270270*ox^8 - 10296*(1920*sqrt(3)*ox^7 - 2240*sqrt(3)*ox^6 + 672*sqrt(3)*ox^5 + 560*sqrt(3)*ox^4 - 280*sqrt(3)*ox^3 - 140*sqrt(3)*ox^2 - 14*sqrt(3)*ox + 163*sqrt(3))*oy^7 - 2574*ox^7*(1280*sqrt(3) - 2037) + 3003*(11520*ox^7 - 13440*ox^6 + 14112*ox^5 - 5040*ox^4 + 5040*ox^3 - 2520*ox^2 + 6*ox*(1280*sqrt(3) - 2037) - 1280*sqrt(3) + 3015)*oy^6 + 15015*ox^6*(256*sqrt(3) - 603) + 36036*(320*sqrt(3)*ox^9 - 480*sqrt(3)*ox^8 + 192*sqrt(3)*ox^7 + 224*sqrt(3)*ox^6 - 168*sqrt(3)*ox^5 - 140*sqrt(3)*ox^4 - 28*sqrt(3)*ox^3 + 978*sqrt(3)*ox^2 - 6*ox*(269*sqrt(3) - 960) + 1529*sqrt(3) - 960)*oy^5 + 54054*ox^5*(1024*sqrt(3) - 2097) - 15015*(960*ox^9 - 1440*ox^8 + 2016*ox^7 - 1008*ox^6 + 1512*ox^5 - 1260*ox^4 + 6*ox^3*(1280*sqrt(3) - 2037) - 15*ox^2*(256*sqrt(3) - 603) - 18*ox*(1024*sqrt(3) - 2097) + 3200*sqrt(3) - 2604)*oy^4 - 60060*ox^4*(800*sqrt(3) - 651) - 2184*(960*sqrt(3)*ox^11 - 1760*sqrt(3)*ox^10 + 880*sqrt(3)*ox^9 + 1320*sqrt(3)*ox^8 - 1320*sqrt(3)*ox^7 - 1540*sqrt(3)*ox^6 - 462*sqrt(3)*ox^5 + 26895*sqrt(3)*ox^4 - 330*ox^3*(269*sqrt(3) - 960) + 165*ox^2*(1529*sqrt(3) - 960) + 110*ox*(2693*sqrt(3) - 2688) + 10398*sqrt(3) + 54560)*oy^3 - 4368*ox^3*(21674*sqrt(3) - 20845) + 273*(5760*ox^11 - 10560*ox^10 + 18480*ox^9 - 11880*ox^8 + 23760*ox^7 - 27720*ox^6 + 198*ox^5*(1280*sqrt(3) - 2037) - 825*ox^4*(256*sqrt(3) - 603) - 1980*ox^3*(1024*sqrt(3) - 2097) + 1320*ox^2*(800*sqrt(3) - 651) + 48*ox*(21674*sqrt(3) - 20845) - 209648*sqrt(3) + 661404)*oy^2 + 1092*ox^2*(52412*sqrt(3) - 165351) + 84*(960*sqrt(3)*ox^13 - 2080*sqrt(3)*ox^12 + 1248*sqrt(3)*ox^11 + 2288*sqrt(3)*ox^10 - 2860*sqrt(3)*ox^9 - 4290*sqrt(3)*ox^8 - 1716*sqrt(3)*ox^7 + 139854*sqrt(3)*ox^6 - 2574*ox^5*(269*sqrt(3) - 960) + 2145*ox^4*(1529*sqrt(3) - 960) + 2860*ox^3*(2693*sqrt(3) - 2688) + 156*ox^2*(5199*sqrt(3) + 27280) + 104*ox*(1861*sqrt(3) + 25341) + 706964*sqrt(3) - 591396)*oy + 168*ox*(141116*sqrt(3) - 518115) - 5998384*sqrt(3) - 458325)*log(abs(ox^2 + oy^2 + 2*ox - 2*oy + 2)) - 105*(13440*(6*sqrt(3)*ox - sqrt(3))*oy^13 - 20160*ox^13 - 43680*(6*ox - 1)*oy^12 + 43680*ox^12 - 17472*(120*sqrt(3)*ox^3 - 60*sqrt(3)*ox^2 + 6*sqrt(3)*ox + sqrt(3))*oy^11 - 91728*ox^11 + 72072*(80*ox^3 - 40*ox^2 + 14*ox - 1)*oy^10 + 72072*ox^10 + 40040*(288*sqrt(3)*ox^5 - 240*sqrt(3)*ox^4 + 48*sqrt(3)*ox^3 + 24*sqrt(3)*ox^2 - 6*sqrt(3)*ox - sqrt(3))*oy^9 - 180180*ox^9 - 270270*(96*ox^5 - 80*ox^4 + 56*ox^3 - 12*ox^2 + 6*ox - 1)*oy^8 + 270270*ox^8 - 10296*(1920*sqrt(3)*ox^7 - 2240*sqrt(3)*ox^6 + 672*sqrt(3)*ox^5 + 560*sqrt(3)*ox^4 - 280*sqrt(3)*ox^3 - 140*sqrt(3)*ox^2 - 14*sqrt(3)*ox + 19*sqrt(3))*oy^7 + 2574*ox^7*(1280*sqrt(3) + 2037) + 3003*(11520*ox^7 - 13440*ox^6 + 14112*ox^5 - 5040*ox^4 + 5040*ox^3 - 2520*ox^2 - 6*ox*(1280*sqrt(3) + 2037) + 1280*sqrt(3) + 2151)*oy^6 - 3003*ox^6*(1280*sqrt(3) + 2151) + 36036*(320*sqrt(3)*ox^9 - 480*sqrt(3)*ox^8 + 192*sqrt(3)*ox^7 + 224*sqrt(3)*ox^6 - 168*sqrt(3)*ox^5 - 140*sqrt(3)*ox^4 - 28*sqrt(3)*ox^3 + 114*sqrt(3)*ox^2 - 6*ox*(557*sqrt(3) + 960) + 529*sqrt(3) + 960)*oy^5 - 54054*ox^5*(1024*sqrt(3) + 1809) - 15015*(960*ox^9 - 1440*ox^8 + 2016*ox^7 - 1008*ox^6 + 1512*ox^5 - 1260*ox^4 - 6*ox^3*(1280*sqrt(3) + 2037) + 3*ox^2*(1280*sqrt(3) + 2151) + 18*ox*(1024*sqrt(3) + 1809) - 3200*sqrt(3) - 5712)*oy^4 + 240240*ox^4*(200*sqrt(3) + 357) - 2184*(960*sqrt(3)*ox^11 - 1760*sqrt(3)*ox^10 + 880*sqrt(3)*ox^9 + 1320*sqrt(3)*ox^8 - 1320*sqrt(3)*ox^7 - 1540*sqrt(3)*ox^6 - 462*sqrt(3)*ox^5 + 3135*sqrt(3)*ox^4 - 330*ox^3*(557*sqrt(3) + 960) + 165*ox^2*(529*sqrt(3) + 960) + 110*ox*(1549*sqrt(3) + 2688) - 31958*sqrt(3) - 54560)*oy^3 + 8736*ox^3*(10837*sqrt(3) + 19030) + 273*(5760*ox^11 - 10560*ox^10 + 18480*ox^9 - 11880*ox^8 + 23760*ox^7 - 27720*ox^6 - 198*ox^5*(1280*sqrt(3) + 2037) + 165*ox^4*(1280*sqrt(3) + 2151) + 1980*ox^3*(1024*sqrt(3) + 1809) - 5280*ox^2*(200*sqrt(3) + 357) - 96*ox*(10837*sqrt(3) + 19030) + 209648*sqrt(3) + 364236)*oy^2 - 1092*ox^2*(52412*sqrt(3) + 91059) + 84*(960*sqrt(3)*ox^13 - 2080*sqrt(3)*ox^12 + 1248*sqrt(3)*ox^11 + 2288*sqrt(3)*ox^10 - 2860*sqrt(3)*ox^9 - 4290*sqrt(3)*ox^8 - 1716*sqrt(3)*ox^7 + 16302*sqrt(3)*ox^6 - 2574*ox^5*(557*sqrt(3) + 960) + 2145*ox^4*(529*sqrt(3) + 960) + 2860*ox^3*(1549*sqrt(3) + 2688) - 156*ox^2*(15979*sqrt(3) + 27280) - 104*ox*(13873*sqrt(3) + 25341) + 326068*sqrt(3) + 591396)*oy - 168*ox*(141116*sqrt(3) + 256659) + 5998384*sqrt(3) + 10926783)*log(abs(ox^2 + oy^2 - 2*ox + 2*oy + 2)) + 105*(13440*(6*sqrt(3)*ox - sqrt(3))*oy^13 - 20160*ox^13 - 43680*(6*ox - 1)*oy^12 + 43680*ox^12 - 17472*(120*sqrt(3)*ox^3 - 60*sqrt(3)*ox^2 + 6*sqrt(3)*ox + sqrt(3))*oy^11 - 91728*ox^11 + 72072*(80*ox^3 - 40*ox^2 + 14*ox - 1)*oy^10 + 72072*ox^10 + 40040*(288*sqrt(3)*ox^5 - 240*sqrt(3)*ox^4 + 48*sqrt(3)*ox^3 + 24*sqrt(3)*ox^2 - 6*sqrt(3)*ox - sqrt(3))*oy^9 - 180180*ox^9 - 270270*(96*ox^5 - 80*ox^4 + 56*ox^3 - 12*ox^2 + 6*ox - 1)*oy^8 + 270270*ox^8 - 10296*(1920*sqrt(3)*ox^7 - 2240*sqrt(3)*ox^6 + 672*sqrt(3)*ox^5 + 560*sqrt(3)*ox^4 - 280*sqrt(3)*ox^3 - 140*sqrt(3)*ox^2 - 14*sqrt(3)*ox + 19*sqrt(3))*oy^7 - 2574*ox^7*(1280*sqrt(3) - 2037) + 3003*(11520*ox^7 - 13440*ox^6 + 14112*ox^5 - 5040*ox^4 + 5040*ox^3 - 2520*ox^2 + 6*ox*(1280*sqrt(3) - 2037) - 1280*sqrt(3) + 2151)*oy^6 + 3003*ox^6*(1280*sqrt(3) - 2151) + 36036*(320*sqrt(3)*ox^9 - 480*sqrt(3)*ox^8 + 192*sqrt(3)*ox^7 + 224*sqrt(3)*ox^6 - 168*sqrt(3)*ox^5 - 140*sqrt(3)*ox^4 - 28*sqrt(3)*ox^3 + 114*sqrt(3)*ox^2 - 6*ox*(557*sqrt(3) - 960) + 529*sqrt(3) - 960)*oy^5 + 54054*ox^5*(1024*sqrt(3) - 1809) - 15015*(960*ox^9 - 1440*ox^8 + 2016*ox^7 - 1008*ox^6 + 1512*ox^5 - 1260*ox^4 + 6*ox^3*(1280*sqrt(3) - 2037) - 3*ox^2*(1280*sqrt(3) - 2151) - 18*ox*(1024*sqrt(3) - 1809) + 3200*sqrt(3) - 5712)*oy^4 - 240240*ox^4*(200*sqrt(3) - 357) - 2184*(960*sqrt(3)*ox^11 - 1760*sqrt(3)*ox^10 + 880*sqrt(3)*ox^9 + 1320*sqrt(3)*ox^8 - 1320*sqrt(3)*ox^7 - 1540*sqrt(3)*ox^6 - 462*sqrt(3)*ox^5 + 3135*sqrt(3)*ox^4 - 330*ox^3*(557*sqrt(3) - 960) + 165*ox^2*(529*sqrt(3) - 960) + 110*ox*(1549*sqrt(3) - 2688) - 31958*sqrt(3) + 54560)*oy^3 - 8736*ox^3*(10837*sqrt(3) - 19030) + 273*(5760*ox^11 - 10560*ox^10 + 18480*ox^9 - 11880*ox^8 + 23760*ox^7 - 27720*ox^6 + 198*ox^5*(1280*sqrt(3) - 2037) - 165*ox^4*(1280*sqrt(3) - 2151) - 1980*ox^3*(1024*sqrt(3) - 1809) + 5280*ox^2*(200*sqrt(3) - 357) + 96*ox*(10837*sqrt(3) - 19030) - 209648*sqrt(3) + 364236)*oy^2 + 1092*ox^2*(52412*sqrt(3) - 91059) + 84*(960*sqrt(3)*ox^13 - 2080*sqrt(3)*ox^12 + 1248*sqrt(3)*ox^11 + 2288*sqrt(3)*ox^10 - 2860*sqrt(3)*ox^9 - 4290*sqrt(3)*ox^8 - 1716*sqrt(3)*ox^7 + 16302*sqrt(3)*ox^6 - 2574*ox^5*(557*sqrt(3) - 960) + 2145*ox^4*(529*sqrt(3) - 960) + 2860*ox^3*(1549*sqrt(3) - 2688) - 156*ox^2*(15979*sqrt(3) - 27280) - 104*ox*(13873*sqrt(3) - 25341) + 326068*sqrt(3) - 591396)*oy + 168*ox*(141116*sqrt(3) - 256659) - 5998384*sqrt(3) + 10926783)*log(abs(ox^2 + oy^2 - 2*ox - 2*oy + 2)) + 7005083904*sqrt(3)*ox + 575093376*sqrt(3))/pi

```python
import numpy as np
xs = np.linspace(-1.99, 1.99, 100)
ys = [float(If.subs(ox==xv, oy==0.5)) for xv in xs]
import matplotlib.pyplot as plt
plt.plot(xs, ys)
plt.show()
```

```python
r, theta = var('r, theta')
ox, oy = chebyshev_pts[0], chebyshev_pts[1]
T1 = atan2(-1-oy, 1-ox)
T2 = atan2(1-oy, 1-ox)
T1.subs(ox==0, oy==0), T2.subs(ox==0, oy==0)
```

    (arctan(1/4*sqrt(3) - 1/2), arctan(1/4*sqrt(3) + 1/2))

```python

assume(T1 < theta < T2)
assume(cos(theta) > 0)
Kbr = (basis_functions[0].subs(x==sx) * basis_functions[1].subs(x == sy)).full_simplify() * log(r)
Kbrt = Kbr.subs(sx==ox+r*cos(theta), sy==oy+r*sin(theta))
It = integrate(Kbrt * r, r, 0, (1-ox) / cos(theta))
```

```python
It
```

    2/945*sqrt(3)*log(2/cos(theta))*sin(theta)/cos(theta)^3 + 416/891*sqrt(3)*log(2/cos(theta))*sin(theta)^3/cos(theta)^5 + 12160/11583*sqrt(3)*log(2/cos(theta))*sin(theta)^5/cos(theta)^7 - 376/2835*log(2/cos(theta))*sin(theta)^2/cos(theta)^4 - 1088/567*log(2/cos(theta))*sin(theta)^4/cos(theta)^6 - 237056/405405*log(2/cos(theta))*sin(theta)^6/cos(theta)^8 - 47/595350*sqrt(3)*sin(theta)/cos(theta)^3 + 72176/617463*sqrt(3)*sin(theta)^3/cos(theta)^5 + 1984144/104351247*sqrt(3)*sin(theta)^5/cos(theta)^7 + 1/378/cos(theta)^2 - 3854/178605*sin(theta)^2/cos(theta)^4 - 494248/1964655*sin(theta)^4/cos(theta)^6 + 693363392/18261468225*sin(theta)^6/cos(theta)^8

```python

integrate(It, theta, T1, T2)
```

```python

integrate(Kb.subs(sx==ox+r*cos(theta), sy==oy+r*sin(theta)), theta, 0, 2*pi)
```

```python
Ir = _
```

```python
integrate(Ir, r, 0, 1)
```

    1/876550474800*sqrt(3)*(11778624*(352800*sqrt(3)*ox^6 - 352800*sqrt(3)*ox^5 - 58800*sqrt(3)*ox^4 + 156800*sqrt(3)*ox^3 + 27930*sqrt(3)*ox^2 - 33810*sqrt(3)*ox + 633*sqrt(3))*oy^6 + 6301563840*sqrt(3)*ox^6 - 17667936*(352800*ox^6 - 352800*ox^5 - 58800*ox^4 + 156800*ox^3 + 27930*ox^2 - 33810*ox + 633)*oy^5 - 6301563840*sqrt(3)*ox^5 - 4907760*(352800*sqrt(3)*ox^6 - 352800*sqrt(3)*ox^5 - 423360*sqrt(3)*ox^4 + 399840*sqrt(3)*ox^3 + 89514*sqrt(3)*ox^2 - 78642*sqrt(3)*ox + 67*sqrt(3))*oy^4 + 2291923920*sqrt(3)*ox^4 + 2453880*(1764000*ox^6 - 1764000*ox^5 - 1023120*ox^4 + 1270080*ox^3 + 262818*ox^2 - 258714*ox + 2033)*oy^3 + 572572000*sqrt(3)*ox^3 + 8112*(29882160*sqrt(3)*ox^6 - 29882160*sqrt(3)*ox^5 - 64294560*sqrt(3)*ox^4 + 52823760*sqrt(3)*ox^3 + 8025930*sqrt(3)*ox^2 - 8704740*sqrt(3)*ox + 34099*sqrt(3))*oy^2 + 1112402616*sqrt(3)*ox^2 - 12168*(59764320*ox^6 - 59764320*ox^5 - 48112020*ox^4 + 51996120*ox^3 + 9722955*ox^2 - 9934705*ox + 72189)*oy - 585597168*sqrt(3)*ox + 860297*sqrt(3))

```python

```


## Last Class:

* MAP estimates

* Beta distribution: Conjugate prior for a Bernoulli/Binomial likelihood.

# LINEAR REGRESSION

## Topics

* $ MSE = Bias^2 + Variance $

* Gauss Markov Theorem

### Question 1

* Show $ E (b) = \beta $ under the assumption that $ y_i = \alpha + \beta  x_i + \epsilon_i$ where $ \epsilon_i \sim N(0, \sigma^2)$. Thus show that least square estimators (a & b) are unbiased.

## Relationship of bias and variance with MSE

Mean Square Error measure the "average" distance of the parameter estimate from its true value.

### Question 2
Prove that:

$$ \begin{align}
\operatorname{MSE_{\theta}}(\hat{\theta}) &= \operatorname{E}_{X|\theta} \left [(\hat{\theta}-\theta)^2 \right ] \\
&= \operatorname{Var}_{\theta}(\hat\theta)+ \operatorname{Bias}_{\theta}(\hat\theta)^2
\end{align} $$

[Hint Use the fact that $ Var(X) = E[X^2] - E[X]^2 $]

## Gauss Markov Theorem

If:

* The expected average value of residuals is 0. ($ E(\epsilon_i ) = 0 $)

* The spread of residuals is constant and finite for all $ X_i (Var(\epsilon_i  ) = \sigma^2 $ )

* There is no relationship amongst the residuals ( $ cov(\epsilon_i , \epsilon_j ) = 0 $)

* There is no relationship between the residuals and the $ X_i (cov(X_i , \epsilon_i ) = 0 $)

Then, least square estimates have lowest variance amongst all linear unbiased estimates.

Note: Our assumption that $ y_i = \alpha + \beta  x_i + \epsilon_i$ where $ \epsilon_i \to N(0, \sigma^2)$ is a special case of the Gauss Markov theorem. (We additionally, assume that the $epsilon_i$ are normal distributed)

### Proof:

Let the regression line be $ Y = b_{0} + b_{1}X$.
Least square estimates of coefficients are given by:
$$
b_{1} = \frac{\sum_{i}{(x_{i}-\bar{x})(y_{i}-\bar{y})}}{\sum_{i}{(x_{i}-\bar{x})^{2}}} = \sum_{i}{K_{i}Y_{i}}
$$

where,
$$
K_{i} =  \frac{(x_{i}-\bar{x})}{\sum_{i}{(x_{i}-\bar{x})^{2}}}
$$

and
$$
Y_{i} = y_{i}-\bar{y}
$$

And the other coefficient is given by,
$$
b_{0} = \bar{y} - b_{1}\bar{x}
$$

Now first calculate variance of $b_{1}$,

\begin{align*}
\sigma^{2}(b_{1})= & \sigma^{2}(\sum_{i}{K_{i}Y_{i}}) \\
                 = & \sum_{i}{K_{i}^{2}\sigma^{2}(Y_{i})} .... (Why?)\\
                 = & \sigma^{2} * \sum_{i}{\frac{1}{(x_{i}-\bar{x})^{2}}}
\end{align*}

Here $\sigma^{2}$ is the variance of each $Y_{i}$. \\
Now consider another estimator of $\beta_{1}$ as $\hat{\beta_{1}}$.\\
Let,

$$
\hat{\beta_{1}} = \sum_{i}{c_{i}y_{i}}
$$

for some $c_{i}$.

Now consider expected value and variance of this estimator.

\begin{align*}
E(\hat{\beta_{1}}) = & \sum_{i}{c_{i}E(y_{i})} \\
                   = & \sum_{i}{c_{i}E(\beta_{0} + \beta_{1}x_{i})} \\
                   = & \beta_{0}\sum_{i}{c_{i}} + \beta_{1}\sum_{i}{c_{i}x_{i}}
\end{align*}

As $\hat{\beta_{1}}$ is an unbiased estimator, $E(\hat{\beta_{1}}) = \beta_{1}$ for generic values of $x_{i}$. \\
So from above expression we can get conditions on $c_{i}$'s as\\
$\sum_{i}{c_{i}}=0$ and \\
$\sum_{i}{c_{i}x_{i}}=1$

Variance of the estimator is given by,
\begin{align*}
\sigma^{2}(\hat{\beta_{1}}) = & \sum_{i}{c_{i}\sigma^{2}(y_{i})} \\
= & \sigma^{2}\sum_{i}{c_{i}^{2}}
\end{align*}
Let $c_{i} = K_{i} + d_{i}$ for some $d_{i}$. Then we can write,

\begin{align*}
\sigma^{2}(\hat{\beta_{1}}) = & \sigma^{2}*(\sum_{i}{( K_{i} + d_{i})^{2}}) \\
= & \sigma^{2}*(\sum_{i}{K_{i}^{2}} + \sum_{i}{d_{i}^{2}} + 2\sum_{i}{K_{i}d_{i}}) \\
= & \sigma^{2}\sum_{i}{K_{i}^{2}} + \sigma^{2}\sum_{i}{d_{i}^{2}} + 2\sigma^{2}\sum_{i}{K_{i}d_{i}} \\
= & \sigma^{2}(b_{1}) + \sigma^{2}\sum_{i}{d_{i}^{2}} + 2\sigma^{2}\sum_{i}{K_{i}d_{i}}      .................. (\sigma^{2}\sum_{i}{K_{i}^{2}} = \sigma^{2}(b_{1}))
\end{align*}
Now consider the expression $\sum_{i}{K_{i}d_{i}}$.

\begin{align*}
\sum_{i}{K_{i}d_{i}} = & \sum_{i}{K_{i}(c_{i} - K_{i})} \\
= & \sum_{i}{K_{i}c_{i}} - \sum_{i}{K_{i}^{2}} \\
= & \sum_{i}{c_{i}(\frac{(x_{i}-\bar{x})}{\sum_{i}{(x_{i}-\bar{x})^{2}}})} - \frac{1}{(x_{i}-\bar{x})^{2}} \\
= & \frac{\sum_{i}{c_{i}x_{i}} - \sum_{i}{c_{i}} - 1 }{\sum_{i}{(x_{i}-\bar{x})^{2}}}
\end{align*}
We know that $\sum_{i}{c_{i}x_{i}} = 1$ and $\sum_{i}{c_{i}} = 0$ as $\beta_{1}$ is an unbiased estimator (derived above). So substituting these values in above equation,

\begin{align*}
\sum_{i}{K_{i}d_{i}} = & \frac{1 - 0 - 1}{\sum_{i}{(x_{i}-\bar{x})^{2}}} \\
= & 0 ........................................(*)
\end{align*}
Therefore we get,

\begin{align*}
\sigma^{2}(\hat{\beta_{1}}) = & \sigma^{2}(b_{1}) + \sigma^{2}\sum_{i}{d_{i}^{2}} + 2*0 \\
= & \sigma^{2}(b_{1}) + \sigma^{2}\sum_{i}{d_{i}^{2}} \\
\geq & \sigma^{2}(b_{1})
\end{align*}

Thus, the least square estimate is the most **efficient** one amongst unbiased estimators.

## Linear Regression: Summary

* Minimizing the Mean squared loss function, L is the same as minimizing the (conditional) negative log likelihood (Maximizing the likelihood) under the assumption that $ Y|X \sim \alpha + \beta X + \epsilon ; \quad \epsilon \sim N(0, \sigma^2) $

* Thus $$ b = \frac{\sum{x'_i y'_i}}{\sum{x'_i}^2} = \frac{sample \; covariance \; between \; x \; and \; y} {sample \; variance \; of \; x} $$

$$ a = \bar{y} - b \bar{x} $$ correspond to MLE estimates with the above assumption

* Both the above estimates are unbiased.

* The Gauss Markow theorem states that amongst unbiased estimates, the above estimates have the least variance and are thus the most efficient ones. **BLUE - Best Linear Unbiased Estimator **

Further reading: https://people.eecs.berkeley.edu/~jegonzal/assets/slides/linear_regression.pdf

### Multivariate Linear Regression

http://faculty.cas.usf.edu/mbrannick/regression/Reg2IV.html


# Introduction to Programming and Numerical Analysis - Inaugural Project Spring 2020

**Team:** Kongerækken

**Members:** Frederik Degn Pedersen (qwn116) & Christian Brauer Johanssen (sjk185)

**Imports and set magics:**

```python
import numpy as np
from scipy import optimize
import matplotlib.pyplot as plt
plt.style.use("seaborn")

# autoreload modules when code is run
%load_ext autoreload
%autoreload 2

# local modules
import inauguralproject
```

# Question 1

We consider a consumer solving the following maximisation problem

$$
\begin{aligned}
U^* = U(c^*,l^*) & = \text{arg}\max_{c,l}\log(c)-\nu\frac{l^{1+\frac{1}{\epsilon}}}{1 + \frac{1}{\epsilon}}\\
& \text{s.t.}\\
x & = m+wl-[\tau_{0}wl + \tau_{1} \max \{wl-\kappa, 0\}]\\
c &\in [0, x]\\
l &\in [0, 1],
\end{aligned}
$$

where $c$ is consumption, $l$ is labour supply, $m$ is cash-on-hand, $w$ is the wage rate, $\tau_0$ is the standard labour income tax, $\tau_1$ is the top bracket labour income tax, $\kappa$ is the cut-off for the top labour income bracket, $x$ is total resources, $\nu$ scales the disutility of labour, and $\epsilon$ is the Frisch elasticity of labour supply.

Utility is monotonically increasing in consumption, which implies that

$$
\begin{align}
c^* & = x
\end{align}
$$

Thus, inserting for c and subsequently for x yields the following univariate maximisation problem with only one constraint:

$$
\begin{aligned}
U^* & = \text{arg}\max_{l}\log(m+wl-[\tau_{0}wl + \tau_{1} \max \{wl-\kappa, 0\}])-\nu\frac{l^{1+\frac{1}{\epsilon}}}{1 + \frac{1}{\epsilon}}\\
& \text{s.t. }l \in [0, 1]
\end{aligned}
$$

The above utility function as well as the optimising function used to solve the maximisation problem are defined in the module.

```python
# a. set parameters
m = 1
nu = 10
eps = 0.3
tau0 = 0.4
tau1 = 0.1
kappa = 0.4
w = 1

# b. compute optimal labour and consumption
l_star, c_star, u_star = inauguralproject.u_optimiser(eps,kappa,nu,m,tau0,tau1,w)

# c. print solution for assigned parameter values
print(f'The agent will choose optimal labour = {l_star:.2f}, which implies optimal consumption = {c_star:.2f} and utility = {u_star:.2f}')
```

    The agent will choose optimal labour = 0.40, which implies optimal consumption = 1.24 and utility = 0.17

# Question 2

First we create a numpy array of wage values between 0.5 and 1.5 and two corresponding empty arrays in which to append the values for labour and consumption choice. Next we loop our user defined optimiser function over the wage values and store the results in the initially empty numpy arrays l_vals and c_vals. Finally we plot the two figures using a function defined in the corresponding module.

```python
# a. create array of w and container for values of l and c
N = 100
w = np.linspace(0.5,1.5,num=N)
l_vals = np.empty(N)
c_vals = np.empty(N)

# b. loop the optimiser over the w array
for i,wi in enumerate (w):
    lc = inauguralproject.u_optimiser(eps,kappa,nu,m,tau0,tau1,wi)

    l_vals[i] = lc[0]
    c_vals[i] = lc[1]

# c. plot the figure
inauguralproject.two_figures(w, l_vals, "Labour", "$w$", "$l$", w, c_vals, "Consumption", "$w$", "$c$")
```

# Question 3

In the module, we define a function which calculates the total tax revenue given parameters and the previously defined utility function.

```python
# set parameter values
seed = 97
size = 10000
low = 0.5
high = 1.5

# compute total tax revenue
total_tax_rev = inauguralproject.tax_revenue(seed,size,low,high)

print(f'The total tax revenue is {total_tax_rev:.2f}')
```

    The total tax revenue is 1633.01

# Question 4

We merely run the function from question 4 again with $\epsilon = 0.1$:

```python
# run tax_revenue function again with new value of eps
total_tax_rev = inauguralproject.tax_revenue(seed,size,low,high,eps=0.1)

print(f'The total tax revenue with Frisch elasticity = 0.1 is {total_tax_rev:.2f}')
```

    The total tax revenue with Frisch elasticity = 0.1 is 3200.94

# Question 5

In this question, we return to $\epsilon = 0.3$. We first define an objective function in order to subsequently maximize the tax revenue for the parameters in question.

```python
# list of parameters
params = [tau0,tau1,kappa]

# objective function
def objective_tax(params,seed,size,low,high):
    """
    Objective function version of total tax revenue. Params is a list that contains [t0,t1,kappa].
    See docstring of total_tax_rev for input description of remaining variables.

    """
    return -(inauguralproject.tax_revenue(seed,size,low,high,tau0=params[0],tau1=params[1],kappa=params[2]))
```

```python
# initial guess
init_guess = [0.4,0.1,0.4] # same as assignment text

# solve for optimal tax parameters
tax_params = optimize.minimize(objective_tax,x0=init_guess,method='SLSQP',
                  args=(seed,size,low,high), bounds= [(0,1),(0,1),(0,1)])

# unpack and print solution
tau0_star = tax_params.x[0]
tau1_star = tax_params.x[1]
kappa_star = tax_params.x[2]

print(f'The optimal standard tax is = {tau0_star:.4f}')
print(f'The optimal top bracket tax is = {tau1_star:.4f}')
print(f'The optimal cut off for top bracket tax is = {kappa_star:.4f}')
print(f'Expected optimal total tax revenue is {-tax_params.fun:.2f}')
```

    The optimal standard tax is = 0.7855
    The optimal top bracket tax is = 0.0000
    The optimal cut off for top bracket tax is = 0.0010
    Expected optimal total tax revenue is 2470.43

# Conclusion

In this assignment we have solved a consumer utility maximisation problem with respect to consumption and labour choice. When plotting optimal consumption and labour choices for a wage range between 0.5 and 1.5, we observe that there is a kink in the labour supply curve (i.e. continuity is violated, which is the reason why the problem cannot be solved analytically). Moreover, in a small interval around $w = 1$, consumption is constant and wage increases merely lead to reduced labour supply. This is a consequence of the top income bracket labour tax being effective from the moment where income ($w_i l^*$) exceeds the cutoff value ($\kappa=0.4$).

From question 3 and 4, we can conclude that when the Frisch elasticity of labour decreases, the tax revenue increases. This is because labour supply becomes more inelastic, which implies that other things equal the agents are willing to supply more labour (in the limit they supply their whole time endowment) for a given wage rate. A larger labour supply is equivalent with a larger tax base.

At last, we find that for the politician to maximize the expected revenue, she should discard the top bracket tax and just increase standard income tax to 79%. How about that for a Laffer curve.


# Additive Secret Sharing

Author:
- Carlos Salgado - [email](mailto:csalgado@uwo.ca) - [linkedin](https://www.linkedin.com/in/eng-socd/) - [github](https://github.com/socd06)

## Additive Secret Sharing
Additive Secret Sharing is a mechanism to share data among parties and to perform computation on it.

## Sharing
A secret `s` is uniformly split into `n` shares, one per shareholder (also known as worker, node, user or party) using some randomness `r`, also known as some **very high random prime** number `Q`.

$ F_s (s, r, n) = ( s_1, s_2, ..., s_n ) $

## Reconstruction
`s` can be reconstructed (decrypted) by adding up **all the shares** and taking the [*modulo*](https://en.wikipedia.org/wiki/Modulo_operation) of the random prime number `Q`, used to encrypt the shares originally.

$ s = ( \: \sum \limits _{i=1} ^n s_i \: ) \; mod \; Q $

## 32-bit Integer Secrets
A secret is the data or message that a party wants to secure. In additive secret sharing, secrets (and therefore, shares) must be members of a fixed [finite field](https://en.wikipedia.org/wiki/Finite_field). Particularly, the literature mentions shares should be members of the $ {\mathbb{Z}_{2^{32}}} $ [ring](https://en.wikipedia.org/wiki/Ring_(mathematics)), which is the [ring of integers](https://en.wikipedia.org/wiki/Ring_of_integers) that fit within [32-bits](https://en.wikipedia.org/wiki/32-bit_computing).

Rings are [sets](https://en.wikipedia.org/wiki/Set_(mathematics)) with two operations, addition and multiplication, which allow the rationale of secret sharing and reconstruction to work.

Plainly, secrets and secret shares **must** be integers within -2,147,483,647 to +2,147,483,647

## Governance
Additive secret sharing provides shared governance. The threshold `t` to reconstruct `s` is equal to `n`, which means **no party can recover the data** alone because all the shares are required to decrypt the secret *(t = n)*. This scheme allows us to do computation on the shares while each shareholder is only aware of their **own** share.

### [Quiz] Find the secret `s`

In practice, we use a **very high prime number** Q to add a **big deal of uniform randomness** to our shares. Here we will use a very small Q, so you can try to solve the quiz without programming yet.

Let $ s_1 = 10 \; and \; s_2 = 74 \; and \; Q = 59 $

What is the original secret `s`? Fill the ____ space below with your answer.
Try **not** to use a calculator or programming.

```python
# Run this cell to import the quizzes
from quiz import q0, q1, q2
```

```python
# run to check your answer
q0.check(___)
```

```python
# Uncomment the line below to see a hint
# q0.hint
```

```python
# Uncomment the line below to see the solution
# q0.solution
```

### [Quiz] Find the final share s2

Using a small `Q` to facilitate calculation (it needs to be a **very high prime number** in production), let

$ s = 7, n = 2 $ with $ Q = 59 $ and $ s_1 = 9 $
plugged in on the secret reconstruction equation, find the final share s2.

Fill the ____ space below with your answer. Feel free to implement the equation in a new cell or use whatever tool you'd like (e.g. a calculator), it's your call.

```python
# Fill the ____ space below with your answer
final_share =

# run to check your answer
q1.check(final_share)
```

```python
# Uncomment the line below to see a hint
# q1.hint
```

```python
# Uncomment the line below to see the solution
# q1.solution
```

## In Practice
Just as an educational example, we can generate a list of prime numbers using [sympy](https://www.sympy.org/en/index.html)

```python
# Verify we have all the tools we need to run the notebook
!pip install -r requirements.txt
```

```python
import sympy

# An arbitrary constant, feel free to play with it
CONST = 999

BIT_DEPTH = 31

# Range start
start = 2**BIT_DEPTH-CONST

# Maximum in Z2**32 ring
end = 2**BIT_DEPTH

prime_lst = list(sympy.primerange(start,end+1))

print("Prime numbers in range: " , prime_lst)
```

And **randomly** choose one every time using [NumPy](https://numpy.org/devdocs/contents.html)'s [randint](https://numpy.org/doc/stable/reference/random/generated/numpy.random.randint.html)

```python
from numpy.random import randint

Q = prime_lst[randint(len(prime_lst))]
Q
```

As an additional note, the [Secrets module](https://docs.python.org/3/library/secrets.html), introduced in Python 3.6, provides randomness as secure as your operating system.

```python
import secrets

Q = secrets.choice(prime_lst)
Q
```

## The Final Share and 2-party Additive Secret Sharing

Knowing that $ s_n = Q - (\;  \sum \limits _{i=1} ^{n-1} s_i \; mod \; Q \; ) + s $

How do we implement 2-party ($ n=2 $) additive secret sharing using Python?

Keep reading and fing out!

```python
def dual_share(s, r):
    '''
    s = secret
    r = randomness
    '''
    share_lst = list()
    share_lst.append(randint(0,r))

    final_share = r - (share_lst[0] % r) + s

    share_lst.append(final_share)

    return share_lst
```

```python
# Let's generate a couple of shares
secret = 5

dual_shares = dual_share(secret, Q)
dual_shares
```

Now go back to the previous cell and **run it again**. Notice anything?

...

...

...

See it yet? The shares are never the same because they are **randomly generated**.

Now let's implement the reconstruction (or decryption) function.

```python
def decrypt(shares, r):
    '''
    shares = iterable made of additive secret shares
    r = randomness
    '''
    return sum(shares) % r
```

```python
# And let's decrypt our secret for the first time
decrypt(dual_shares, Q)
```

## Exercise: Implement n-party additive secret sharing
Fill the function below with your code.

```python
def n_share(s, r, n):
    '''
    s = secret
    r = randomness
    n = number of nodes, workers or participants

    returns a tuple of n-shares
    '''
    # replace with your code
    pass
```

```python
five_shares = n_share(s=686,r=Q,n=5)
five_shares

# run this cell to check your solution
q2.check(decrypt(five_shares, Q))
```

```python
# Uncomment the line below to see a hint
# q2.hint
```

```python
# Uncomment the line below to see the solution
# q2.solution
```

## Addition
Given two shared values $a$ and $b$, a party $P_i$ can compute the added shares as:
$ c_i = ( a_i + b_i ) \; mod \; Q$

In Python, we can implement this type of addition like this:

```python
def addition(a, b, r):
    '''
    a = iterable of the same length of b
    b = iterable of the same length of a
    r = randomness AKA randomly generated very high prime number
    '''
    c = list()

    for i in range(len(a)):
        c.append((a[i] + b[i]) % r)

    return tuple(c)
```

Considering Alice and Bob are our parties, with secrets $s_a$ and $s_b$ to be shared (2-way) and wanting to compute addition.

Let $s_a = 5 $ and $s_b = 11 $

Alice's shares would be something like:

```python
# Alice's secret
sa = 5

alice_shares = dual_share(sa, Q)
alice_shares
```

While Bob's shares would be

```python
# Bob's secret
sb = 11

bob_shares = dual_share(sb, Q)
bob_shares
```

```python
secret_sum = addition(alice_shares, bob_shares, Q)
secret_sum
```

Doesn't make a lot of sense, does it?

Secret shares must only reveal information about their secrets when they are all combined. Otherwise all data must be hidden, which defines the **privacy** property.

These are still secret shares so there is one more step to get the sum of the original secrets.

```python
decrypt(secret_sum, Q)
```

Et Voilà!

## Public (scalar) Multiplication
Given a list of shared values $a$ and a **scalar** $b$, a party $P_i$ can compute the multiplied shares as:
$ c_i = a_i \times b \; mod \; Q$

In Python, we can implement this type of multiplication like this:

```python
def public_mul(a, b, r):
    '''
    a = iterable of the same length of b
    b = scalar to multiply a by
    r = randomness AKA randomly generated very high prime number
    '''
    c = list()

    for i in range(len(a)):
        c.append((a[i] * b) % r)

    return tuple(c)
```

Let's say another party wants to multiply Alice's shares by the **scalar** value of 3.

```python
alice_times3 = public_mul(alice_shares, 3, Q)
```

Then we can decrypt (with Alice's permission) to double check we did multiply what we intended.

```python
decrypt(alice_times3,Q)
```

And this is `True` because Alice's secret $sa = 5$, remember?

```python
decrypt(alice_times3,Q) == sa * 3
```

## PyTorch + PySyft implementation
Now that you know how additive secret sharing works under the hood, let's see how we can leverage PyTorch and PySyft to do it for us.

```python
import torch
import syft as sy
hook = sy.TorchHook(torch)
```

Let's say Alice, Bob and Charlie are all enrolled on the **Foundations of Privacy** course and we, as instructors, want to know on average, how far in the course they are. We don't want to breach their privacy so each percentage of completion will be their own secret (a, b and c).

For educational purposes, we will define our parties (nodes, workers, etc) using `VirtualWorker` PySyft objects.

```python
alice = sy.VirtualWorker(hook, id="alice")
bob = sy.VirtualWorker(hook, id="bob")
charlie = sy.VirtualWorker(hook, id="charlie")
```

We also need a "secure worker", also known as the `Crypto Provider` to provide us with random prime numbers.

```python
secure_worker = sy.VirtualWorker(hook, "secure_worker")
```

We define our secrets using `torch.tensor` PyTorch tensor objects and we `Additive Share` them with our fellow workers.

```python
# Let a, b and c be our students' completion percentage
a = torch.tensor([35])
b = torch.tensor([77])
c = torch.tensor([10])
```

```python
# And we additive share with our parties
a = a.share(alice, bob, charlie, crypto_provider=secure_worker)
b = b.share(alice, bob, charlie, crypto_provider=secure_worker)
c = c.share(alice, bob, charlie, crypto_provider=secure_worker)
```

```python
# And we compute the mean of our tensor
mean = torch.mean(torch.stack(list([a,b,c])))
mean
```

Also, see that the object type is **[AdditiveSharingTensor]**.
For this example, we can decrypt our computation result using the get() method

```python
decrypted_mean = mean.get()
decrypted_mean
```

And get the scalar using the item() method (Only works for 1-dimensional tensors).

```python
scalar_mean = decrypted_mean.item()
scalar_mean
```

Now, the average completion should actually be 40 and $ \frac{1}{3} $ (or 40.6666666666... ) but this is something we will learn about in the next lessons.

Let’s now tackle private multiplication!


# Change of base & Transformation (Reflecting Bear)
## Background
Panda Bear is confused. He is trying to work out how things should look when reflected in a mirror, but is getting the wrong results.
As is the way with bears, his coordinate system is not orthonormal: so what he thinks is the direction perpendicular to the mirror isn't actually the direction the mirror reflects in.
Help Bear write a code that will do his matrix calculations properly!

## Instructions
In this assignment you will write a Python function that will produce a transformation matrix for reflecting vectors in an arbitrarily angled mirror.

Building on the last assingment, where you wrote a code to construct an orthonormal basis that spans a set of input vectors, here you will take a matrix which takes simple form in that basis, and transform it into our starting basis.
Recall the from the last video,

 \\( T = E T_E E^{-1} \\)

You will write a function that will construct this matrix.
This assessment is not conceptually complicated, but will build and test your ability to express mathematical ideas in code.
As such, your final code submission will be relatively short, but you will receive less structure on how to write it.

### Matrices in Python
For this exercise, we shall make use of the @ operator again.
Recall from the last exercise, we used this operator to take the dot product of vectors.
In general the operator will combine vectors and/or matrices in the expected linear algebra way,
i.e. it will be either the vector dot product, matrix multiplication, or matrix operation on a vector, depending on it's input.
For example to calculate the following expressions,

 \\( a = \mathbf{s}\cdot\mathbf{t} \\)

 \\( \mathbf{s} = A\mathbf{t} \\)

 \\( M = A B \\),

One would use the code,
```python
a = s @ t
s = A @ t
M = A @ B
```
(This is in contrast to the \\(*\\) operator, which performs element-wise multiplication, or multiplication by a scalar.)

You may need to use some of the following functions:
```python
inv(A)
transpose(A)
gsBasis(A)
```
These, respectively, take the inverse of a matrix, give the transpose of a matrix, and produce a matrix of orthonormal column vectors given a general matrix of column vectors - i.e. perform the Gram-Schmidt process.
This exercise will require you to combine some of these functions.

### How to submit
Edit the code in the cell below to complete the assignment.
Once you are finished and happy with it, press the *Submit Assignment* button at the top of this notebook.

Please don't change any of the function names, as these will be checked by the grading script.

```python
# !find ~ | grep -i bearNecessities
# from bearNecessities import *
```

```python
%matplotlib inline

import numpy as np
import numpy as np
import numpy.linalg as la
from numpy.linalg import norm, inv
from numpy import transpose
import matplotlib.pyplot as plt
```

```python
def build_reflection_matrix(bearBasis) :

    # The parameter bearBasis is a 2×2 matrix that is passed to the function.

    # Use the gsBasis function on bearBasis to get the mirror's orthonormal basis.
    E = gsBasis(bearBasis)

    # Transormation matrix that perform's the mirror's reflection in the mirror's basis.
    TE = np.array([[1, 0],
                   [0, -1]])
    # Combine the matrices E and TE to produce your transformation matrix.
    T = E @ TE @ E.T
    return T

```

```python
def gsBasis(A):
    """Gram-Schmidt for n vectors"""

    # Work with a copy - vectors are mutable
    B = np.array(A, dtype=np.float_)
    verySmallNumber
    # Loop over all vectors
    for i in range(B.shape[1]):
        # Loop over all previous vectors, j, to subtract.
        for j in range(i):
            # Subtract the overlap with previous vectors
            # you'll need the current vector B[:, i] and a previous vector B[:, j]
            B[:, i] -= (B[:, i] @ B[:, j] * B[:, j])

        # Normalise - norm(indepent)=1, norm(dependent)=0
        if la.norm(B[:, i]) > verySmallNumber:
            B[:, i] = B[:, i] / la.norm(B[:, i])
        else :
            B[:, i] = np.zeros_like(B[:, i])

    return B

def dimensions(A):
    """Gram-schmidt process to calculate the dimension spanned by a list of vectors.
    Independent vectors are normalised to one and dependent vectors to zero
    Thus the sum of all the norms will be the dimension"""
    return np.sum(la.norm(gsBasis(A), axis=0))
```

```python
def gram_schmidt_columns(X):
    Q, R = np.linalg.qr(X)
    return Q
```

```python

```

## Test your code before submission
To test the code you've written above, run the cell (select the cell above, then press the play button [ ▶| ] or press shift-enter).
You can then use the code below to test out your function.
You don't need to submit this cell; you can edit and run it as much as you like.

The code below will show a picture of Panda Bear.
If you have correctly implemented the function above, you will also see Bear's reflection in his mirror.

```python
# This is the matrix of Bear's basis vectors.

# bearBasis = np.array(
#     [[1,   -1],
#      [1.5, 2]])
# # This line uses your code to build a transformation matrix for us to use.
# T = build_reflection_matrix(bearBasis)

# # Bear is drawn as a set of polygons, the vertices of which are placed as a matrix list of column vectors.
# # We have three of these non-square matrix lists: bear_white_fur, bear_black_fur, and bear_face.
# # We'll make new lists of vertices by applying the T matrix you've calculated.
# reflected_bear_white_fur = T @ bear_white_fur
# reflected_bear_black_fur = T @ bear_black_fur
# reflected_bear_face = T @ bear_face

# # This next line runs a code to set up the graphics environment.
# ax = draw_mirror(bearBasis)

# # We'll first plot Bear, his white fur, his black fur, and his face.
# ax.fill(bear_white_fur[0], bear_white_fur[1], color=bear_white, zorder=1)
# ax.fill(bear_black_fur[0], bear_black_fur[1], color=bear_black, zorder=2)
# ax.plot(bear_face[0], bear_face[1], color=bear_white, zorder=3)

# # Next we'll plot Bear's reflection.
# ax.fill(reflected_bear_white_fur[0], reflected_bear_white_fur[1], color=bear_white, zorder=1)
# ax.fill(reflected_bear_black_fur[0], reflected_bear_black_fur[1], color=bear_black, zorder=2)
# ax.plot(reflected_bear_face[0], reflected_bear_face[1], color=bear_white, zorder=3);
```

Linear algebra change of basis explained using Python

Motivation

I'm always forgetting about the intuition behind the change of basis in linear algebra.
There is a very nice video explaining it on Youtube, but I want the explanation in text format so I can easily refer too when in doubt.

Change of basis

Let's say we have two sets of basis vector \(\color{blue}{\boldsymbol{b_{i}}}\) and \(\color{red}{\boldsymbol{\beta_{i}}}\).
The set \(\color{blue}{\boldsymbol{b_{i}}}\) defines the original system, the one we start with, and the set \(\color{red}{\boldsymbol{\beta_{i}}}\) the transformed system.
The \(\color{blue}{blue}\) color will be used for original coordinate system and \(\color{red}{red}\) for the transformed.
The notation with \([]\) will need a subscript to denote which coordinate system it is referring to.
In the 2-d space, the basis vectors of the original system can be written as,

\begin{equation}
\label{eq:1}
\color{blue}{\boldsymbol{b_{1}} =
\begin{bmatrix}
b_{1x} \\ b_{1y}
\end{bmatrix}}_{\color{blue}{b}} \qquad
\color{blue}{\boldsymbol{b_{2}} =
\begin{bmatrix}
b_{2x} \\ b_{2y}
\end{bmatrix}}_{\color{blue}{b}}
\end{equation}

generally, those will be the classic unit vectors \([1, 0]\) and \([0, 1]\).
The basis vector of the transformed space using the coordinate system of the original space are

\begin{equation}
\label{eq:2}
\color{blue}{\boldsymbol{\beta_{1}} =
\begin{bmatrix}
\beta_{1x} \\ \beta_{1y}
\end{bmatrix}}_{\color{blue}{b}} = \color{blue}{\beta_{1x}} \color{blue}{\boldsymbol{b_1}} + \color{blue}{\beta_{1y}} \color{blue}{\boldsymbol{b_2}} \qquad
\color{blue}{\boldsymbol{\beta_{2}} =
\begin{bmatrix}
\beta_{2x} \\ \beta_{2y}
\end{bmatrix}}_{\color{blue}{b}} = \color{blue}{\beta_{2x}} \color{blue}{\boldsymbol{b_1}} +  \color{blue}{\beta_{2y}} \color{blue}{\boldsymbol{b_2}}
\end{equation}

Given that we know the transformation on the basis vector of the original system we can find \(\color{blue}{\beta_{1x}, \beta_{1y}, \beta_{2x}, \beta_{2y}}\).

Now, for any vector \(\boldsymbol{v}\) written in the transformed system,

\begin{equation}
\label{eq:20}
\color{red}{\boldsymbol{v}_{\beta}} = \color{red}{v_{1}} \boldsymbol{\color{red}{\beta_{1}}} + \color{red}{v_{2}} \boldsymbol{\color{red}{\beta_{2}}} =
\begin{bmatrix}
\color{red}{v_{1}} \\ \color{red}{v_{2}}
\end{bmatrix}_{\color{red}{\beta}}
\end{equation}

we can transform it by using \(\color{blue}{\beta}_{i}\) (the basis vector in the original system), expressed in the previous equation,

\begin{equation}
\label{eq:3}
\color{blue}{\boldsymbol{v}_{b}} =
\color{red}{v_{1}} \boldsymbol{\color{blue}{\beta_{1}}} +
\color{red}{v_{2}} \boldsymbol{\color{blue}{\beta_{2}}}
\end{equation}

Using the above equation we can define matrix multiplication by,

\begin{equation}
\label{eq:5}
\color{blue}{\boldsymbol{v}_{{b}}} =
\begin{bmatrix}
\boldsymbol{\color{blue}{\beta_{1}}} & \boldsymbol{\color{blue}{\beta_{2}}}
\end{bmatrix}
\begin{bmatrix}
\color{red}{v_{1}} \\ \color{red}{v_{2}}
\end{bmatrix}_{\color{red}{\beta}}
=
\begin{bmatrix}
\color{blue}{\beta_{1x}} & \color{blue}{\beta_{2x}} \\
\color{blue}{\beta_{1y}} & \color{blue}{\beta_{2y}}
\end{bmatrix}
\begin{bmatrix}
\color{red}{v_{1}} \\ \color{red}{v_{2}}
\end{bmatrix}_{\color{red}{\beta}} =
\begin{bmatrix}
\color{red}{v_{1}} \color{blue}{\beta_{1x}} +\color{red}{v_{2}} \color{blue}{\beta_{2x}} \\
\color{red}{v_{1}} \color{blue}{\beta_{1y}} + \color{red}{v_{2}} \color{blue}{\beta_{2y}}
\end{bmatrix}_{\color{blue}{b}}
\end{equation}

the matrix product will result in a vector in the original system.
The matrix has two columns which are the vectors with the transformed system using the original coordinates.
Therefore, the above equation is a transformation from the transformed system to the original system and the transformation matrix \(\boldsymbol{Q}\), is given by,

\begin{equation}
\label{eq:6}
\boldsymbol{Q} = \begin{bmatrix}
\color{blue}{\beta_{1x}} & \color{blue}{\beta_{2x}} \\
\color{blue}{\beta_{1y}} & \color{blue}{\beta_{2y}}
\end{bmatrix}
\end{equation}

If we have the vector in the original coordinate and want it in the transformed system, we have to invert the transformation matrix.

\begin{equation}
\label{eq:7}
\color{red}{\boldsymbol{v}_{{\beta}}}
=
\begin{bmatrix}
\color{blue}{\beta_{1x}} & \color{blue}{\beta_{2x}} \\
\color{blue}{\beta_{1y}} & \color{blue}{\beta_{2y}}
\end{bmatrix}^{-1}
\begin{bmatrix}
\color{blue}{v_{1}} \\ \color{blue}{v_{2}}
\end{bmatrix}_{\color{blue}{b}}
\end{equation}

Example

Assuming that $b_{i}$ is the Cartesian system and the new basis is given by,

\begin{equation}
\label{eq:9}
\beta_{1} =
\begin{bmatrix}
2 \\ 3
\end{bmatrix} \qquad
\beta_2=
\begin{bmatrix}
-1 \\ 1
\end{bmatrix}
\end{equation}

Those vectors in the Cartesian coordinate system are drawn with

```python
import sympy as sp
from sympy import Matrix as spm
sp.init_printing(use_unicode=True)

# Cartesian base
# b1, b2 = np.array([1, 0]), np.array([0, 1])
B = np.eye(2)
b1, b2 = B[:,0], B[:,1]
print('Cartesian base: ')
spm(B)

# New base
β1, β2 = np.array([2, 3]), np.array([-1, 1])

# Transform matrix
Q = np.array([β1, β2]).T
print('Transformed to original system with: ')
spm(Q)

# Vector in original base [b1, b2]
v = np.array([2, -4])
spm(v)

# Vector in the new coordinate system [β1, β2]
v_β = np.linalg.solve(Q, v)
print('The vector in the new coordinates: ')
spm(v_β)

# Change base; Q_inv @ v
spm(np.linalg.inv(Q) @ v)

# Change base and back; Q_inv @ v @ Q.T
spm(np.linalg.inv(Q) @ v @ Q.T)

# Transformation Matrix in new base (reflect mirror 90º)
TE = np.array([[1, 0], [0, -1]])

# Change base, transform and back to cartesian; Q_inv @ v @ TE @ Q.T
spm(np.linalg.inv(Q) @ v @ TE @ Q.T)
```

```python
def ax_annot(b, col, ax, alpha=1):
    """Helper to draw arrow on plot"""
    return ax.annotate(s=b, xy=(0,0), xytext=b*1.15, horizontalalignment='center', verticalalignment='center')  #arrowprops=dict(arrowstyle='<-', ec=col, fc=col, lw=1.2, alpha=alpha)
```

```python
def ax_arrow(b, col, ax, alpha=1):
    """Helper to draw arrow on plot"""
    ax_annot(b, col, ax, alpha=1)
    return ax.arrow(0, 0, b[0], b[1], fc=col, ec=col, head_width=0.2, head_length=.2, alpha=alpha)
```

```python
figsize = [7, 7]

fig, ax = plt.subplots()

ax_arrow(b1, 'b', ax)
ax_arrow(b2, 'b', ax)
ax_arrow(β1, 'r', ax)
ax_arrow(β2, 'r', ax)

ax.axis([-3, 4, -5, 4])
ax.set_aspect('equal')
ax.axhline(color='k', alpha=.3)
ax.axvline(color='k', alpha=.3)
fig.set_size_inches(figsize);
```

#### Cartesian Base vectors __[b1, b2]__ for $\boldsymbol{v}=[2, -4]$

```python
fig, ax = plt.subplots()

ax_arrow(v, 'g', ax)
ax_arrow(v[0]*b1, 'b', ax)
ax_arrow(v[1]*b2, 'b', ax)

ax_arrow(b1, 'b', ax, .2)
ax_arrow(b2, 'b', ax, .2)
ax_arrow(β1, 'r', ax, .2)
ax_arrow(β2, 'r', ax, .2)

ax.axis([-3, 4, -5, 4])
ax.set_aspect('equal')
ax.axhline(color='k', alpha=.3)
ax.axvline(color='k', alpha=.3)
fig.set_size_inches(figsize);
```

#### New base vectors [$\boldsymbol{\beta_{1}}$, $\boldsymbol{\beta_{2}}$]  for $\boldsymbol{v}=[2, -4]$

```python
fig, ax = plt.subplots()

ax_arrow(v, 'g', ax)
ax_arrow(v_β[0]*β1, 'b', ax)
ax_arrow(v_β[1]*β2, 'b', ax)

ax_arrow(b1, 'b', ax, .2)
ax_arrow(b2, 'b', ax, .2)
ax_arrow(β1, 'r', ax, .2)
ax_arrow(β2, 'r', ax, .2)

ax.axis([-3, 4, -5, 4])
ax.set_aspect('equal')
ax.axhline(color='k', alpha=.3)
ax.axvline(color='k', alpha=.3)
fig.set_size_inches(figsize);
```

```python

```

```python

```

```python

```

_math/Imperial College London - Math for ML/linalg_transform_base_mpl_annotate_ReflectingBear.ipynb


# Reproducibility and Accuracy

When computing the sum of floating point values as in the scalar product
\begin{align}
\vec x\cdot \vec y = \sum_k x_k y_k
\end{align}
round-off errors can (i) falsify the numerical result and (ii) make the result non-reproducible in a parallel setting. To see the first point imagine a naive implementation
like
```{code-block} cpp
double sum = 0;
for( unsigned u=0; u<size; u++)
    sum += x[u]*y[u];
```
 $ x\oplus y$ is numerically not exact, in fact $1\oplus \varepsilon = 1$ if $\varepsilon$ is the machine precision. This means that most accuracy is lost in $s \oplus x_u y_u$ at the end of the for loop, when
the variable `sum` gets increasingly larger in comparison to `x[u]*y[u]`.
The accuracy problem is somewhat alleviated in algorithms like tree-reduction but not entirely.

Another problem is that $(a \oplus b) \oplus c \neq a\oplus (b\oplus c)$, which leads to non-reproducible results in a parallel setting where the order of execution cannot be guaranteed.
```{admonition} Further reading
You can read more about this topic in our publication  M. Wiesenberger, L. Einkemmer, M. Held, A. Gutierrez-Milla, X. Sáez, R. Iakymchuk  [Reproducibility, accuracy and performance of the Feltor code and library on parallel computer architectures](https://doi.org/10.1016/j.cpc.2018.12.006) Computer Physics Communications 23
```

## The `dg::blas1::dot` function
We base our algorithm on the "exblas" approach, which computes sums with a long accumulator (a large fixed point number) that can accurately store the result and only perform one rounding operation at the end. This makes the `dg::blas1::dot` function both **as accurate as it can be** and **binary reproducible** across many different platforms.

## Is Feltor binary reproducible?
The short answer is no. The longer answer is "almost" or "at least if you don't change the compiler. In order to be binary reproducible **all computations** have to be implemented either with long accumulators or such that the order of execution is always guaranteed. Now the problem lies in the fact that we do not always have full control over what is implemented. Consider

```c++
#pragma cling add_include_path("../../include")
#pragma cling add_include_path("../feltor/inc") // Feltor path
#define THRUST_DEVICE_SYSTEM THRUST_DEVICE_SYSTEM_CPP
#include <iostream>
#include "dg/exblas/exblas.h"
```

```c++
#include "dg/exblas/exblas.h"
double x = 6.12610567450009658;
dg::exblas::udouble result;
result.d = sin(x);
//std::cout << result.d << " "<<result.i<<"\n";
std::cout << "Difference to correct result: "<<result.i  - -4628567870976535683<<"\n";
```

    Difference to correct result 1

Depending on your platform/compiler the result of the above example may or may not be zero. This is because the implementation of the sine function is not unique and rounding is not always done correctly for all inputs.

This simple example shows that from a developer perspective it is almost impossible (or at least highly impractical) to make an entire program binary reproducible across all platforms and compilers.

```c++

```