```
#!/usr/bin/python

# interpolate scalar gradient onto nedelec space

import petsc4py
import sys

petsc4py.init(sys.argv)

from petsc4py import PETSc
from dolfin import *
import mshr
Print = PETSc.Sys.Print
# from MatrixOperations import *
import numpy as np
import PETScIO as IO
import common
import scipy
import scipy.io
import time

import BiLinear as forms
import IterOperations as Iter
import MatrixOperations as MO
import CheckPetsc4py as CP
import ExactSol
import Solver as S
import MHDmatrixPrecondSetup as PrecondSetup
import NSprecondSetup
import MHDprec as MHDpreconditioner
import memory_profiler
import gc
import MHDmulti
import MHDmatrixSetup as MHDsetup
import Lshaped
#@profile
m = 2

set_log_active(False)
errL2u =np.zeros((m-1,1))
errH1u =np.zeros((m-1,1))
errL2p =np.zeros((m-1,1))
errL2b =np.zeros((m-1,1))
errCurlb =np.zeros((m-1,1))
errL2r =np.zeros((m-1,1))
errH1r =np.zeros((m-1,1))

l2uorder =  np.zeros((m-1,1))
H1uorder =np.zeros((m-1,1))
l2porder =  np.zeros((m-1,1))
l2border =  np.zeros((m-1,1))
Curlborder =np.zeros((m-1,1))
l2rorder =  np.zeros((m-1,1))
H1rorder = np.zeros((m-1,1))

NN = np.zeros((m-1,1))
DoF = np.zeros((m-1,1))
Velocitydim = np.zeros((m-1,1))
Magneticdim = np.zeros((m-1,1))
Pressuredim = np.zeros((m-1,1))
Lagrangedim = np.zeros((m-1,1))
Wdim = np.zeros((m-1,1))
iterations = np.zeros((m-1,1))
SolTime = np.zeros((m-1,1))
udiv = np.zeros((m-1,1))
MU = np.zeros((m-1,1))
level = np.zeros((m-1,1))
NSave = np.zeros((m-1,1))
Mave = np.zeros((m-1,1))
TotalTime = np.zeros((m-1,1))

nn = 2

dim = 2
ShowResultPlots = 'yes'
split = 'Linear'

MU[0]= 1e0
for xx in xrange(1,m):
    print xx
    level[xx-1] = xx+ 2
    nn = 2**(level[xx-1])

    # Create mesh and define function space
    nn = int(nn)
    NN[xx-1] = nn/2
    # parameters["form_compiler"]["quadrature_degree"] = 6
    # parameters = CP.ParameterSetup()
    # mesh = UnitSquareMesh(nn,nn)
    # domain = mshr.Rectangle(Point(0., 0.), Point(1., 2.)) + mshr.Rectangle(Point(1., 0.), Point(2., 1.))
    # mesh = mshr.generate_mesh(domain, nn)
    mesh, boundaries, domains = Lshaped.Domain(nn)
    # set_log_level(WARNING)

    order = 2
    parameters['reorder_dofs_serial'] = False
    Velocity = VectorFunctionSpace(mesh, "CG", order)
    Pressure = FunctionSpace(mesh, "CG", order-1)
    Magnetic = FunctionSpace(mesh, "N1curl", order-1)
    Lagrange = FunctionSpace(mesh, "CG", order-1)
    W = MixedFunctionSpace([Velocity, Pressure, Magnetic,Lagrange])
    # W = Velocity*Pressure*Magnetic*Lagrange
    Velocitydim[xx-1] = Velocity.dim()
    Pressuredim[xx-1] = Pressure.dim()
    Magneticdim[xx-1] = Magnetic.dim()
    Lagrangedim[xx-1] = Lagrange.dim()
    Wdim[xx-1] = W.dim()
    print "\n\nW:  ",Wdim[xx-1],"Velocity:  ",Velocitydim[xx-1],"Pressure:  ",Pressuredim[xx-1],"Magnetic:  ",Magneticdim[xx-1],"Lagrange:  ",Lagrangedim[xx-1],"\n\n"
    dim = [Velocity.dim(), Pressure.dim(), Magnetic.dim(), Lagrange.dim()]

    def boundary(x, on_boundary):
        return on_boundary

    # u0, p0,b0, r0, Laplacian, Advection, gradPres,CurlCurl, gradR, NS_Couple, M_Couple = ExactSol.MHD2D(7,5, mesh)
    # u0, p0, b0, r0, F_NS, F_M, gradu0 = Lshaped.SolutionTest(mesh)

    # u0, p0, b0, r0, F_NS, F_M, gradu0 = Lshaped.Solution(mesh)
    # print r0.value_shape()
    # bcu = DirichletBC(Velocity,u0, boundaries, 1)
    # bcb = DirichletBC(Magnetic,b0, boundaries, 1)
    # bcr = DirichletBC(Lagrange,r0, boundaries, 1)

    # # bc = [u0,p0,b0,r0]
    # bcs = [bcu,bcb,bcr]
    FSpaces = [Velocity,Pressure,Magnetic,Lagrange]

    kappa = 1.0
    Mu_m =1e4
    MU = 1.0
    params = [kappa,Mu_m,MU]

#     u0, p0,b0, r0, Laplacian, Advection, gradPres,CurlCurl, gradR, NS_Couple, M_Couple = ExactSol.MHD2D(7,5, mesh)

interactive()

```

    DEBUG:FFC:Reusing form from cache.
    DEBUG:FFC:Reusing form from cache.
    DEBUG:FFC:Reusing form from cache.
    DEBUG:FFC:Reusing form from cache.
    DEBUG:FFC:Reusing form from cache.

    1

    W:   [ 1364.] Velocity:   [ 834.] Pressure:   [ 113.] Magnetic:   [ 304.] Lagrange:   [ 113.]

```

```

```

```

```
 u0, p0, b0, r0, F_NS, F_M, gradu0, cc = Lshaped.Solution(mesh, params)

```

```
p0(1,1)
```

```
file = File("p.vtk")
file << interpolate(p0,Pressure)
```

```
plot(interpolate(b0,Magnetic))
```

    <dolfin.cpp.io.VTKPlotter; proxy of <Swig Object of type 'std::shared_ptr< dolfin::VTKPlotter > *' at 0x1168aeb10> >

```
plot(interpolate(u0,Velocity))
```

    <dolfin.cpp.io.VTKPlotter; proxy of <Swig Object of type 'std::shared_ptr< dolfin::VTKPlotter > *' at 0x1168ae8a0> >

```
plot(interpolate(p0,Pressure))
```

    <dolfin.cpp.io.VTKPlotter; proxy of <Swig Object of type 'std::shared_ptr< dolfin::VTKPlotter > *' at 0x110804c00> >

```
import sympy as sy

l = 0.54448373678246
omega = (3./2)*np.pi

phi = sy.symbols('rho')
rho = sy.symbols('phi')
l = sy.symbols('lambda')
omega = sy.symbols('omega')
z = sy.symbols('z')

# looked at all the exact solutions and they seems to be the same as the paper.....
psi = (sy.sin((1+l)*phi)*sy.cos(l*omega))/(1+l) - sy.cos((1+l)*phi) - (sy.sin((1-l)*phi)*sy.cos(l*omega))/(1-l) + sy.cos((1-l)*phi)
psi_prime = sy.diff(psi, phi)
psi_3prime = sy.diff(psi, phi, phi, phi)

u = rho**l*((1+l)*sy.sin(phi)*psi + sy.cos(phi)*psi_prime)
v = rho**l*(-(1+l)*sy.cos(phi)*psi + sy.sin(phi)*psi_prime)

p = -rho**(l-1)*((1+l)**2*psi_prime + psi_3prime)/(1-l)

f = rho**(2./3)*sy.sin((2./3)*phi)
b = polarx(f, rho, phi)
d = polary(f, rho, phi)

r = sy.diff(rho,z)

```

```
b
```

```
plot(mesh)
```

    <dolfin.cpp.io.VTKPlotter; proxy of <Swig Object of type 'std::shared_ptr< dolfin::VTKPlotter > *' at 0x103592360> >

```
u0, p0, b0, r0 = Lshaped.SolutionTest(mesh, 1, Lagrange)
plot(interpolate(u0,Velocity))
```

    0.771818064702 -1.94378404859
    0.514062998266 -2.14340425219
    0.715084405928 -2.20973623988
    0.61424476511 -2.18199632831
    0.736897422219 -2.07165628657
    0.639869563579 -2.02352319237
    0.771818064702 -1.94378404859
    0.514062998266 -2.14340425219
    0.715084405928 -2.20973623988
    0.61424476511 -2.18199632831
    0.736897422219 -2.07165628657
    0.639869563579 -2.02352319237
    1.11803398875 -2.0344439358
    1.25 -2.21429743559
    1.04166666667 -2.21429743559
    1.14583333333 -2.21429743559
    1.07549245826 -2.12118227447
    1.17924764151 -2.12939564214
    1.11803398875 -2.0344439358
    1.25 -2.21429743559
    1.04166666667 -2.21429743559
    1.14583333333 -2.21429743559
    1.07549245826 -2.12118227447
    1.17924764151 -2.12939564214
    0.883883476483 -2.35619449019
    0.838525491562 -2.67794504459
    0.712034584876 -2.48462922381
    0.771685371453 -2.58919673402
    0.796333346992 -2.41348750297
    0.850091906796 -2.51279636717
    0.883883476483 -2.35619449019
    0.838525491562 -2.67794504459
    0.712034584876 -2.48462922381
    0.771685371453 -2.58919673402
    0.796333346992 -2.41348750297
    0.850091906796 -2.51279636717
    0.514062998266 -2.14340425219
    0.715084405928 -2.20973623988
    0.712034584876 -2.48462922381
    0.706830012319 -2.34688713842
    0.604381629764 -2.34182791758
    0.61424476511 -2.18199632831
    0.514062998266 -2.14340425219
    0.715084405928 -2.20973623988
    0.712034584876 -2.48462922381
    0.706830012319 -2.34688713842
    0.604381629764 -2.34182791758
    0.61424476511 -2.18199632831
    0.883883476483 -2.35619449019
    0.838525491562 -2.67794504459
    0.988211768803 -2.53604798998
    0.91108623357 -2.60117315332
    0.932277118136 -2.45114619654
    0.850091906796 -2.51279636717
    0.883883476483 -2.35619449019
    0.838525491562 -2.67794504459
    0.988211768803 -2.53604798998
    0.91108623357 -2.60117315332
    0.932277118136 -2.45114619654
    0.850091906796 -2.51279636717
    0.559016994375 -2.67794504459
    0.454462016546 2.96034728553
    0.712097781161 -3.07667454315
    0.579083387317 3.11074304287
    0.623153036762 -2.90163779521
    0.480909083786 -2.96593724053
    0.559016994375 -2.67794504459
    0.454462016546 2.96034728553
    0.712097781161 -3.07667454315
    0.579083387317 3.11074304287
    0.623153036762 -2.90163779521
    0.480909083786 -2.96593724053
    0.5 -1.57079632679
    0.75 -1.57079632679
    0.638067482233 -1.77352801529
    0.690494408356 -1.66396019237
    0.56615592196 -1.68450128659
    0.625 -1.57079632679
    0.5 -1.57079632679
    0.75 -1.57079632679
    0.638067482233 -1.77352801529
    0.690494408356 -1.66396019237
    0.56615592196 -1.68450128659
    0.625 -1.57079632679
    0.589255650989 2.35619449019
    0.425122255926 2.53646255808
    0.605812056484 2.68369655179
    0.514113954015 2.62300489851
    0.589542027833 2.52223461211
    0.505184120377 2.4317056296
    0.589255650989 2.35619449019
    0.425122255926 2.53646255808
    0.605812056484 2.68369655179
    0.514113954015 2.62300489851
    0.589542027833 2.52223461211
    0.505184120377 2.4317056296
    0.957540432857 2.35619449019
    1.15379069349 2.35619449019
    1.06714978856 2.50147742847
    1.10754613661 2.42599716227
    1.00968315704 2.43277541526
    1.05566556317 2.35619449019
    0.957540432857 2.35619449019
    1.15379069349 2.35619449019
    1.06714978856 2.50147742847
    1.10754613661 2.42599716227
    1.00968315704 2.43277541526
    1.05566556317 2.35619449019
    1.01646599796 0.785398163397
    0.840949195133 1.03120808153
    0.689105089525 0.835854309646
    0.76141656687 0.943255386262
    0.85252417655 0.805783065251
    0.921764855969 0.896630890953
    1.01646599796 0.785398163397
    0.840949195133 1.03120808153
    0.689105089525 0.835854309646
    0.76141656687 0.943255386262
    0.85252417655 0.805783065251
    0.921764855969 0.896630890953
    0.728868986856 0.540419500271
    0.646840612344 0.260602391747
    0.84328548027 0.326958840636
    0.744660131483 0.298156113636
    0.781627994976 0.425892199142
    0.681157613511 0.408907828951
    0.728868986856 0.540419500271
    0.646840612344 0.260602391747
    0.84328548027 0.326958840636
    0.744660131483 0.298156113636
    0.781627994976 0.425892199142
    0.681157613511 0.408907828951
    1.11803398875 0.463647609001
    1.25 0.643501108793
    0.940417912789 0.580322263015
    1.09467346928 0.616377823912
    1.02748814073 0.516945551939
    1.17924764151 0.558599315344
    1.11803398875 0.463647609001
    1.25 0.643501108793
    0.940417912789 0.580322263015
    1.09467346928 0.616377823912
    1.02748814073 0.516945551939
    1.17924764151 0.558599315344
    1.01646599796 0.785398163397
    0.689105089525 0.835854309646
    0.940417912789 0.580322263015
    0.808278989591 0.688278265981
    0.973310557757 0.686859028498
    0.85252417655 0.805783065251
    1.01646599796 0.785398163397
    0.689105089525 0.835854309646
    0.940417912789 0.580322263015
    0.808278989591 0.688278265981
    0.973310557757 0.686859028498
    0.85252417655 0.805783065251
    0.559016994375 1.10714871779
    0.840949195133 1.03120808153
    0.689105089525 0.835854309646
    0.76141656687 0.943255386262
    0.618390987892 0.957277006395
    0.699499025874 1.06152821917
    0.559016994375 1.10714871779
    0.840949195133 1.03120808153
    0.689105089525 0.835854309646
    0.76141656687 0.943255386262
    0.618390987892 0.957277006395
    0.699499025874 1.06152821917
    1.0 1.57079632679
    1.0307764064 1.81577498992
    0.831205090139 1.82967495711
    0.930968522183 1.82198004697
    0.908008352515 1.68823781149
    1.00778221854 1.69515132134
    1.0 1.57079632679
    1.0307764064 1.81577498992
    0.831205090139 1.82967495711
    0.930968522183 1.82198004697
    0.908008352515 1.68823781149
    1.00778221854 1.69515132134
    0.559016994375 1.10714871779
    0.315642584119 1.13221889849
    0.477870567666 1.49166205304
    0.390635406452 1.34906694959
    0.508950783789 1.28417246843
    0.437298091421 1.11619574522
    0.559016994375 1.10714871779
    0.315642584119 1.13221889849
    0.477870567666 1.49166205304
    0.390635406452 1.34906694959
    0.508950783789 1.28417246843
    0.437298091421 1.11619574522
    0.589255650989 2.35619449019
    0.326687688122 1.90946276725
    0.425122255926 2.53646255808
    0.357905371237 2.26538354874
    0.505184120377 2.4317056296
    0.447540302659 2.19785434363
    0.589255650989 2.35619449019
    0.326687688122 1.90946276725
    0.425122255926 2.53646255808
    0.357905371237 2.26538354874
    0.505184120377 2.4317056296
    0.447540302659 2.19785434363
    0.454462016546 2.96034728553
    0.425122255926 2.53646255808
    0.605812056484 2.68369655179
    0.514113954015 2.62300489851
    0.525176989777 2.80215221363
    0.429962494424 2.75558222397
    0.454462016546 2.96034728553
    0.425122255926 2.53646255808
    0.605812056484 2.68369655179
    0.514113954015 2.62300489851
    0.525176989777 2.80215221363
    0.429962494424 2.75558222397
    0.326687688122 1.90946276725
    0.315642584119 1.13221889849
    0.297223894641 1.52788127162
    0.157821292059 1.13221889849
    0.163343844061 1.90946276725
    0.326687688122 1.90946276725
    0.315642584119 1.13221889849
    0.297223894641 1.52788127162
    0.157821292059 1.13221889849
    0.163343844061 1.90946276725
    0.559016994375 1.10714871779
    0.450693909433 0.588002603548
    0.315642584119 1.13221889849
    0.369516062926 0.81097708807
    0.437298091421 1.11619574522
    0.488140604744 0.876058050598
    0.559016994375 1.10714871779
    0.450693909433 0.588002603548
    0.315642584119 1.13221889849
    0.369516062926 0.81097708807
    0.437298091421 1.11619574522
    0.488140604744 0.876058050598
    1.11803398875 -2.67794504459
    1.25 -2.4980915448
    0.988211768803 -2.53604798998
    1.11890711187 -2.51484975238
    1.05048351962 -2.61137688081
    1.17924764151 -2.58299333825
    1.11803398875 -2.67794504459
    1.25 -2.4980915448
    0.988211768803 -2.53604798998
    1.11890711187 -2.51484975238
    1.05048351962 -2.61137688081
    1.17924764151 -2.58299333825
    0.643493221073 1.73531883021
    0.831205090139 1.82967495711
    0.614930471097 2.03853022605
    0.719217124137 1.9184293389
    0.621998431969 1.8834569026
    0.736542023294 1.78850649709
    0.643493221073 1.73531883021
    0.831205090139 1.82967495711
    0.614930471097 2.03853022605
    0.719217124137 1.9184293389
    0.621998431969 1.8834569026
    0.736542023294 1.78850649709
    0.589255650989 2.35619449019
    0.614930471097 2.03853022605
    0.774304298205 2.30780767414
    0.68841412788 2.18870754638
    0.681584129395 2.32871716713
    0.594517785856 2.19394709478
    0.589255650989 2.35619449019
    0.614930471097 2.03853022605
    0.774304298205 2.30780767414
    0.68841412788 2.18870754638
    0.681584129395 2.32871716713
    0.594517785856 2.19394709478
    0.957540432857 2.35619449019
    0.805564012005 2.07265137974
    0.774304298205 2.30780767414
    0.784482315321 2.18789231697
    0.865671793817 2.33456133594
    0.872773860983 2.22672530376
    0.957540432857 2.35619449019
    0.805564012005 2.07265137974
    0.774304298205 2.30780767414
    0.784482315321 2.18789231697
    0.865671793817 2.33456133594
    0.872773860983 2.22672530376
    0.279582168163 -2.70090219662
    0.244167580618 2.68590015531
    0.236134792315 -3.11659289398
    0.122083790309 2.68590015531
    0.139791084081 -2.70090219662
    0.279582168163 -2.70090219662
    0.244167580618 2.68590015531
    0.236134792315 -3.11659289398
    0.122083790309 2.68590015531
    0.139791084081 -2.70090219662
    0.805564012005 2.07265137974
    0.614930471097 2.03853022605
    0.774304298205 2.30780767414
    0.68841412788 2.18870754638
    0.784482315321 2.18789231697
    0.7101457423 2.05788058868
    0.805564012005 2.07265137974
    0.614930471097 2.03853022605
    0.774304298205 2.30780767414
    0.68841412788 2.18870754638
    0.784482315321 2.18789231697
    0.7101457423 2.05788058868
    0.326687688122 1.90946276725
    0.244167580618 2.68590015531
    0.264648764497 2.23863084596
    0.122083790309 2.68590015531
    0.163343844061 1.90946276725
    0.326687688122 1.90946276725
    0.244167580618 2.68590015531
    0.264648764497 2.23863084596
    0.122083790309 2.68590015531
    0.163343844061 1.90946276725
    0.454462016546 2.96034728553
    0.279582168163 -2.70090219662
    0.244167580618 2.68590015531
    0.236134792315 -3.11659289398
    0.346329912087 2.86466669296
    0.350441734715 -3.08829066212
    0.454462016546 2.96034728553
    0.279582168163 -2.70090219662
    0.244167580618 2.68590015531
    0.236134792315 -3.11659289398
    0.346329912087 2.86466669296
    0.350441734715 -3.08829066212
    1.11803398875 2.0344439358
    0.805564012005 2.07265137974
    1.0307764064 1.81577498992
    0.910721594848 1.92837540495
    1.06800046816 1.92956699707
    0.961628131695 2.05044407445
    1.11803398875 2.0344439358
    0.805564012005 2.07265137974
    1.0307764064 1.81577498992
    0.910721594848 1.92837540495
    1.06800046816 1.92956699707
    0.961628131695 2.05044407445
    1.0 3.14159265359
    1.0307764064 2.89661399046
    0.877991323518 2.99873682651
    0.953147942644 2.94358472395
    0.936611445887 3.07481311801
    1.00778221854 3.01723765904
    1.0 3.14159265359
    1.0307764064 2.89661399046
    0.877991323518 2.99873682651
    0.953147942644 2.94358472395
    0.936611445887 3.07481311801
    1.00778221854 3.01723765904
    1.11803398875 1.10714871779
    1.25 0.927295218002
    1.07246709387 0.94866502143
    1.16116764756 0.937163318725
    1.09181514266 1.02955871926
    1.17924764151 1.01219701145
    1.11803398875 1.10714871779
    1.25 0.927295218002
    1.07246709387 0.94866502143
    1.16116764756 0.937163318725
    1.09181514266 1.02955871926
    1.17924764151 1.01219701145
    0.5 0.0
    0.450693909433 0.588002603548
    0.25 0.0
    0.336572800446 0.380506377112
    0.375 0.0
    0.45500686808 0.278299659005
    0.5 0.0
    0.450693909433 0.588002603548
    0.25 0.0
    0.336572800446 0.380506377112
    0.375 0.0
    0.45500686808 0.278299659005
    0.559016994375 -2.67794504459
    0.514062998266 -2.14340425219
    0.279582168163 -2.70090219662
    0.382866836673 -2.33779658963
    0.419275025715 -2.68559862379
    0.517524391594 -2.42214521764
    0.559016994375 -2.67794504459
    0.514062998266 -2.14340425219
    0.279582168163 -2.70090219662
    0.382866836673 -2.33779658963
    0.419275025715 -2.68559862379
    0.517524391594 -2.42214521764
    0.559016994375 -2.67794504459
    0.454462016546 2.96034728553
    0.279582168163 -2.70090219662
    0.350441734715 -3.08829066212
    0.419275025715 -2.68559862379
    0.480909083786 -2.96593724053
    0.559016994375 -2.67794504459
    0.454462016546 2.96034728553
    0.279582168163 -2.70090219662
    0.350441734715 -3.08829066212
    0.419275025715 -2.68559862379
    0.480909083786 -2.96593724053
    1.0 1.57079632679
    0.77400876924 1.38176484732
    1.0307764064 1.32581766367
    0.902046687265 1.34981042201
    1.00778221854 1.44644133225
    0.883109816827 1.48835635534
    1.0 1.57079632679
    0.77400876924 1.38176484732
    1.0307764064 1.32581766367
    0.902046687265 1.34981042201
    1.00778221854 1.44644133225
    0.883109816827 1.48835635534
    0.559016994375 1.10714871779
    0.77400876924 1.38176484732
    0.840949195133 1.03120808153
    0.795128237089 1.19914593294
    0.699499025874 1.06152821917
    0.660403625501 1.26673851026
    0.559016994375 1.10714871779
    0.77400876924 1.38176484732
    0.840949195133 1.03120808153
    0.795128237089 1.19914593294
    0.699499025874 1.06152821917
    0.660403625501 1.26673851026
    1.11803398875 -2.67794504459
    0.838525491562 -2.67794504459
    1.0307764064 -2.89661399046
    0.929129296707 -2.79856871317
    1.06800046816 -2.78282198332
    0.978279740156 -2.67794504459
    1.11803398875 -2.67794504459
    0.838525491562 -2.67794504459
    1.0307764064 -2.89661399046
    0.929129296707 -2.79856871317
    1.06800046816 -2.78282198332
    0.978279740156 -2.67794504459
    0.559016994375 -2.67794504459
    0.838525491562 -2.67794504459
    0.712097781161 -3.07667454315
    0.760057829771 -2.86083754495
    0.623153036762 -2.90163779521
    0.698771242969 -2.67794504459
    0.559016994375 -2.67794504459
    0.838525491562 -2.67794504459
    0.712097781161 -3.07667454315
    0.760057829771 -2.86083754495
    0.623153036762 -2.90163779521
    0.698771242969 -2.67794504459
    0.279582168163 -2.70090219662
    0.25 -1.57079632679
    0.223772228233 -2.1712499733
    0.125 -1.57079632679
    0.139791084081 -2.70090219662
    0.279582168163 -2.70090219662
    0.25 -1.57079632679
    0.223772228233 -2.1712499733
    0.125 -1.57079632679
    0.139791084081 -2.70090219662
    1.0 0.0
    1.0307764064 0.244978663127
    0.84328548027 0.326958840636
    0.936251741003 0.281865614343
    0.90944387175 0.149456305865
    1.00778221854 0.124354994547
    1.0 0.0
    1.0307764064 0.244978663127
    0.84328548027 0.326958840636
    0.936251741003 0.281865614343
    0.90944387175 0.149456305865
    1.00778221854 0.124354994547
    1.0 0.0
    0.75 0.0
    0.84328548027 0.326958840636
    0.786057737686 0.173136888034
    0.90944387175 0.149456305865
    0.875 0.0
    1.0 0.0
    0.75 0.0
    0.84328548027 0.326958840636
    0.786057737686 0.173136888034
    0.90944387175 0.149456305865
    0.875 0.0
    0.75 0.0
    0.646840612344 0.260602391747
    0.84328548027 0.326958840636
    0.744660131483 0.298156113636
    0.786057737686 0.173136888034
    0.692532089108 0.12062366858
    0.75 0.0
    0.646840612344 0.260602391747
    0.84328548027 0.326958840636
    0.744660131483 0.298156113636
    0.786057737686 0.173136888034
    0.692532089108 0.12062366858
    0.5 0.0
    0.75 0.0
    0.646840612344 0.260602391747
    0.692532089108 0.12062366858
    0.568639335998 0.147078355388
    0.625 0.0
    0.5 0.0
    0.75 0.0
    0.646840612344 0.260602391747
    0.692532089108 0.12062366858
    0.568639335998 0.147078355388
    0.625 0.0
    1.25 -2.4980915448
    0.988211768803 -2.53604798998
    1.1574664573 -2.35619449019
    1.06853113518 -2.439008604
    1.2007093667 -2.4298745779
    1.11890711187 -2.51484975238
    1.25 -2.4980915448
    0.988211768803 -2.53604798998
    1.1574664573 -2.35619449019
    1.06853113518 -2.439008604
    1.2007093667 -2.4298745779
    1.11890711187 -2.51484975238
    1.25 -2.21429743559
    1.04166666667 -2.21429743559
    1.1574664573 -2.35619449019
    1.096807962 -2.28898816441
    1.2007093667 -2.28251440249
    1.14583333333 -2.21429743559
    1.25 -2.21429743559
    1.04166666667 -2.21429743559
    1.1574664573 -2.35619449019
    1.096807962 -2.28898816441
    1.2007093667 -2.28251440249
    1.14583333333 -2.21429743559
    1.11803398875 -2.67794504459
    0.838525491562 -2.67794504459
    0.988211768803 -2.53604798998
    0.91108623357 -2.60117315332
    1.05048351962 -2.61137688081
    0.978279740156 -2.67794504459
    1.11803398875 -2.67794504459
    0.838525491562 -2.67794504459
    0.988211768803 -2.53604798998
    0.91108623357 -2.60117315332
    1.05048351962 -2.61137688081
    0.978279740156 -2.67794504459
    0.77400876924 1.38176484732
    0.840949195133 1.03120808153
    1.0307764064 1.32581766367
    0.925832455158 1.19356013832
    0.902046687265 1.34981042201
    0.795128237089 1.19914593294
    0.77400876924 1.38176484732
    0.840949195133 1.03120808153
    1.0307764064 1.32581766367
    0.925832455158 1.19356013832
    0.902046687265 1.34981042201
    0.795128237089 1.19914593294
    1.11803398875 1.10714871779
    0.840949195133 1.03120808153
    1.0307764064 1.32581766367
    0.925832455158 1.19356013832
    1.06800046816 1.21202565652
    0.978799717613 1.07455157268
    1.11803398875 1.10714871779
    0.840949195133 1.03120808153
    1.0307764064 1.32581766367
    0.925832455158 1.19356013832
    1.06800046816 1.21202565652
    0.978799717613 1.07455157268
    0.838525491562 -2.67794504459
    1.0307764064 -2.89661399046
    0.880483081972 -2.99914386798
    0.954382045168 -2.94384415896
    0.848450481588 -2.84249840123
    0.929129296707 -2.79856871317
    0.838525491562 -2.67794504459
    1.0307764064 -2.89661399046
    0.880483081972 -2.99914386798
    0.954382045168 -2.94384415896
    0.848450481588 -2.84249840123
    0.929129296707 -2.79856871317
    1.0 3.14159265359
    1.0307764064 -2.89661399046
    0.880483081972 -2.99914386798
    0.954382045168 -2.94384415896
    0.937867308386 -3.07490267285
    1.00778221854 -3.01723765904
    1.0 3.14159265359
    1.0307764064 -2.89661399046
    0.880483081972 -2.99914386798
    0.954382045168 -2.94384415896
    0.937867308386 -3.07490267285
    1.00778221854 -3.01723765904
    0.957540432857 2.35619449019
    1.06193561665 2.20005789176
    1.15379069349 2.35619449019
    1.10449465302 2.28136916743
    1.05566556317 2.35619449019
    1.00667081356 2.2740823166
    0.957540432857 2.35619449019
    1.06193561665 2.20005789176
    1.15379069349 2.35619449019
    1.10449465302 2.28136916743
    1.05566556317 2.35619449019
    1.00667081356 2.2740823166
    1.11803398875 2.0344439358
    1.25 2.21429743559
    1.06193561665 2.20005789176
    1.15593870365 2.20775683118
    1.08625240464 2.11511511498
    1.17924764151 2.12939564214
    1.11803398875 2.0344439358
    1.25 2.21429743559
    1.06193561665 2.20005789176
    1.15593870365 2.20775683118
    1.08625240464 2.11511511498
    1.17924764151 2.12939564214
    0.771818064702 -1.94378404859
    0.75 -1.57079632679
    0.638067482233 -1.77352801529
    0.690494408356 -1.66396019237
    0.702413048335 -1.866751197
    0.747717882125 -1.75999534889
    0.771818064702 -1.94378404859
    0.75 -1.57079632679
    0.638067482233 -1.77352801529
    0.690494408356 -1.66396019237
    0.702413048335 -1.866751197
    0.747717882125 -1.75999534889
    1.0 -1.57079632679
    0.75 -1.57079632679
    1.0307764064 -1.81577498992
    0.883883476483 -1.7126933814
    1.00778221854 -1.69515132134
    0.875 -1.57079632679
    1.0 -1.57079632679
    0.75 -1.57079632679
    1.0307764064 -1.81577498992
    0.883883476483 -1.7126933814
    1.00778221854 -1.69515132134
    0.875 -1.57079632679
    0.771818064702 -1.94378404859
    0.75 -1.57079632679
    1.0307764064 -1.81577498992
    0.883883476483 -1.7126933814
    0.899489872789 -1.87057239689
    0.747717882125 -1.75999534889
    0.771818064702 -1.94378404859
    0.75 -1.57079632679
    1.0307764064 -1.81577498992
    0.883883476483 -1.7126933814
    0.899489872789 -1.87057239689
    0.747717882125 -1.75999534889
    1.11803398875 -2.0344439358
    1.04166666667 -2.21429743559
    0.931986099831 -2.05943872941
    0.983878843214 -2.14117960844
    1.02493065907 -2.04580708306
    1.07549245826 -2.12118227447
    1.11803398875 -2.0344439358
    1.04166666667 -2.21429743559
    0.931986099831 -2.05943872941
    0.983878843214 -2.14117960844
    1.02493065907 -2.04580708306
    1.07549245826 -2.12118227447
    0.779284659479 2.8150112189
    1.0307764064 2.89661399046
    0.877991323518 2.99873682651
    0.953147942644 2.94358472395
    0.82515652504 2.91236072031
    0.904291857849 2.86148467829
    0.779284659479 2.8150112189
    1.0307764064 2.89661399046
    0.877991323518 2.99873682651
    0.953147942644 2.94358472395
    0.82515652504 2.91236072031
    0.904291857849 2.86148467829
    1.25 2.4980915448
    1.15379069349 2.35619449019
    1.06714978856 2.50147742847
    1.10754613661 2.42599716227
    1.15857324435 2.4996508936
    1.19887647887 2.42998742756
    1.25 2.4980915448
    1.15379069349 2.35619449019
    1.06714978856 2.50147742847
    1.10754613661 2.42599716227
    1.15857324435 2.4996508936
    1.19887647887 2.42998742756
    0.957540432857 2.35619449019
    0.908305101992 2.59358689818
    1.06714978856 2.50147742847
    0.986686901545 2.54382633687
    1.00968315704 2.43277541526
    0.92636319055 2.47174379477
    0.957540432857 2.35619449019
    0.908305101992 2.59358689818
    1.06714978856 2.50147742847
    0.986686901545 2.54382633687
    1.00968315704 2.43277541526
    0.92636319055 2.47174379477
    1.25 2.21429743559
    1.06193561665 2.20005789176
    1.15379069349 2.35619449019
    1.10449465302 2.28136916743
    1.19887647887 2.28240155282
    1.15593870365 2.20775683118
    1.25 2.21429743559
    1.06193561665 2.20005789176
    1.15379069349 2.35619449019
    1.10449465302 2.28136916743
    1.19887647887 2.28240155282
    1.15593870365 2.20775683118
    1.01646599796 0.785398163397
    1.25 0.927295218002
    1.07246709387 0.94866502143
    1.16116764756 0.937163318725
    1.04099081084 0.869224930386
    1.13041232798 0.863669303919
    1.01646599796 0.785398163397
    1.25 0.927295218002
    1.07246709387 0.94866502143
    1.16116764756 0.937163318725
    1.04099081084 0.869224930386
    1.13041232798 0.863669303919
    1.01646599796 0.785398163397
    1.25 0.643501108793
    0.940417912789 0.580322263015
    1.09467346928 0.616377823912
    0.973310557757 0.686859028498
    1.13041232798 0.707127022876
    1.01646599796 0.785398163397
    1.25 0.643501108793
    0.940417912789 0.580322263015
    1.09467346928 0.616377823912
    0.973310557757 0.686859028498
    1.13041232798 0.707127022876
    1.01646599796 0.785398163397
    1.25 0.643501108793
    1.25 0.927295218002
    1.23743686708 0.785398163397
    1.13041232798 0.863669303919
    1.13041232798 0.707127022876
    1.01646599796 0.785398163397
    1.25 0.643501108793
    1.25 0.927295218002
    1.23743686708 0.785398163397
    1.13041232798 0.863669303919
    1.13041232798 0.707127022876
    1.41421356237 0.785398163397
    1.25 0.643501108793
    1.25 0.927295218002
    1.23743686708 0.785398163397
    1.32876822659 0.851966327173
    1.32876822659 0.718829999622
    1.41421356237 0.785398163397
    1.25 0.643501108793
    1.25 0.927295218002
    1.23743686708 0.785398163397
    1.32876822659 0.851966327173
    1.32876822659 0.718829999622
    0.25 0.0
    0.315642584119 1.13221889849
    0.239347739688 0.639724902832
    0.157821292059 1.13221889849
    0.125 0.0
    0.25 0.0
    0.315642584119 1.13221889849
    0.239347739688 0.639724902832
    0.157821292059 1.13221889849
    0.125 0.0
    0.450693909433 0.588002603548
    0.25 0.0
    0.315642584119 1.13221889849
    0.239347739688 0.639724902832
    0.369516062926 0.81097708807
    0.336572800446 0.380506377112
    0.450693909433 0.588002603548
    0.25 0.0
    0.315642584119 1.13221889849
    0.239347739688 0.639724902832
    0.369516062926 0.81097708807
    0.336572800446 0.380506377112
    0.643493221073 1.73531883021
    0.831205090139 1.82967495711
    0.801038251085 1.61004226427
    0.811207235798 1.72189641291
    0.720866139625 1.66584018214
    0.736542023294 1.78850649709
    0.643493221073 1.73531883021
    0.831205090139 1.82967495711
    0.801038251085 1.61004226427
    0.811207235798 1.72189641291
    0.720866139625 1.66584018214
    0.736542023294 1.78850649709
    1.0 1.57079632679
    0.831205090139 1.82967495711
    0.801038251085 1.61004226427
    0.811207235798 1.72189641291
    0.90034786974 1.58825125982
    0.908008352515 1.68823781149
    1.0 1.57079632679
    0.831205090139 1.82967495711
    0.801038251085 1.61004226427
    0.811207235798 1.72189641291
    0.90034786974 1.58825125982
    0.908008352515 1.68823781149
    0.514062998266 -2.14340425219
    0.279582168163 -2.70090219662
    0.25 -1.57079632679
    0.223772228233 -2.1712499733
    0.368372561031 -1.95849436074
    0.382866836673 -2.33779658963
    0.514062998266 -2.14340425219
    0.279582168163 -2.70090219662
    0.25 -1.57079632679
    0.223772228233 -2.1712499733
    0.368372561031 -1.95849436074
    0.382866836673 -2.33779658963
    0.5 -1.57079632679
    0.514062998266 -2.14340425219
    0.25 -1.57079632679
    0.368372561031 -1.95849436074
    0.375 -1.57079632679
    0.486396439023 -1.86118288757
    0.5 -1.57079632679
    0.514062998266 -2.14340425219
    0.25 -1.57079632679
    0.368372561031 -1.95849436074
    0.375 -1.57079632679
    0.486396439023 -1.86118288757
    0.643493221073 1.73531883021
    0.326687688122 1.90946276725
    0.477870567666 1.49166205304
    0.393845514494 1.66074827278
    0.556617160266 1.63157177579
    0.483449039896 1.79389372295
    0.643493221073 1.73531883021
    0.326687688122 1.90946276725
    0.477870567666 1.49166205304
    0.393845514494 1.66074827278
    0.556617160266 1.63157177579
    0.483449039896 1.79389372295
    0.326687688122 1.90946276725
    0.315642584119 1.13221889849
    0.477870567666 1.49166205304
    0.390635406452 1.34906694959
    0.393845514494 1.66074827278
    0.297223894641 1.52788127162
    0.326687688122 1.90946276725
    0.315642584119 1.13221889849
    0.477870567666 1.49166205304
    0.390635406452 1.34906694959
    0.393845514494 1.66074827278
    0.297223894641 1.52788127162
    0.326687688122 1.90946276725
    0.244167580618 2.68590015531
    0.425122255926 2.53646255808
    0.333779550126 2.5909448553
    0.357905371237 2.26538354874
    0.264648764497 2.23863084596
    0.326687688122 1.90946276725
    0.244167580618 2.68590015531
    0.425122255926 2.53646255808
    0.333779550126 2.5909448553
    0.357905371237 2.26538354874
    0.264648764497 2.23863084596
    0.454462016546 2.96034728553
    0.244167580618 2.68590015531
    0.425122255926 2.53646255808
    0.333779550126 2.5909448553
    0.429962494424 2.75558222397
    0.346329912087 2.86466669296
    0.454462016546 2.96034728553
    0.244167580618 2.68590015531
    0.425122255926 2.53646255808
    0.333779550126 2.5909448553
    0.429962494424 2.75558222397
    0.346329912087 2.86466669296
    1.11803398875 2.67794504459
    1.0307764064 2.89661399046
    0.908305101992 2.59358689818
    0.958478030429 2.75474356205
    1.01227808458 2.64013412652
    1.06800046816 2.78282198332
    1.11803398875 2.67794504459
    1.0307764064 2.89661399046
    0.908305101992 2.59358689818
    0.958478030429 2.75474356205
    1.01227808458 2.64013412652
    1.06800046816 2.78282198332
    0.779284659479 2.8150112189
    1.0307764064 2.89661399046
    0.908305101992 2.59358689818
    0.958478030429 2.75474356205
    0.838659174384 2.69580028973
    0.904291857849 2.86148467829
    0.779284659479 2.8150112189
    1.0307764064 2.89661399046
    0.908305101992 2.59358689818
    0.958478030429 2.75474356205
    0.838659174384 2.69580028973
    0.904291857849 2.86148467829
    0.559016994375 1.10714871779
    0.77400876924 1.38176484732
    0.477870567666 1.49166205304
    0.625047844036 1.42370272466
    0.508950783789 1.28417246843
    0.660403625501 1.26673851026
    0.559016994375 1.10714871779
    0.77400876924 1.38176484732
    0.477870567666 1.49166205304
    0.625047844036 1.42370272466
    0.508950783789 1.28417246843
    0.660403625501 1.26673851026
    0.643493221073 1.73531883021
    0.77400876924 1.38176484732
    0.477870567666 1.49166205304
    0.625047844036 1.42370272466
    0.556617160266 1.63157177579
    0.697799907824 1.54209500332
    0.643493221073 1.73531883021
    0.77400876924 1.38176484732
    0.477870567666 1.49166205304
    0.625047844036 1.42370272466
    0.556617160266 1.63157177579
    0.697799907824 1.54209500332
    0.559016994375 1.10714871779
    0.450693909433 0.588002603548
    0.689105089525 0.835854309646
    0.565720874237 0.737977588851
    0.618390987892 0.957277006395
    0.488140604744 0.876058050598
    0.559016994375 1.10714871779
    0.450693909433 0.588002603548
    0.689105089525 0.835854309646
    0.565720874237 0.737977588851
    0.618390987892 0.957277006395
    0.488140604744 0.876058050598
    0.728868986856 0.540419500271
    0.450693909433 0.588002603548
    0.689105089525 0.835854309646
    0.565720874237 0.737977588851
    0.701271997093 0.683964131434
    0.589623820754 0.558599315344
    0.728868986856 0.540419500271
    0.450693909433 0.588002603548
    0.689105089525 0.835854309646
    0.565720874237 0.737977588851
    0.701271997093 0.683964131434
    0.589623820754 0.558599315344
    0.883883476483 -2.35619449019
    0.715084405928 -2.20973623988
    0.712034584876 -2.48462922381
    0.706830012319 -2.34688713842
    0.796333346992 -2.41348750297
    0.797365191347 -2.29070967539
    0.883883476483 -2.35619449019
    0.715084405928 -2.20973623988
    0.712034584876 -2.48462922381
    0.706830012319 -2.34688713842
    0.796333346992 -2.41348750297
    0.797365191347 -2.29070967539
    0.771818064702 -1.94378404859
    0.715084405928 -2.20973623988
    0.931986099831 -2.05943872941
    0.821251321333 -2.12467284513
    0.85049069272 -2.00705352732
    0.736897422219 -2.07165628657
    0.771818064702 -1.94378404859
    0.715084405928 -2.20973623988
    0.931986099831 -2.05943872941
    0.821251321333 -2.12467284513
    0.85049069272 -2.00705352732
    0.736897422219 -2.07165628657
    0.883883476483 -2.35619449019
    0.715084405928 -2.20973623988
    0.931986099831 -2.05943872941
    0.821251321333 -2.12467284513
    0.897965606748 -2.20385697969
    0.797365191347 -2.29070967539
    0.883883476483 -2.35619449019
    0.715084405928 -2.20973623988
    0.931986099831 -2.05943872941
    0.821251321333 -2.12467284513
    0.897965606748 -2.20385697969
    0.797365191347 -2.29070967539
    0.883883476483 -2.35619449019
    1.04166666667 -2.21429743559
    0.931986099831 -2.05943872941
    0.983878843214 -2.14117960844
    0.897965606748 -2.20385697969
    0.960369214301 -2.27942259892
    0.883883476483 -2.35619449019
    1.04166666667 -2.21429743559
    0.931986099831 -2.05943872941
    0.983878843214 -2.14117960844
    0.897965606748 -2.20385697969
    0.960369214301 -2.27942259892
    0.728868986856 0.540419500271
    0.450693909433 0.588002603548
    0.646840612344 0.260602391747
    0.541666666667 0.3947911197
    0.681157613511 0.408907828951
    0.589623820754 0.558599315344
    0.728868986856 0.540419500271
    0.450693909433 0.588002603548
    0.646840612344 0.260602391747
    0.541666666667 0.3947911197
    0.681157613511 0.408907828951
    0.589623820754 0.558599315344
    0.5 0.0
    0.450693909433 0.588002603548
    0.646840612344 0.260602391747
    0.541666666667 0.3947911197
    0.568639335998 0.147078355388
    0.45500686808 0.278299659005
    0.5 0.0
    0.450693909433 0.588002603548
    0.646840612344 0.260602391747
    0.541666666667 0.3947911197
    0.568639335998 0.147078355388
    0.45500686808 0.278299659005
    1.11803398875 0.463647609001
    1.0307764064 0.244978663127
    0.84328548027 0.326958840636
    0.936251741003 0.281865614343
    0.978415294851 0.404891786285
    1.06800046816 0.358770670271
    1.11803398875 0.463647609001
    1.0307764064 0.244978663127
    0.84328548027 0.326958840636
    0.936251741003 0.281865614343
    0.978415294851 0.404891786285
    1.06800046816 0.358770670271
    0.728868986856 0.540419500271
    0.689105089525 0.835854309646
    0.940417912789 0.580322263015
    0.808278989591 0.688278265981
    0.834480005357 0.562899652712
    0.701271997093 0.683964131434
    0.728868986856 0.540419500271
    0.689105089525 0.835854309646
    0.940417912789 0.580322263015
    0.808278989591 0.688278265981
    0.834480005357 0.562899652712
    0.701271997093 0.683964131434
    0.883883476483 -2.35619449019
    1.04166666667 -2.21429743559
    1.1574664573 -2.35619449019
    1.096807962 -2.28898816441
    1.02067496689 -2.35619449019
    0.960369214301 -2.27942259892
    0.883883476483 -2.35619449019
    1.04166666667 -2.21429743559
    1.1574664573 -2.35619449019
    1.096807962 -2.28898816441
    1.02067496689 -2.35619449019
    0.960369214301 -2.27942259892
    0.883883476483 -2.35619449019
    0.988211768803 -2.53604798998
    1.1574664573 -2.35619449019
    1.06853113518 -2.439008604
    1.02067496689 -2.35619449019
    0.932277118136 -2.45114619654
    0.883883476483 -2.35619449019
    0.988211768803 -2.53604798998
    1.1574664573 -2.35619449019
    1.06853113518 -2.439008604
    1.02067496689 -2.35619449019
    0.932277118136 -2.45114619654
    0.728868986856 0.540419500271
    0.84328548027 0.326958840636
    0.940417912789 0.580322263015
    0.884726208183 0.460576096062
    0.834480005357 0.562899652712
    0.781627994976 0.425892199142
    0.728868986856 0.540419500271
    0.84328548027 0.326958840636
    0.940417912789 0.580322263015
    0.884726208183 0.460576096062
    0.834480005357 0.562899652712
    0.781627994976 0.425892199142
    1.11803398875 0.463647609001
    0.84328548027 0.326958840636
    0.940417912789 0.580322263015
    0.884726208183 0.460576096062
    1.02748814073 0.516945551939
    0.978415294851 0.404891786285
    1.11803398875 0.463647609001
    0.84328548027 0.326958840636
    0.940417912789 0.580322263015
    0.884726208183 0.460576096062
    1.02748814073 0.516945551939
    0.978415294851 0.404891786285
    0.805564012005 2.07265137974
    1.0307764064 1.81577498992
    0.831205090139 1.82967495711
    0.930968522183 1.82198004697
    0.812354034897 1.94925055808
    0.910721594848 1.92837540495
    0.805564012005 2.07265137974
    1.0307764064 1.81577498992
    0.831205090139 1.82967495711
    0.930968522183 1.82198004697
    0.812354034897 1.94925055808
    0.910721594848 1.92837540495
    0.805564012005 2.07265137974
    0.831205090139 1.82967495711
    0.614930471097 2.03853022605
    0.719217124137 1.9184293389
    0.7101457423 2.05788058868
    0.812354034897 1.94925055808
    0.805564012005 2.07265137974
    0.831205090139 1.82967495711
    0.614930471097 2.03853022605
    0.719217124137 1.9184293389
    0.7101457423 2.05788058868
    0.812354034897 1.94925055808
    1.41421356237 -2.35619449019
    1.25 -2.4980915448
    1.1574664573 -2.35619449019
    1.2007093667 -2.4298745779
    1.28584000984 -2.35619449019
    1.32876822659 -2.42276265397
    1.41421356237 -2.35619449019
    1.25 -2.4980915448
    1.1574664573 -2.35619449019
    1.2007093667 -2.4298745779
    1.28584000984 -2.35619449019
    1.32876822659 -2.42276265397
    1.41421356237 -2.35619449019
    1.25 -2.21429743559
    1.1574664573 -2.35619449019
    1.2007093667 -2.28251440249
    1.28584000984 -2.35619449019
    1.32876822659 -2.28962632642
    1.41421356237 -2.35619449019
    1.25 -2.21429743559
    1.1574664573 -2.35619449019
    1.2007093667 -2.28251440249
    1.28584000984 -2.35619449019
    1.32876822659 -2.28962632642
    0.589255650989 2.35619449019
    0.326687688122 1.90946276725
    0.614930471097 2.03853022605
    0.469920974604 1.99377608338
    0.594517785856 2.19394709478
    0.447540302659 2.19785434363
    0.589255650989 2.35619449019
    0.326687688122 1.90946276725
    0.614930471097 2.03853022605
    0.469920974604 1.99377608338
    0.594517785856 2.19394709478
    0.447540302659 2.19785434363
    0.643493221073 1.73531883021
    0.326687688122 1.90946276725
    0.614930471097 2.03853022605
    0.469920974604 1.99377608338
    0.621998431969 1.8834569026
    0.483449039896 1.79389372295
    0.643493221073 1.73531883021
    0.326687688122 1.90946276725
    0.614930471097 2.03853022605
    0.469920974604 1.99377608338
    0.621998431969 1.8834569026
    0.483449039896 1.79389372295
    0.559016994375 -2.67794504459
    0.514062998266 -2.14340425219
    0.712034584876 -2.48462922381
    0.604381629764 -2.34182791758
    0.632602412669 -2.5696149718
    0.517524391594 -2.42214521764
    0.559016994375 -2.67794504459
    0.514062998266 -2.14340425219
    0.712034584876 -2.48462922381
    0.604381629764 -2.34182791758
    0.632602412669 -2.5696149718
    0.517524391594 -2.42214521764
    0.559016994375 -2.67794504459
    0.838525491562 -2.67794504459
    0.712034584876 -2.48462922381
    0.771685371453 -2.58919673402
    0.632602412669 -2.5696149718
    0.698771242969 -2.67794504459
    0.559016994375 -2.67794504459
    0.838525491562 -2.67794504459
    0.712034584876 -2.48462922381
    0.771685371453 -2.58919673402
    0.632602412669 -2.5696149718
    0.698771242969 -2.67794504459
    0.957540432857 2.35619449019
    0.908305101992 2.59358689818
    0.774304298205 2.30780767414
    0.832785316181 2.46215441077
    0.865671793817 2.33456133594
    0.92636319055 2.47174379477
    0.957540432857 2.35619449019
    0.908305101992 2.59358689818
    0.774304298205 2.30780767414
    0.832785316181 2.46215441077
    0.865671793817 2.33456133594
    0.92636319055 2.47174379477
    0.589255650989 2.35619449019
    0.774304298205 2.30780767414
    0.605812056484 2.68369655179
    0.678089226809 2.47253694825
    0.589542027833 2.52223461211
    0.681584129395 2.32871716713
    0.589255650989 2.35619449019
    0.774304298205 2.30780767414
    0.605812056484 2.68369655179
    0.678089226809 2.47253694825
    0.589542027833 2.52223461211
    0.681584129395 2.32871716713
    0.957540432857 2.35619449019
    0.805564012005 2.07265137974
    1.06193561665 2.20005789176
    0.931891557273 2.14511148665
    1.00667081356 2.2740823166
    0.872773860983 2.22672530376
    0.957540432857 2.35619449019
    0.805564012005 2.07265137974
    1.06193561665 2.20005789176
    0.931891557273 2.14511148665
    1.00667081356 2.2740823166
    0.872773860983 2.22672530376
    1.11803398875 2.0344439358
    0.805564012005 2.07265137974
    1.06193561665 2.20005789176
    0.931891557273 2.14511148665
    1.08625240464 2.11511511498
    0.961628131695 2.05044407445
    1.11803398875 2.0344439358
    0.805564012005 2.07265137974
    1.06193561665 2.20005789176
    0.931891557273 2.14511148665
    1.08625240464 2.11511511498
    0.961628131695 2.05044407445
    1.41421356237 2.35619449019
    1.25 2.21429743559
    1.15379069349 2.35619449019
    1.19887647887 2.28240155282
    1.28400212793 2.35619449019
    1.32876822659 2.28962632642
    1.41421356237 2.35619449019
    1.25 2.21429743559
    1.15379069349 2.35619449019
    1.19887647887 2.28240155282
    1.28400212793 2.35619449019
    1.32876822659 2.28962632642
    1.41421356237 2.35619449019
    1.25 2.4980915448
    1.15379069349 2.35619449019
    1.19887647887 2.42998742756
    1.28400212793 2.35619449019
    1.32876822659 2.42276265397
    1.41421356237 2.35619449019
    1.25 2.4980915448
    1.15379069349 2.35619449019
    1.19887647887 2.42998742756
    1.28400212793 2.35619449019
    1.32876822659 2.42276265397
    0.779284659479 2.8150112189
    0.605812056484 2.68369655179
    0.63233233558 2.96893094079
    0.612789898189 2.82938938868
    0.703742014526 2.88394371266
    0.691079576981 2.7575886068
    0.779284659479 2.8150112189
    0.605812056484 2.68369655179
    0.63233233558 2.96893094079
    0.612789898189 2.82938938868
    0.703742014526 2.88394371266
    0.691079576981 2.7575886068
    0.454462016546 2.96034728553
    0.605812056484 2.68369655179
    0.63233233558 2.96893094079
    0.612789898189 2.82938938868
    0.543392305497 2.96534153981
    0.525176989777 2.80215221363
    0.454462016546 2.96034728553
    0.605812056484 2.68369655179
    0.63233233558 2.96893094079
    0.612789898189 2.82938938868
    0.543392305497 2.96534153981
    0.525176989777 2.80215221363
    0.908305101992 2.59358689818
    0.774304298205 2.30780767414
    0.605812056484 2.68369655179
    0.678089226809 2.47253694825
    0.756320996808 2.6296347388
    0.832785316181 2.46215441077
    0.908305101992 2.59358689818
    0.774304298205 2.30780767414
    0.605812056484 2.68369655179
    0.678089226809 2.47253694825
    0.756320996808 2.6296347388
    0.832785316181 2.46215441077
    0.779284659479 2.8150112189
    0.908305101992 2.59358689818
    0.605812056484 2.68369655179
    0.756320996808 2.6296347388
    0.691079576981 2.7575886068
    0.838659174384 2.69580028973
    0.779284659479 2.8150112189
    0.908305101992 2.59358689818
    0.605812056484 2.68369655179
    0.756320996808 2.6296347388
    0.691079576981 2.7575886068
    0.838659174384 2.69580028973
    1.11803398875 -2.0344439358
    1.0307764064 -1.81577498992
    0.931986099831 -2.05943872941
    0.974125431299 -1.93144434154
    1.02493065907 -2.04580708306
    1.06800046816 -1.92956699707
    1.11803398875 -2.0344439358
    1.0307764064 -1.81577498992
    0.931986099831 -2.05943872941
    0.974125431299 -1.93144434154
    1.02493065907 -2.04580708306
    1.06800046816 -1.92956699707
    0.771818064702 -1.94378404859
    1.0307764064 -1.81577498992
    0.931986099831 -2.05943872941
    0.974125431299 -1.93144434154
    0.85049069272 -2.00705352732
    0.899489872789 -1.87057239689
    0.771818064702 -1.94378404859
    1.0307764064 -1.81577498992
    0.931986099831 -2.05943872941
    0.974125431299 -1.93144434154
    0.85049069272 -2.00705352732
    0.899489872789 -1.87057239689
    0.838525491562 -2.67794504459
    0.712097781161 -3.07667454315
    0.880483081972 -2.99914386798
    0.795698883439 -3.03380847305
    0.848450481588 -2.84249840123
    0.760057829771 -2.86083754495
    0.838525491562 -2.67794504459
    0.712097781161 -3.07667454315
    0.880483081972 -2.99914386798
    0.795698883439 -3.03380847305
    0.848450481588 -2.84249840123
    0.760057829771 -2.86083754495
    0.779284659479 2.8150112189
    0.877991323518 2.99873682651
    0.63233233558 2.96893094079
    0.755080189927 2.98625806984
    0.703742014526 2.88394371266
    0.82515652504 2.91236072031
    0.779284659479 2.8150112189
    0.877991323518 2.99873682651
    0.63233233558 2.96893094079
    0.755080189927 2.98625806984
    0.703742014526 2.88394371266
    0.82515652504 2.91236072031
    0.643493221073 1.73531883021
    0.77400876924 1.38176484732
    0.801038251085 1.61004226427
    0.782400802597 1.49787084537
    0.720866139625 1.66584018214
    0.697799907824 1.54209500332
    0.643493221073 1.73531883021
    0.77400876924 1.38176484732
    0.801038251085 1.61004226427
    0.782400802597 1.49787084537
    0.720866139625 1.66584018214
    0.697799907824 1.54209500332
    1.0 1.57079632679
    0.77400876924 1.38176484732
    0.801038251085 1.61004226427
    0.782400802597 1.49787084537
    0.90034786974 1.58825125982
    0.883109816827 1.48835635534
    1.0 1.57079632679
    0.77400876924 1.38176484732
    0.801038251085 1.61004226427
    0.782400802597 1.49787084537
    0.90034786974 1.58825125982
    0.883109816827 1.48835635534
    1.11803398875 2.67794504459
    1.25 2.4980915448
    1.06714978856 2.50147742847
    1.15857324435 2.4996508936
    1.08834393046 2.59177119502
    1.17924764151 2.58299333825
    1.11803398875 2.67794504459
    1.25 2.4980915448
    1.06714978856 2.50147742847
    1.15857324435 2.4996508936
    1.08834393046 2.59177119502
    1.17924764151 2.58299333825
    1.11803398875 2.67794504459
    0.908305101992 2.59358689818
    1.06714978856 2.50147742847
    0.986686901545 2.54382633687
    1.08834393046 2.59177119502
    1.01227808458 2.64013412652
    1.11803398875 2.67794504459
    0.908305101992 2.59358689818
    1.06714978856 2.50147742847
    0.986686901545 2.54382633687
    1.08834393046 2.59177119502
    1.01227808458 2.64013412652
    1.11803398875 1.10714871779
    0.840949195133 1.03120808153
    1.07246709387 0.94866502143
    0.95590539314 0.984940018681
    1.09181514266 1.02955871926
    0.978799717613 1.07455157268
    1.11803398875 1.10714871779
    0.840949195133 1.03120808153
    1.07246709387 0.94866502143
    0.95590539314 0.984940018681
    1.09181514266 1.02955871926
    0.978799717613 1.07455157268
    1.01646599796 0.785398163397
    0.840949195133 1.03120808153
    1.07246709387 0.94866502143
    0.95590539314 0.984940018681
    1.04099081084 0.869224930386
    0.921764855969 0.896630890953
    1.01646599796 0.785398163397
    0.840949195133 1.03120808153
    1.07246709387 0.94866502143
    0.95590539314 0.984940018681
    1.04099081084 0.869224930386
    0.921764855969 0.896630890953
    0.5 -1.57079632679
    0.514062998266 -2.14340425219
    0.638067482233 -1.77352801529
    0.56635673524 -1.93833377608
    0.56615592196 -1.68450128659
    0.486396439023 -1.86118288757
    0.5 -1.57079632679
    0.514062998266 -2.14340425219
    0.638067482233 -1.77352801529
    0.56635673524 -1.93833377608
    0.56615592196 -1.68450128659
    0.486396439023 -1.86118288757
    0.771818064702 -1.94378404859
    0.514062998266 -2.14340425219
    0.638067482233 -1.77352801529
    0.56635673524 -1.93833377608
    0.702413048335 -1.866751197
    0.639869563579 -2.02352319237
    0.771818064702 -1.94378404859
    0.514062998266 -2.14340425219
    0.638067482233 -1.77352801529
    0.56635673524 -1.93833377608
    0.702413048335 -1.866751197
    0.639869563579 -2.02352319237
    0.712097781161 -3.07667454315
    0.877991323518 2.99873682651
    0.63233233558 2.96893094079
    0.755080189927 2.98625806984
    0.667494539602 3.09480191444
    0.790804930667 3.0917465659
    0.712097781161 -3.07667454315
    0.877991323518 2.99873682651
    0.63233233558 2.96893094079
    0.755080189927 2.98625806984
    0.667494539602 3.09480191444
    0.790804930667 3.0917465659
    0.454462016546 2.96034728553
    0.712097781161 -3.07667454315
    0.63233233558 2.96893094079
    0.667494539602 3.09480191444
    0.543392305497 2.96534153981
    0.579083387317 3.11074304287
    0.454462016546 2.96034728553
    0.712097781161 -3.07667454315
    0.63233233558 2.96893094079
    0.667494539602 3.09480191444
    0.543392305497 2.96534153981
    0.579083387317 3.11074304287
    0.712097781161 -3.07667454315
    0.877991323518 2.99873682651
    0.880483081972 -2.99914386798
    0.870306283253 3.14159265359
    0.795698883439 -3.03380847305
    0.790804930667 3.0917465659
    0.712097781161 -3.07667454315
    0.877991323518 2.99873682651
    0.880483081972 -2.99914386798
    0.870306283253 3.14159265359
    0.795698883439 -3.03380847305
    0.790804930667 3.0917465659
    1.0 3.14159265359
    0.877991323518 2.99873682651
    0.880483081972 -2.99914386798
    0.870306283253 3.14159265359
    0.937867308386 -3.07490267285
    0.936611445887 3.07481311801
    1.0 3.14159265359
    0.877991323518 2.99873682651
    0.880483081972 -2.99914386798
    0.870306283253 3.14159265359
    0.937867308386 -3.07490267285
    0.936611445887 3.07481311801

    <dolfin.cpp.io.VTKPlotter; proxy of <Swig Object of type 'std::shared_ptr< dolfin::VTKPlotter > *' at 0x1172a17e0> >

```

```

```

```

```
ccode

```

```
import ExactSol
u0, p0,b0, r0, Laplacian, Advection, gradPres,CurlCurl, gradR, NS_Couple, M_Couple = ExactSol.MHD2D(7,5, mesh)
```

       >>>>>>>>>>>>>>>>>>>>>>>>>>
         MHD 2D Exact Solution:
       >>>>>>>>>>>>>>>>>>>>>>>>>>

     ----------------------
       NS Exact Solution:
     ----------------------
      u = ( (x**2 + y**2)**0.27224186839123*(x*(-0.45551626321754*sin(0.45551626321754*atan2(y, x)) + 1.54448373678246*sin(1.54448373678246*atan2(y, x)) + 0.838771399357052*cos(0.45551626321754*atan2(y, x)) - 0.838771399357052*cos(1.54448373678246*atan2(y, x)))/sqrt(x**2 + y**2) + 1.54448373678246*y*(1.84136433117094*sin(0.45551626321754*atan2(y, x)) - 0.543075578836731*sin(1.54448373678246*atan2(y, x)) + cos(0.45551626321754*atan2(y, x)) - cos(1.54448373678246*atan2(y, x)))/sqrt(x**2 + y**2)) , (x**2 + y**2)**0.27224186839123*(-1.54448373678246*x*(1.84136433117094*sin(0.45551626321754*atan2(y, x)) - 0.543075578836731*sin(1.54448373678246*atan2(y, x)) + cos(0.45551626321754*atan2(y, x)) - cos(1.54448373678246*atan2(y, x)))/sqrt(x**2 + y**2) + y*(-0.45551626321754*sin(0.45551626321754*atan2(y, x)) + 1.54448373678246*sin(1.54448373678246*atan2(y, x)) + 0.838771399357052*cos(0.45551626321754*atan2(y, x)) - 0.838771399357052*cos(1.54448373678246*atan2(y, x)))/sqrt(x**2 + y**2)) )

      p = ( -2.19531130005436*(x**2 + y**2)**(-0.22775813160877)*(-0.992084788647475*sin(0.45551626321754*atan2(y, x)) + 1.82678954331272*cos(0.45551626321754*atan2(y, x))) )

     ---------------------------
       Maxwell Exact Solution:
     ---------------------------
      b = ( 0.666666666666667*x*(x**2 + y**2)**(-0.666666666666667)*sin(0.666666666666667*atan2(y, x)) - 0.666666666666667*y*(x**2 + y**2)**(-0.666666666666667)*cos(0.666666666666667*atan2(y, x)) , 0.666666666666667*x*(x**2 + y**2)**(-0.666666666666667)*cos(0.666666666666667*atan2(y, x)) + 0.666666666666667*y*(x**2 + y**2)**(-0.666666666666667)*sin(0.666666666666667*atan2(y, x)) )

      p = ( 0 )

```
float('nan')
u = interpolate(u0,Velocity).vector().array()
```

```
p = np.zeros(mesh.num_vertices())
for I in range(mesh.num_vertices()):
    if abs(p0(mesh.coordinates()[I])) == np.inf:
        p[I] = 0
    else:
        p[I] = p0(mesh.coordinates()[I])
P = Function(Lagrange)
P.vector()[:] = p
```

```
for i in range(len(interpolate(u0,Velocity).vector().array())):
    if u[i] == float('nan'):
        u[i] = 0
U = Function(Velocity)
U.vector()[:] = u
```

```
plot(interpolate(u0,Velocity))
```

    <dolfin.cpp.io.VTKPlotter; proxy of <Swig Object of type 'std::shared_ptr< dolfin::VTKPlotter > *' at 0x11354e510> >


```python
import numpy as np
import matplotlib.pyplot as plt

from collections import defaultdict
from scipy.optimize import minimize

import networkx as nx
from networkx.generators.random_graphs import erdos_renyi_graph

from IPython.display import Image
```

```python
from qiskit import QuantumCircuit, execute, Aer
from qiskit.tools.visualization import circuit_drawer, plot_histogram
```

```python
from quantuminspire.credentials import get_authentication
from quantuminspire.api import QuantumInspireAPI
from quantuminspire.qiskit import QI

QI_URL = 'https://api.quantum-inspire.com/'
```

In this notebook you will apply what you have just learned about cqasm and Quantum Inspire. We will consider a simple quantum algorithm, the quantum approximate optimization algorithm (QAOA), for which you will code the circuit in cqasm and send some jobs to real quantum hardware on the Quantum Inspire platform.

## 1. Recap: QAOA and MAXCUT

### Introduction to the Quantum Approximate Optimization Algorithm

$$\newcommand{\ket}[1]{\left|{#1}\right\rangle}$$
$$\newcommand{\bra}[1]{\left\langle{#1}\right|}$$
$$\newcommand{\braket}[2]{\left\langle{#1}\middle|{#2}\right\rangle}$$

Consider some combinatorial optimization problem with objective function $C:x\rightarrow \mathbb{R}$ acting on $n$-bit strings $x\in \{0,1\}^n$, domain $\mathcal{D} \subseteq \{0,1\}^n$, and objective

\begin{align}
     \max_{x \in \mathcal{D}} C(x).
\end{align}

In maximization, an approximate optimization algorithm aims to find a string $x'$ that achieves a desired approximation ratio $\alpha$, i.e.

\begin{equation}
    \frac{C(x')}{C^*}\geq \alpha,
\end{equation}

where $C^* = \max_{x \in \mathcal{D}} C(x)$.
In QAOA, such combinatorial optimization problems are encoded into a cost Hamiltonian $H_C$, a mixing Hamiltonian $H_M$ and some initial quantum state $\ket{\psi_0}$. The cost Hamiltonian is diagonal in the computational basis by design, and represents $C$ if its eigenvalues satisfy

\begin{align}
    H_C \ket{x} = C(x) \ket{x} \text{ for all } x \in  \{0,1\}^n.
\end{align}

The mixing Hamiltonian $H_M$ depends on $\mathcal{D}$ and its structure, and is in the unconstrained case (i.e. when $\mathcal{D}=\{0,1\}^n$) usually taken to be the transverse field Hamiltonian $H_M = \sum_{j} X_j$. Constraints (i.e. when $\mathcal{D}\subset \{0,1\}^n$) can be incorporated directly into the mixing Hamiltonian or are added as a penalty function in the cost Hamiltonian. The initial quantum state $\ket{\psi_0}$ is usually taken as the uniform superposition over all possible states in the domain. $\text{QAOA}_p$, parametrized in $\gamma=(\gamma_0,\gamma_1,\dots,\gamma_{p-1}),\beta=(\beta_0,\beta_1,\dots,\beta_{p-1})$, refers to a level-$p$ QAOA circuit that applies $p$ steps of alternating time evolutions of the cost and mixing Hamiltonians on the initial state. At step $k$, the unitaries of the time evolutions are given by

\begin{align}
    U_C(\gamma_k) = e^{-i \gamma_k H_C }, \label{eq:UC} \\
    U_M(\beta_k) = e^{-i \beta_k H_M }. \label{eq:UM}
\end{align}

So the final state $\ket{\gamma,\beta}$ of $\text{QAOA}_p$ is given by

\begin{align}
    \ket{\gamma,\beta} = \prod_{k=0}^{p-1} U_M(\beta_k) U_C(\gamma_k) \ket{\psi_0}.
\end{align}

The expectation value $ F_p(\gamma,\beta)$ of the cost Hamiltonian for state $\ket{\gamma,\beta}$ is given by

\begin{align}
    F_p(\gamma,\beta) =
    \bra{\gamma,\beta}H_C\ket{\gamma,\beta},
    \label{eq:Fp}
\end{align}

and can be statistically estimated by taking samples of $\ket{\gamma,\beta}$. The achieved approximation ratio (in expectation) of $\text{QAOA}_p$ is then

\begin{equation}
    \alpha = \frac{F_p(\gamma,\beta)}{C^*}.
\end{equation}

The parameter combinations of $\gamma,\beta$ are usually found through a classical optimization procedure that uses $F_p(\gamma,\beta)$ as a black-box function to be maximized.

### Example application: MAXCUT

MaxCut is an NP-hard optimisation problem that looks for an optimal 'cut' for a graph $G(V,E)$, in the sense that the cut generates a subset of nodes $S \subset V$ that shares the largest amount of edges with its complement $ V\setminus S$. In slightly modified form (omitting the constant), it has the following objective function

\begin{align}
\max_{s} \frac{1}{2} \sum_{
\langle i,j \rangle \in E} 1-s_i s_j,
\end{align}

where the $s_i\in\{-1,1\}$ are the variables and $i,j$ are the edge indices. This function can be easily converted into an Ising cost Hamiltonian, which takes the form

\begin{align}
H_C = \frac{1}{2}\sum_{\langle i,j\rangle \in E} I-Z_i Z_j.
\end{align}

We use the standard mixing Hamiltonian that sums over all nodes:

\begin{align}
H_M = \sum_{v \in V} X_v.
\end{align}

As the initial state $\ket{\Psi_0}$ we take the uniform superposition, given by

\begin{align}
\ket{\psi_0} = \frac{1}{\sqrt{2^{|V|}}}\sum_{x=0}^{2^{|V|}-1} \ket{x}
\end{align}

The goal of this workshop is to guide you through an implemented code that simulates a small quantum computer running the QAOA algorithm applied to the MAXCUT problem. We will use qiskit as well as cqasm as SDK's. For the sake of run time, you will always run the classical optimization part using the qiskit simulator: it would take too long for our purposes to do the actual function evualtions in the classical optimization step on the hardware.

## 2. Some useful functions and intializations

We first define some useful functions to be used later throughout the code.

```python
# Just some function to draw graphs
def draw_cc_graph(G,node_color='b',fig_size=4):
    plt.figure(figsize=(fig_size,fig_size))
    nx.draw(G, G.pos,
        node_color= node_color,
        with_labels=True,
        node_size=1000,font_size=14)
    plt.show()
```

```python
# Define the objective function
def maxcut_obj(x,G):
    cut = 0
    for i, j in G.edges():
        if x[i] != x[j]:
            # the edge is cut, negative value in agreement with the optimizer (which is a minimizer)
            cut -= 1
    return cut

# Brute force method
def brute_force(G):
    n = len(G.nodes)
    costs = np.zeros(0)
    costs=[]
    for i in range(2**n):
        calc_costs = -1*maxcut_obj(bin(i)[2:].zfill(n),G)
        costs.append(calc_costs)
    max_costs_bf = max(costs)
    index_max = costs.index(max(costs))
    max_sol_bf = bin(index_max)[2:].zfill(n)
    return max_costs_bf, max_sol_bf,costs

```

```python
# Generating the distribution resulting from random guessing the solution
def random_guessing_dist(G):
    dictio= dict()
    n = len(G.nodes())
    for i in range(2**n):
        key = bin(i)[2:].zfill(n)
        dictio[key] = maxcut_obj(bin(i)[2:].zfill(n),G)
    RG_energies_dist = defaultdict(int)
    for x in dictio:
        RG_energies_dist[maxcut_obj(x,G)] += 1
    return RG_energies_dist

# Visualize multiple distributions
def plot_E_distributions(E_dists,p,labels):
    plt.figure()
    x_min = 1000
    x_max = - 1000
    width = 0.25/len(E_dists)
    for index,E_dist in enumerate(E_dists):
        pos = width*index-width*len(E_dists)/4
        label = labels[index]
        X_list,Y_list = zip(*E_dist.items())
        X = -np.asarray(X_list)
        Y = np.asarray(Y_list)
        plt.bar(X + pos, Y/np.sum(Y), color = 'C'+str(index), width = width,label= label+', $p=$'+str(p))
        if np.min(X)<x_min:
            x_min = np.min(X)
        if np.max(X)>x_max:
            x_max = np.max(X)
    plt.xticks(np.arange(x_min,x_max+1))
    plt.legend()
    plt.xlabel('Objective function value')
    plt.ylabel('Probability')
    plt.show()

# Determinet the expected objective function value from the random guessing distribution
def energy_random_guessing(RG_energies_dist):
    energy_random_guessing = 0
    total_count = 0
    for energy in RG_energies_dist.keys():
        count = RG_energies_dist[energy]
        energy_random_guessing += energy*count
        total_count += count
    energy_random_guessing = energy_random_guessing/total_count
    return energy_random_guessing
```

### Test instances

```python
w2  = np.matrix([
 [0, 1],
 [1, 0]])
G2 = nx.from_numpy_matrix(w2)
positions = nx.circular_layout(G2)
G2.pos=positions
print('G2:')
draw_cc_graph(G2)

w3  = np.matrix([
 [0, 1, 1],
 [1, 0, 1],
 [1, 1, 0]])
G3 = nx.from_numpy_matrix(w3)
positions = nx.circular_layout(G3)
G3.pos=positions
print('G3:')
draw_cc_graph(G3)
```

## 3. Circuit generators

We provide you with an example written in qiskit. You have to write the one for cqasm yourself.

### Qiskit generators

```python
class Qiskit(object):
    # Cost operator:
    def get_cost_operator_circuit(G, gamma):
        N = G.number_of_nodes()
        qc = QuantumCircuit(N,N)
        for i, j in G.edges():
            qc.cx(i,j)
            qc.rz(2*gamma, j)
            qc.cx(i,j)
        return qc

    # Mixing operator
    def get_mixer_operator_circuit(G, beta):
        N = G.number_of_nodes()
        qc = QuantumCircuit(N,N)
        for n in G.nodes():
            qc.rx(2*beta, n)
        return qc

    # Build the circuit:
    def get_qaoa_circuit(G, beta, gamma):
        assert(len(beta) == len(gamma))
        p = len(beta) # number of unitary operations
        N = G.number_of_nodes()
        qc = QuantumCircuit(N,N)
        # first step: apply Hadamards to obtain uniform superposition
        qc.h(range(N))
        # second step: apply p alternating operators
        for i in range(p):
            qc.compose(Qiskit.get_cost_operator_circuit(G,gamma[i]),inplace=True)
            qc.compose(Qiskit.get_mixer_operator_circuit(G,beta[i]),inplace=True)
        # final step: measure the result
        qc.barrier(range(N))
        qc.measure(range(N), range(N))
        return qc

```

```python
# Show the circuit for the G3 (triangle) graph
p = 1
beta = np.random.rand(p)*2*np.pi
gamma = np.random.rand(p)*2*np.pi
qc = Qiskit.get_qaoa_circuit(G3,beta, gamma)
qc.draw(output='mpl')

```

### cqasm generators

Now it is up to you to apply what we have learned about cqasm to write the script for the cost and mixing operators:

```python
class Cqasm(object):

    ### We give them this part
    def get_qasm_header(N_qubits):
        """
        Create cQASM header for `N_qubits` qubits and prepare all in |0>-state.
        """
        header = f"""
version 1.0
qubits {N_qubits}
prep_z q[0:{N_qubits-1}]
"""
        return header

    def get_cost_operator(graph, gamma, p=1):
        ...

    def get_mixing_operator(graph, beta, p=1):
        ...

    def get_qaoa_circuit(graph, beta, gamma):
        """
        Create full QAOA circuit for given `graph` and angles `beta` and `gamma`.
        """
        assert len(beta) == len(gamma)
        p = len(beta) # number of layers
        N_qubits = graph.number_of_nodes()
        circuit_str = Cqasm.get_qasm_header(5) #N_qubits)

        # first step: apply Hadamards to obtain uniform superposition
        circuit_str += "{" + ' | '.join([f"H q[{i}]" for i in graph.nodes()]) + "}\n\n"
        # second step: apply p alternating operators
        circuit_str += '\n'.join([Cqasm.get_cost_operator(graph, gamma[i], i+1)
                                  + Cqasm.get_mixing_operator(graph, beta[i], i+1) for i in range(p)])
        # final step: measure the result
        circuit_str += "\n"
        circuit_str += "measure_all"

        return circuit_str
```

## 4. Hybrid-quantum classical optimization

Since QAOA is usually adopted as a hybrid quantum-classical algorithm, we need to construct an outer loop which optimizes the estimated $\bra{\gamma,\beta}H\ket{\gamma,\beta}$.

```python
# Black-box function that describes the energy output of the QAOA quantum circuit
def get_black_box_objective(G, p, SDK = 'qiskit', backend = None, shots=2**10):
    if SDK == 'cqasm':
        if not backend:
            backend = 'QX single-node simulator'
            backend_type = qi.get_backend_type_by_name(backend)
            def f(theta):
                # first half is betas, second half is gammas
                beta = theta[:p]
                gamma = theta[p:]
                qc = Cqasm.get_qaoa_circuit(G, beta, gamma)
                result = qi.execute_qasm(qc, backend_type=backend_type, number_of_shots=shots)
                counts = result['histogram']
                # return the energy
                return compute_maxcut_energy(counts, G)

    if SDK == 'qiskit':
        if not backend:
            backend = 'qasm_simulator'
        backend = Aer.get_backend(backend)
        def f(theta):
            # first half is betas, second half is gammas
            beta = theta[:p]
            gamma = theta[p:]
            qc = Qiskit.get_qaoa_circuit(G,beta, gamma)
            counts = execute(qc, backend,shots=shots).result().get_counts()
            # return the energy
            return compute_maxcut_energy(counts, G)
    else:
        return 'error: SDK not found'
    return f

# Estimate the expectation value based on the circuit output
def compute_maxcut_energy(counts, G):
    energy = 0
    total_counts = 0
    for meas, meas_count in counts.items():
        obj_for_meas = maxcut_obj(meas, G)
        energy += obj_for_meas * meas_count
        total_counts += meas_count
    return energy / total_counts
```

## 5. A simple instance on the quantum inspire platform: 2-qubit case

Let us first consider the most simple MAXCUT instance. We have just two nodes, and an optimal cut with objective value 1 would be to place both nodes in its own set.

```python
G=G2
max_costs_bf, max_sol_bf,costs = brute_force(G)
print("brute force method best cut: ",max_costs_bf)
print("best string brute force method:",max_sol_bf)

colors = ['red' if x == '0' else 'b' for x in max_sol_bf]
draw_cc_graph(G,node_color = colors)
```

Using qiskit, the circuit would look the following:

```python
# Test and show circuit for some beta,gamma
p = 1
beta = np.random.rand(p)*np.pi
gamma = np.random.rand(p)*2*np.pi
qc = Qiskit.get_qaoa_circuit(G,beta, gamma)
qc.draw(output='mpl')
```

Now let's run our hybrid-quantum algorithm simulation using qiskit:

```python
# Parameters that can be changed:
p = 1
lb = np.zeros(2*p)
ub = np.hstack([np.full(p, np.pi), np.full(p, 2*np.pi)])
init_point = np.random.uniform(lb, ub, 2*p)
shots = 2**10
optimiser = 'COBYLA'
max_iter = 100

# Training of the parameters beta and gamma
obj = get_black_box_objective(G,p,SDK='qiskit',shots=shots)
# Lower and upper bounds: beta \in {0, pi}, gamma \in {0, 2*pi}
bounds = [lb,ub]

# Maximum number of iterations: 100
res = minimize(obj, init_point, method=optimiser, bounds = bounds, options={'maxiter':max_iter, 'disp': True})
print(res)
```

         fun: -1.0
       maxcv: 0.0
     message: 'Optimization terminated successfully.'
        nfev: 40
      status: 1
     success: True
           x: array([0.39495919, 2.33392237])

```python
#Determine the approximation ratio:
print('Approximation ratio is',-res['fun']/max_costs_bf)
```

    Approximation ratio is 0.9970703125

```python
# Extract the optimal values for beta and gamma and run a new circuit with these parameters
optimal_theta = res['x']
qc = Qiskit.get_qaoa_circuit(G, optimal_theta[:p], optimal_theta[p:])
counts = execute(qc,backend = Aer.get_backend('qasm_simulator'),shots=shots).result().get_counts()
```

```python
plt.bar(counts.keys(), counts.values())
plt.xlabel('String')
plt.ylabel('Count')
plt.show()
```

```python
RG_dist = random_guessing_dist(G)
```

```python
# Measurement distribution
E_dist = defaultdict(int)
for k, v in counts.items():
    E_dist[maxcut_obj(k,G)] += v

plot_E_distributions([E_dist,RG_dist],p,['Qiskit','random guessing'])

E_random_guessing = energy_random_guessing(RG_dist)
print('Energy from random guessing is', E_random_guessing)
```

```python
X_list,Y_list = zip(*E_dist.items())
X = -np.asarray(X_list)
Y = np.asarray(Y_list)
print('Probability of measuring the optimal solution is',Y[np.argmax(X)]/shots)
```

    Probability of measuring the optimal solution is 0.9951171875

Now that we have obtained some good values for $\beta$ and $\gamma$ through classical simulation, let's see what Starmon-5 would give us.

The figure below shows the topology of Starmon-5. Since q0 is not connected to q1, we have to relabel the nodes. Networkx as such an option, by using 'nx.relabel_nodes(G,{1:2}' we can relabel node 1 as node 2. Since q0 is connected to q2, this does allow us to run our cqasm code on Starmon-5. For qiskit, this step is irrelevant as we have all-to-all connectivity in the simulation.

```python
Image(filename='Starmon5.png')
```

```python
qc_Cqasm = Cqasm.get_qaoa_circuit(nx.relabel_nodes(G, {1: 2}), optimal_theta[:p], optimal_theta[p:])
print(qc_Cqasm)
```

    version 1.0
    qubits 5
    prep_z q[0:4]
    {H q[0] | H q[2]}

    .U_gamma_1
    CNOT q[0], q[2]
    Rz q[2], 5.633895595352522
    CNOT q[0], q[2]
    .U_beta_1
    {Rx q[0], 3.807285952793924 | Rx q[2], 3.807285952793924}

    measure_all

Now we run the Cqasm-circuit on the Starmon-5 Hardware.

```python
authentication = get_authentication()
QI.set_authentication(authentication, QI_URL)
```

```python
qiapi = QuantumInspireAPI(QI_URL, authentication)
result = qiapi.execute_qasm(qc_Cqasm, backend_type=qiapi.get_backend_type('Starmon-5'), number_of_shots=2**10)
counts_QI = result['histogram']
```

Inspecting 'counts_QI', we see that it returns the integer corresponding to the bit string result of the measurement

```python
counts_QI
```

    OrderedDict([('0', 0.0791015625),
                 ('1', 0.4033203125),
                 ('2', 0.001953125),
                 ('3', 0.0166015625),
                 ('4', 0.3818359375),
                 ('5', 0.0302734375),
                 ('6', 0.0205078125),
                 ('7', 0.001953125),
                 ('8', 0.0029296875),
                 ('9', 0.005859375),
                 ('11', 0.0009765625),
                 ('12', 0.02734375),
                 ('13', 0.0029296875),
                 ('14', 0.0009765625),
                 ('16', 0.0029296875),
                 ('17', 0.005859375),
                 ('20', 0.0068359375),
                 ('22', 0.0009765625),
                 ('28', 0.0048828125),
                 ('29', 0.001953125)])

Note that we measure more than just the two relevant qubits, since we had the 'measure all' command in the the cqasm code. The distribution over the strings looks the following:

```python
counts_bin = {}
for k,v in counts_QI.items():
    counts_bin[f'{int(k):05b}'] = v
print(counts_bin)
plt.bar(counts_bin.keys(), counts_bin.values())
plt.xlabel('State')
plt.ylabel('Measurement probability')
plt.xticks(rotation='vertical')
plt.show()
```

Let's create another counts dictionary with only the relevant qubits, which are q0 and q2:

```python
counts_bin_red = defaultdict(float)
for string in counts_bin:
    q0 = string[-1]
    q1 = string[-3]
    counts_bin_red[(q0+q1)]+=counts_bin[string]
```

```python
counts_bin_red
```

    defaultdict(float,
                {'00': 0.0869140625,
                 '10': 0.4326171875,
                 '01': 0.443359375,
                 '11': 0.037109375})

We now plot all distributions (qiskit, Starmon-5, and random guessing) in a single plot.

```python
#Determine the approximation ratio:
print('Approximation ratio on the hardware is',-compute_maxcut_energy(counts_bin_red,G)/max_costs_bf)

# Random guessing distribution
RG_dist = random_guessing_dist(G)

# Measurement distribution
E_dist_S5 = defaultdict(int)
for k, v in counts_bin_red.items():
    E_dist_S5[maxcut_obj(k,G)] += v

plot_E_distributions([E_dist,E_dist_S5,RG_dist],p,['Qiskit','Starmon-5','random guessing'])

X_list,Y_list = zip(*E_dist_S5.items())
X = -np.asarray(X_list)
Y = np.asarray(Y_list)
print('Probability of measuring the optimal solution is',Y[np.argmax(X)])

E_random_guessing = energy_random_guessing(RG_dist)
print('Expected approximation ratio random guessing is', -E_random_guessing/max_costs_bf)
```

## 6. Compilation issues: the triangle graph

For the graph with just two nodes we already had some minor compilation issues, but this was easily fixed by relabeling the nodes. We will now consider an example for which relabeling is simply not good enough to get it mapped to the Starmon-5 toplogy.

```python
G=G3
max_costs_bf, max_sol_bf,costs = brute_force(G)
print("brute force method best cut: ",max_costs_bf)
print("best string brute force method:",max_sol_bf)

colors = ['red' if x == '0' else 'b' for x in max_sol_bf]
draw_cc_graph(G,node_color = colors)
```

Due to the topology of Starmon-5 this graph cannot be executed without any SWAPS. Therefore, we ask you to write a new circuit generator that uses SWAPS in order to make the algorithm work with the Starmon-5 topology. Let's also swap back to the original graph configuration, so that we can in the end measure only the qubits that correspond to a node in the graph (this is already written for you)

```python
def QAOA_triangle_circuit_cqasm(graph, beta, gamma):
    circuit_str = Cqasm.get_qasm_header(5)
    circuit_str += "{" + ' | '.join([f"H q[{i}]" for i in graph.nodes()]) + "}\n\n"

    def get_triangle_cost_operator(graph, gamma, p):
        ....

    circuit_str += '\n'.join([get_triangle_cost_operator(graph, gamma[i], i+1)
                              + Cqasm.get_mixing_operator(graph, beta[i], i+1) for i in range(p)])
    circuit_str += "\n"
    circuit_str += "{" + ' | '.join([f"measure q[{i}]" for i in graph.nodes()]) + "}\n"
    return circuit_str
```

We now run the same procedure as before to obtain good parameter values

```python
# Parameters that can be changed:
p = 1
lb = np.zeros(2*p)
ub = np.hstack([np.full(p, np.pi), np.full(p, 2*np.pi)])
init_point = np.random.uniform(lb, ub, 2*p)
shots = 2**10
optimiser = 'COBYLA'
max_iter = 100

# Training of the parameters beta and gamma
obj = get_black_box_objective(G,p,SDK='qiskit',shots=shots)
# Lower and upper bounds: beta \in {0, pi}, gamma \in {0, 2*pi}
bounds = [lb,ub]

# Maximum number of iterations: 100
res = minimize(obj, init_point, method=optimiser, bounds = bounds,options={'maxiter':max_iter, 'disp': True})
print(res)
```

    C:\Users\jordi\Anaconda3\envs\EQTC_workshop\lib\site-packages\scipy\optimize\_minimize.py:544: RuntimeWarning: Method COBYLA cannot handle bounds.
      warn('Method %s cannot handle bounds.' % method,

         fun: -1.931640625
       maxcv: 0.0
     message: 'Optimization terminated successfully.'
        nfev: 26
      status: 1
     success: True
           x: array([2.89884114, 1.99787208])

```python
#Determine the approximation ratio:
print('Approximation ratio is',-res['fun']/max_costs_bf)

# Extract the optimal values for beta and gamma and run a new circuit with these parameters
optimal_theta = res['x']
qc = Qiskit.get_qaoa_circuit(G, optimal_theta[:p], optimal_theta[p:])
counts = execute(qc,backend = Aer.get_backend('qasm_simulator'),shots=shots).result().get_counts()

# Random guessing distribution
RG_dist = random_guessing_dist(G)

# Measurement distribution
E_dist = defaultdict(int)
for k, v in counts.items():
    E_dist[maxcut_obj(k,G)] += v

X_list,Y_list = zip(*E_dist.items())
X = -np.asarray(X_list)
Y = np.asarray(Y_list)
print('Probability of measuring the optimal solution is',Y[np.argmax(X)]/shots)

E_random_guessing = energy_random_guessing(RG_dist)
print('Expected approximation ratio random guessing is', -E_random_guessing/max_costs_bf)
```

    Approximation ratio is 0.9658203125
    Probability of measuring the optimal solution is 0.9541015625
    Expected approximation ratio random guessing is 0.75

```python
plt.bar(counts.keys(), counts.values())
plt.xlabel('String')
plt.ylabel('Count')
plt.show()
```

Let's run it on Starmon-5 again!

```python
# Extract the optimal values for beta and gamma and run a new circuit with these parameters
optimal_theta = res['x']
qasm_circuit = QAOA_triangle_circuit_cqasm(G, optimal_theta[:p], optimal_theta[p:])
qiapi = QuantumInspireAPI(QI_URL, authentication)
result = qiapi.execute_qasm(qasm_circuit, backend_type=qiapi.get_backend_type('Starmon-5'), number_of_shots=shots)
counts = result['histogram']

print(qasm_circuit)
print(result)
```

    version 1.0
    qubits 5
    prep_z q[0:4]
    {H q[0] | H q[1] | H q[2]}

    .U_gamma_1
    SWAP q[0], q[2]
    CNOT q[2], q[1]
    Rz q[1], 3.9957441591320597
    CNOT q[2], q[1]
    SWAP q[0], q[2]
    CNOT q[0], q[2]
    Rz q[2], 3.9957441591320597
    CNOT q[0], q[2]
    CNOT q[1], q[2]
    Rz q[2], 3.9957441591320597
    CNOT q[1], q[2]
    .U_beta_1
    {Rx q[0], 5.797682279817749 | Rx q[1], 5.797682279817749 | Rx q[2], 5.797682279817749}

    {measure q[0] | measure q[1] | measure q[2]}

    {'id': 7069977, 'url': 'https://api.quantum-inspire.com/results/7069977/', 'job': 'https://api.quantum-inspire.com/jobs/7077998/', 'created_at': '2021-11-26T10:56:40.429243Z', 'number_of_qubits': 5, 'execution_time_in_seconds': 0.155648, 'raw_text': '', 'raw_data_url': 'https://api.quantum-inspire.com/results/7069977/raw-data/db877bd00c6e31d76aebcaadca7a24c8719d860cc1118387541ac4887982b476/', 'histogram': OrderedDict([('0', 0.09765625), ('1', 0.1376953125), ('2', 0.1552734375), ('3', 0.0712890625), ('4', 0.1474609375), ('5', 0.1943359375), ('6', 0.169921875), ('7', 0.0263671875)]), 'histogram_url': 'https://api.quantum-inspire.com/results/7069977/histogram/db877bd00c6e31d76aebcaadca7a24c8719d860cc1118387541ac4887982b476/', 'measurement_mask': 7, 'quantum_states_url': 'https://api.quantum-inspire.com/results/7069977/quantum-states/db877bd00c6e31d76aebcaadca7a24c8719d860cc1118387541ac4887982b476/', 'measurement_register_url': 'https://api.quantum-inspire.com/results/7069977/measurement-register/db877bd00c6e31d76aebcaadca7a24c8719d860cc1118387541ac4887982b476/', 'calibration': 'https://api.quantum-inspire.com/calibration/109027/'}

```python
counts
```

    OrderedDict([('0', 0.09765625),
                 ('1', 0.1376953125),
                 ('2', 0.1552734375),
                 ('3', 0.0712890625),
                 ('4', 0.1474609375),
                 ('5', 0.1943359375),
                 ('6', 0.169921875),
                 ('7', 0.0263671875)])

```python
counts_bin = {}
for k,v in counts.items():
    counts_bin[f'{int(k):03b}'] = v
print(counts_bin)
plt.bar(counts_bin.keys(), counts_bin.values())
plt.xlabel('String')
plt.ylabel('Probability')
plt.show()
```

```python
#Determine the approximation ratio:
print('Approximation ratio on the hardware is',-compute_maxcut_energy(counts_bin,G)/max_costs_bf)

# Random guessing distribution
RG_dist = random_guessing_dist(G)

# Measurement distribution
E_dist_S5 = defaultdict(int)
for k, v in counts_bin.items():
    E_dist_S5[maxcut_obj(k,G)] += v

plot_E_distributions([E_dist,E_dist_S5,RG_dist],p,['Qiskit','Starmon-5','random guessing'])

X_list,Y_list = zip(*E_dist_S5.items())
X = -np.asarray(X_list)
Y = np.asarray(Y_list)
print('Probability of measuring the optimal solution is',Y[np.argmax(X)])

E_random_guessing = energy_random_guessing(RG_dist)
print('Expected approximation ratio random guessing is', -E_random_guessing/max_costs_bf)
```

## 7. More advanced questions

Some questions you could look at:

- What is the performance on other graph instances?
- How scalable is this hardware for larger problem sizes?
- How much can the circuit be optimized for certain graph instances?
- Are the errors perfectly random or is there some correlation?
- Are there tricks to find good parameters?

```python

```

```python

```


Table of Contents

1  LSTM (Long Short Term Memory)

1.1  LSTM Step by Step Walk Through

1.2  Implementation

1.3  Conclusion

2  Reference

```python
# code for loading the format for the notebook
import os

# path : store the current path to convert back to it later
path = os.getcwd()
os.chdir(os.path.join('..', '..', 'notebook_format'))
from formats import load_style
load_style(css_style = 'custom2.css', plot_style = False)
```

```python
os.chdir(path)

import os
import warnings
import numpy as np
import tensorflow as tf
from time import time
from keras.datasets import mnist

# 1. magic so that the notebook will reload external python modules
# 2. magic to print version
%load_ext autoreload
%autoreload 2
%load_ext watermark
%watermark -a 'Ethen' -d -t -v -p keras,numpy,tensorflow
```

    Using TensorFlow backend.

    Ethen 2018-04-27 20:49:11

    CPython 3.6.4
    IPython 6.3.1

    keras 2.1.5
    numpy 1.14.2
    tensorflow 1.7.0

# LSTM (Long Short Term Memory)

Now that we've understand the motivation behind Recurrent Neural Network (RNN) and seen its [implementation](http://nbviewer.jupyter.org/github/ethen8181/machine-learning/blob/master/deep_learning/rnn/1_tensorflow_rnn.ipynb). Let's turn our head towards its more powerful variants.

Recall that RNNs are networks with loops in them, allowing them to store information about the previous state and potentially leverage it to better reason about the current state. One popular diagram that we might come across for RNNs is the following:

In the diagram above, a chunk of neural network (our RNN layer) takes some input $x_t$ and outputs a value $h_t$. This loop denotes the network will be repeating the process for every sequence in out input. In other words, when given a sentence of 4 words, the network (the RNN cell) will unrolled itself into 4 copies, one copy for each word.

The main issue with these vanilla RNN is that they tend to suffer from the vanishing gradient problem. Training a RNN is similar to training a traditional Neural Network, we also use the backpropagation algorithm, but with a little twist. Because the parameters are shared by all time steps in the network, the gradient at each output depends not only on the calculations of the current time step, but also the previous time steps. For example, in order to calculate the gradient at t=4 we would need to backpropagate 3 steps and sum up the gradients. This is called Backpropagation Through Time (BPTT). Thus we can imagine when computing the gradient, if we multiply a small number with another small number with another and with another, the value dramatically decays to 0, and the weights will no longer be updated when the gradients are 0. To mitigate this issue, other variants of RNNs were developed, and this notebook will look at one of them called **LSTM (Long Short Term Memory)**.

## LSTM Step by Step Walk Through

Note that a large portion of the content for this section is based on [Blog: Understanding LSTM Networks](http://colah.github.io/posts/2015-08-Understanding-LSTMs/)

Given $x_t$, the input at time step $t$ and $h_t$, the hidden state at time step $t$ the computation happening in a vanilla RNN cell are as follow:

\begin{align}
h_t = f(W h_{t - 1} + U x_t)
\end{align}

Here, $f$ is usually a nonlinearity function such as tanh. LSTMs also have this chain like structure, but the repeating module has a different structure. Instead of having a single set of weights $U$ and $W$ connecting the input and hidden state respectively, there are four sets of weights, interacting in a very special way.

LSTM are designed to avoid long-term dependency problems, and the core idea is the cell state, the horizontal line running through the top of the diagram.

Cell state is kind of like a conveyor belt. It runs straight down the entire chain, with only some linear interactions, making it easier for information to flow along it unchanged. LSTMs have the ability to remove or add information to the cell state, carefully regulated by structures called gates. Namely, the **forget gate, input gate and output gate**.

The first step for a LSTM cell is to decide what information we're going to throw away from the cell state. This is determined by the a sigmoid layer "forget gate", the forget gate looks at $h_{t−1}$ and $x_t$, and outputs a number between 0 and 1 for each number in the cell state $C_{t−1}$. A 1 represents completely keep this while a 0 represents completely get rid of this.

\begin{align}
f_t = \sigma(W_f \cdot [ h_{t - 1}, x_t ] + b_f)
\end{align}

Note that $W_f \cdot [ h_{t - 1}, x_t ]$ is a simplified notation for $W h_{t - 1} + U x_t$, $W_f$ denotes that these are the set of weights for the forget gate.

For example, if we are building a language model that's trying to predict the next word based on all the previous ones. In such a problem, the cell state might include the gender of the present subject, to determine the correct pronouns to use. When we see a new subject, we want to forget the gender of the old subject.

The second step is to determine what new information to store in the cell state. This step consists of two parts, first a sigmoid layer known as the "input gate" decides which value we'll update. Second, a tanh layer creates a vector of new candidate value $\tilde{C_t}$, that could be added to the state.

\begin{align}
i_t &= \sigma(W_i \cdot [ h_{t - 1}, x_t ] + b_i) \\
\tilde{C_t} &= tanh(W_c \cdot [ h_{t - 1}, x_t ] + b_c)
\end{align}

In the example of our language model, we want to add the gender of the new subject to the cell state to replace the old one we're forgetting.

It's now time to update the old cell state, $C_{t−1}$, into the new cell state $C_t$. The previous steps already decided what to do, we just need to actually do it. We multiply the old state by $f_t$, forgetting the things we've decided to forget earlier. Then we add $i_t * \tilde{C_t}$, which is the new cell state scaled by how much we've decided to update each value.

\begin{align}
C_t &= f_t * C_{t-1} + i_t * \tilde{C_t}
\end{align}

Looking at this formula more carefully, we can see that the information carried by the previous cell state, $C_{t-1}$ will not be lost if its weight, i.e. the forget gate $f_t$ is on (close to 1), making LSTM better at learning long-term dependencies compared to vanilla RNN.

In the case of the language model, this is where we'd actually drop the information about the old subject's gender and add the new information, as we decided in the previous steps.

Finally, we need to decide what we're going to output. This output will be a filtered version of our cell state. First, we run it through a sigmoid layer which decides what parts of the cell state we're going to output. This is essentially our output gate. Then, we put the cell state through tanh (to push the values to be between −1 and 1) and multiply it by the output of the sigmoid gate, so that we only output the parts we decided to.

\begin{align}
o_t &= \sigma(W_o \cdot [ h_{t - 1}, x_t ] + b_o) \\
h_t &= o_t * tanh(C_t)
\end{align}

For the language model example, since it just saw a subject, it might want to output information relevant to a verb, in case that's what is coming next. Or it might output whether the subject is singular or plural, so that we know what form a verb the next word should take form.

## Implementation

A lot of the scripts is similar to that of the implementation for vanilla [RNN](http://nbviewer.jupyter.org/github/ethen8181/machine-learning/blob/master/deep_learning/rnn/1_tensorflow_rnn.ipynb).

```python
(X_train, Y_train), (X_test, Y_test) = mnist.load_data()
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')

# images takes values between 0 - 255, we can normalize it
# by dividing every number by 255
X_train /= 255
X_test /= 255

print('mnist data shape: ', X_train.shape)
```

    mnist data shape:  (60000, 28, 28)

```python
from dataloader import DataLoader

# Define some parameters
element_size = 28
time_steps = 28
num_classes = 10
batch_size = 128
hidden_layer_size = 128

# example of generating a batch of data using the
# DataLoader class
data_loader = DataLoader(X_train, Y_train, num_classes)
X_batch, y_batch = data_loader.next_batch(batch_size)
print('label shape: ', y_batch.shape)
print('data shape: ', X_batch.shape)
```

    label shape:  (128, 10)
    data shape:  (128, 28, 28)

The formulas for LSTM is listed again for quick reference, note that for the implementation, we've excluded the bias term to keep things simpler.

\begin{align}
f_t &= \sigma(W_f \cdot [ h_{t - 1}, x_t ] + b_f) \nonumber \\
i_t &= \sigma(W_i \cdot [ h_{t - 1}, x_t ] + b_i) \nonumber \\
\tilde{C_t} &= tanh(W_c \cdot [ h_{t - 1}, x_t ] + b_c) \nonumber \\
C_t &= f_t * C_{t-1} + i_t * \tilde{C_t} \nonumber \\
o_t &= \sigma(W_o \cdot [ h_{t - 1}, x_t ] + b_o) \nonumber \\
h_t &= o_t * tanh(C_t)
\end{align}

```python
# the first dimension holds the batch size
inputs = tf.placeholder(tf.float32, shape = [None, time_steps, element_size], name = 'inputs')
labels = tf.placeholder(tf.float32, shape = [None, num_classes], name = 'labels')

# U : input's weight
# W : hidden state's weight
# the first dimension is 4 since we have 4 sets of these weights,
# 1 for forget gate, 1 for input gate, 1 for candidate cell state
# and 1 for output gate. We'll create them in 1 place and slice
# it to access each one
U = tf.Variable(tf.zeros([4, element_size, hidden_layer_size]))
W = tf.Variable(tf.zeros([4, hidden_layer_size, hidden_layer_size]))

def lstm_step(previous_hidden_state, x):
    # lstm contains 2 sets of hidden state weights, 1 for the cell state
    # and the other for the output state (originally the hidden state for
    # vanilla RNN)
    output_state, cell_state = tf.unstack(previous_hidden_state)

    input_gate = tf.sigmoid(tf.matmul(x, U[0]) + tf.matmul(output_state, W[0]))
    forget_gate = tf.sigmoid(tf.matmul(x, U[1]) + tf.matmul(output_state, W[1]))
    output_gate = tf.sigmoid(tf.matmul(x, U[2]) + tf.matmul(output_state, W[2]))
    candidate_cell_state = tf.tanh(tf.matmul(x, U[3]) + tf.matmul(output_state, W[3]))

    new_cell_state = forget_gate * cell_state + input_gate * candidate_cell_state
    new_output_state = output_gate * tf.tanh(new_cell_state)
    current_hidden_state = tf.stack([new_output_state, new_cell_state])
    return current_hidden_state
```

```python
# the original input batch's shape is of [batch_size, time_steps and element_size]
# we permutate the order to [time_steps, batch_size, element_size]. The time_steps
# is put up front in order to leverage tf.scan's functionality
input_reshaped = tf.transpose(inputs, perm = [1, 0, 2])

# we initialize a hidden state to begin with and apply the rnn steps using tf.scan,
# which repeatedly applies a callable to our inputs
initial_hidden = tf.zeros([2, batch_size, hidden_layer_size])
all_hidden_states = tf.scan(
    lstm_step, input_reshaped, initializer = initial_hidden, name = 'hidden_states')

# if we do a fake run, we can see that the output at this point is the hidden state
# for every time step [time_steps, 2, batch_size, hidden_layer_size]
# 2 is for the 2 sets of hidden state LSTM has
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())

    data_loader = DataLoader(X_train, Y_train, num_classes)
    X_batch, y_batch = data_loader.next_batch(batch_size)
    temp = sess.run(all_hidden_states, feed_dict = {inputs: X_batch, labels: y_batch})
    print(temp.shape)
```

    (28, 2, 128, 128)

```python
# output linear layer's weight and bias, V from the diagram
Wl = tf.Variable(tf.truncated_normal(
    [hidden_layer_size, num_classes],
    mean = 0, stddev = .01))
bl = tf.Variable(tf.truncated_normal(
    [num_classes], mean = 0,stddev = .01))

# apply linear layer to state vector;
# instead of calculating the output vector for every hidden state,
# in basic classification, we can assume the last hidden state
# has accumulated the information representing the entire sequence
states = tf.reshape(all_hidden_states[-1, 0], [-1, hidden_layer_size])
output = tf.matmul(states, Wl) + bl
```

```python
learning_rate = 0.001

# specify the cross entropy loss, the optimizer to train the loss,
# the accuracy measurement
cross_entropy = tf.reduce_mean(
    tf.nn.softmax_cross_entropy_with_logits_v2(
    logits = output, labels = labels))
train_step = tf.train.RMSPropOptimizer(learning_rate).minimize(cross_entropy)
correct_prediction = tf.equal(tf.argmax(labels, axis = 1), tf.argmax(output, axis = 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) * 100
```

```python
X_test_batch = X_test[:batch_size]
y_test_batch = to_categorical(Y_test[:batch_size], num_classes)

data_loader = DataLoader(X_train, Y_train, num_classes)

epochs = 5000
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())

    start = time()
    for i in range(epochs):
        X_batch, y_batch = data_loader.next_batch(batch_size)
        sess.run(train_step, feed_dict = {inputs: X_batch, labels: y_batch})

        if i % 1000 == 0:
            acc, loss = sess.run([accuracy, cross_entropy],
                                 feed_dict = {inputs: X_batch, labels: y_batch})
            print("Iter " + str(i) + ", Minibatch Loss =",
                  "{:.5f}".format(loss) + ", Training Accuracy =",
                  "{:.4f}".format(acc))

    print('Optimization finished!')
    acc_test = sess.run(accuracy, feed_dict = {inputs: X_test_batch, labels: y_test_batch})
    print('Test Accuracy: ', acc_test)
    print('elapse time: ', time() - start)
```

    Iter 0, Minibatch Loss = 2.30216, Training Accuracy = 14.0625
    Iter 1000, Minibatch Loss = 0.82200, Training Accuracy = 70.3125
    Iter 2000, Minibatch Loss = 0.24636, Training Accuracy = 93.7500
    Iter 3000, Minibatch Loss = 0.08379, Training Accuracy = 98.4375
    Iter 4000, Minibatch Loss = 0.02557, Training Accuracy = 99.2188
    Optimization finished!
    Test Accuracy:  98.4375
    elapse time:  197.55520510673523

## Conclusion

Given the more complex structure, it makes sense that it takes longer for LSTMs to train compared to vanilla RNN. But, thankfully, it does give better performance on the test set.

Most of exciting result today achieved by RNN-like networks is in fact achieved by LSTMs, because of its capability to deal with long term dependency. The long term dependency problem is that, when we have larger network through time, the gradient decays quickly during back propagation. So training a RNN having long unfolding in time becomes impossible. But LSTM avoids this decay of gradient problem by allowing us to make a super highway (cell states) through time, these highways allow the gradient to freely flow backward in time making them less susceptible to vanishing gradients.

# Reference

- [Blog: Understanding LSTM Networks](http://colah.github.io/posts/2015-08-Understanding-LSTMs/)
- [Blog: Unfolding RNNs II - Vanilla, GRU, LSTM RNNs from scratch in Tensorflow](http://suriyadeepan.github.io/2017-02-13-unfolding-rnn-2/)
- [Quora: How does LSTM help prevent the vanishing (and exploding) gradient problem in a recurrent neural network?](https://www.quora.com/How-does-LSTM-help-prevent-the-vanishing-and-exploding-gradient-problem-in-a-recurrent-neural-network)