```
!nvidia-smi
```

    Tue Jun  8 01:01:30 2021
    +-----------------------------------------------------------------------------+
    | NVIDIA-SMI 465.27       Driver Version: 460.32.03    CUDA Version: 11.2     |
    |-------------------------------+----------------------+----------------------+
    | GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
    | Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
    |                               |                      |               MIG M. |
    |===============================+======================+======================|
    |   0  Tesla T4            Off  | 00000000:00:04.0 Off |                    0 |
    | N/A   42C    P8    10W /  70W |      0MiB / 15109MiB |      0%      Default |
    |                               |                      |                  N/A |
    +-------------------------------+----------------------+----------------------+

    +-----------------------------------------------------------------------------+
    | Processes:                                                                  |
    |  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
    |        ID   ID                                                   Usage      |
    |=============================================================================|
    |  No running processes found                                                 |
    +-----------------------------------------------------------------------------+

```
#!pip install pymatgen==2020.12.31
!pip install pymatgen==2019.11.11
!pip install --pre graphdot
!pip install gdown
```

    Requirement already satisfied: pymatgen==2019.11.11 in /usr/local/lib/python3.7/dist-packages (2019.11.11)
    Requirement already satisfied: palettable>=3.1.1 in /usr/local/lib/python3.7/dist-packages (from pymatgen==2019.11.11) (3.3.0)
    Requirement already satisfied: pydispatcher>=2.0.5 in /usr/local/lib/python3.7/dist-packages (from pymatgen==2019.11.11) (2.0.5)
    Requirement already satisfied: ruamel.yaml>=0.15.6 in /usr/local/lib/python3.7/dist-packages (from pymatgen==2019.11.11) (0.17.7)
    Requirement already satisfied: spglib>=1.9.9.44 in /usr/local/lib/python3.7/dist-packages (from pymatgen==2019.11.11) (1.16.1)
    Requirement already satisfied: networkx>=2.2 in /usr/local/lib/python3.7/dist-packages (from pymatgen==2019.11.11) (2.5.1)
    Requirement already satisfied: numpy>=1.14.3 in /usr/local/lib/python3.7/dist-packages (from pymatgen==2019.11.11) (1.19.5)
    Requirement already satisfied: tabulate in /usr/local/lib/python3.7/dist-packages (from pymatgen==2019.11.11) (0.8.9)
    Requirement already satisfied: requests in /usr/local/lib/python3.7/dist-packages (from pymatgen==2019.11.11) (2.23.0)
    Requirement already satisfied: pandas in /usr/local/lib/python3.7/dist-packages (from pymatgen==2019.11.11) (1.1.5)
    Requirement already satisfied: scipy>=1.0.1 in /usr/local/lib/python3.7/dist-packages (from pymatgen==2019.11.11) (1.4.1)
    Requirement already satisfied: sympy in /usr/local/lib/python3.7/dist-packages (from pymatgen==2019.11.11) (1.7.1)
    Requirement already satisfied: matplotlib>=1.5 in /usr/local/lib/python3.7/dist-packages (from pymatgen==2019.11.11) (3.2.2)
    Requirement already satisfied: monty>=3.0.2 in /usr/local/lib/python3.7/dist-packages (from pymatgen==2019.11.11) (2021.5.9)
    Requirement already satisfied: ruamel.yaml.clib>=0.1.2; platform_python_implementation == "CPython" and python_version < "3.10" in /usr/local/lib/python3.7/dist-packages (from ruamel.yaml>=0.15.6->pymatgen==2019.11.11) (0.2.2)
    Requirement already satisfied: decorator<5,>=4.3 in /usr/local/lib/python3.7/dist-packages (from networkx>=2.2->pymatgen==2019.11.11) (4.4.2)
    Requirement already satisfied: chardet<4,>=3.0.2 in /usr/local/lib/python3.7/dist-packages (from requests->pymatgen==2019.11.11) (3.0.4)
    Requirement already satisfied: idna<3,>=2.5 in /usr/local/lib/python3.7/dist-packages (from requests->pymatgen==2019.11.11) (2.10)
    Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.7/dist-packages (from requests->pymatgen==2019.11.11) (2020.12.5)
    Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /usr/local/lib/python3.7/dist-packages (from requests->pymatgen==2019.11.11) (1.24.3)
    Requirement already satisfied: python-dateutil>=2.7.3 in /usr/local/lib/python3.7/dist-packages (from pandas->pymatgen==2019.11.11) (2.8.1)
    Requirement already satisfied: pytz>=2017.2 in /usr/local/lib/python3.7/dist-packages (from pandas->pymatgen==2019.11.11) (2018.9)
    Requirement already satisfied: mpmath>=0.19 in /usr/local/lib/python3.7/dist-packages (from sympy->pymatgen==2019.11.11) (1.2.1)
    Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib>=1.5->pymatgen==2019.11.11) (2.4.7)
    Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.7/dist-packages (from matplotlib>=1.5->pymatgen==2019.11.11) (0.10.0)
    Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib>=1.5->pymatgen==2019.11.11) (1.3.1)
    Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.7/dist-packages (from python-dateutil>=2.7.3->pandas->pymatgen==2019.11.11) (1.15.0)
    Requirement already satisfied: graphdot in /usr/local/lib/python3.7/dist-packages (0.8a17)
    Requirement already satisfied: numpy>=1.17 in /usr/local/lib/python3.7/dist-packages (from graphdot) (1.19.5)
    Requirement already satisfied: scipy>=1.3.0 in /usr/local/lib/python3.7/dist-packages (from graphdot) (1.4.1)
    Requirement already satisfied: sympy>=1.3 in /usr/local/lib/python3.7/dist-packages (from graphdot) (1.7.1)
    Requirement already satisfied: networkx>=2.4 in /usr/local/lib/python3.7/dist-packages (from graphdot) (2.5.1)
    Requirement already satisfied: pandas>=0.24 in /usr/local/lib/python3.7/dist-packages (from graphdot) (1.1.5)
    Requirement already satisfied: pymatgen==2019.11.11 in /usr/local/lib/python3.7/dist-packages (from graphdot) (2019.11.11)
    Requirement already satisfied: numba>=0.51.0 in /usr/local/lib/python3.7/dist-packages (from graphdot) (0.51.2)
    Requirement already satisfied: kahypar>=1.1.4 in /usr/local/lib/python3.7/dist-packages (from graphdot) (1.1.6)
    Requirement already satisfied: mendeleev>=0.7 in /usr/local/lib/python3.7/dist-packages (from graphdot) (0.7.0)
    Requirement already satisfied: treelib>=1.6.1 in /usr/local/lib/python3.7/dist-packages (from graphdot) (1.6.1)
    Requirement already satisfied: ase>=3.17 in /usr/local/lib/python3.7/dist-packages (from graphdot) (3.21.1)
    Requirement already satisfied: pycuda>=2019 in /usr/local/lib/python3.7/dist-packages (from graphdot) (2021.1)
    Requirement already satisfied: tqdm>=4.55 in /usr/local/lib/python3.7/dist-packages (from graphdot) (4.61.0)
    Requirement already satisfied: mpmath>=0.19 in /usr/local/lib/python3.7/dist-packages (from sympy>=1.3->graphdot) (1.2.1)
    Requirement already satisfied: decorator<5,>=4.3 in /usr/local/lib/python3.7/dist-packages (from networkx>=2.4->graphdot) (4.4.2)
    Requirement already satisfied: python-dateutil>=2.7.3 in /usr/local/lib/python3.7/dist-packages (from pandas>=0.24->graphdot) (2.8.1)
    Requirement already satisfied: pytz>=2017.2 in /usr/local/lib/python3.7/dist-packages (from pandas>=0.24->graphdot) (2018.9)
    Requirement already satisfied: palettable>=3.1.1 in /usr/local/lib/python3.7/dist-packages (from pymatgen==2019.11.11->graphdot) (3.3.0)
    Requirement already satisfied: monty>=3.0.2 in /usr/local/lib/python3.7/dist-packages (from pymatgen==2019.11.11->graphdot) (2021.5.9)
    Requirement already satisfied: ruamel.yaml>=0.15.6 in /usr/local/lib/python3.7/dist-packages (from pymatgen==2019.11.11->graphdot) (0.17.7)
    Requirement already satisfied: pydispatcher>=2.0.5 in /usr/local/lib/python3.7/dist-packages (from pymatgen==2019.11.11->graphdot) (2.0.5)
    Requirement already satisfied: spglib>=1.9.9.44 in /usr/local/lib/python3.7/dist-packages (from pymatgen==2019.11.11->graphdot) (1.16.1)
    Requirement already satisfied: requests in /usr/local/lib/python3.7/dist-packages (from pymatgen==2019.11.11->graphdot) (2.23.0)
    Requirement already satisfied: matplotlib>=1.5 in /usr/local/lib/python3.7/dist-packages (from pymatgen==2019.11.11->graphdot) (3.2.2)
    Requirement already satisfied: tabulate in /usr/local/lib/python3.7/dist-packages (from pymatgen==2019.11.11->graphdot) (0.8.9)
    Requirement already satisfied: setuptools in /usr/local/lib/python3.7/dist-packages (from numba>=0.51.0->graphdot) (57.0.0)
    Requirement already satisfied: llvmlite<0.35,>=0.34.0.dev0 in /usr/local/lib/python3.7/dist-packages (from numba>=0.51.0->graphdot) (0.34.0)
    Requirement already satisfied: six<2.0.0,>=1.15.0 in /usr/local/lib/python3.7/dist-packages (from mendeleev>=0.7->graphdot) (1.15.0)
    Requirement already satisfied: colorama<0.5.0,>=0.4.4 in /usr/local/lib/python3.7/dist-packages (from mendeleev>=0.7->graphdot) (0.4.4)
    Requirement already satisfied: pyfiglet<0.9,>=0.8.post1 in /usr/local/lib/python3.7/dist-packages (from mendeleev>=0.7->graphdot) (0.8.post1)
    Requirement already satisfied: Pygments<3.0.0,>=2.8.0 in /usr/local/lib/python3.7/dist-packages (from mendeleev>=0.7->graphdot) (2.9.0)
    Requirement already satisfied: SQLAlchemy<2.0.0,>=1.3.23 in /usr/local/lib/python3.7/dist-packages (from mendeleev>=0.7->graphdot) (1.4.15)
    Requirement already satisfied: future in /usr/local/lib/python3.7/dist-packages (from treelib>=1.6.1->graphdot) (0.16.0)
    Requirement already satisfied: pytools>=2011.2 in /usr/local/lib/python3.7/dist-packages (from pycuda>=2019->graphdot) (2021.2.7)
    Requirement already satisfied: appdirs>=1.4.0 in /usr/local/lib/python3.7/dist-packages (from pycuda>=2019->graphdot) (1.4.4)
    Requirement already satisfied: mako in /usr/local/lib/python3.7/dist-packages (from pycuda>=2019->graphdot) (1.1.4)
    Requirement already satisfied: ruamel.yaml.clib>=0.1.2; platform_python_implementation == "CPython" and python_version < "3.10" in /usr/local/lib/python3.7/dist-packages (from ruamel.yaml>=0.15.6->pymatgen==2019.11.11->graphdot) (0.2.2)
    Requirement already satisfied: idna<3,>=2.5 in /usr/local/lib/python3.7/dist-packages (from requests->pymatgen==2019.11.11->graphdot) (2.10)
    Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.7/dist-packages (from requests->pymatgen==2019.11.11->graphdot) (2020.12.5)
    Requirement already satisfied: chardet<4,>=3.0.2 in /usr/local/lib/python3.7/dist-packages (from requests->pymatgen==2019.11.11->graphdot) (3.0.4)
    Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /usr/local/lib/python3.7/dist-packages (from requests->pymatgen==2019.11.11->graphdot) (1.24.3)
    Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib>=1.5->pymatgen==2019.11.11->graphdot) (1.3.1)
    Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.7/dist-packages (from matplotlib>=1.5->pymatgen==2019.11.11->graphdot) (0.10.0)
    Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib>=1.5->pymatgen==2019.11.11->graphdot) (2.4.7)
    Requirement already satisfied: greenlet!=0.4.17; python_version >= "3" in /usr/local/lib/python3.7/dist-packages (from SQLAlchemy<2.0.0,>=1.3.23->mendeleev>=0.7->graphdot) (1.1.0)
    Requirement already satisfied: importlib-metadata; python_version < "3.8" in /usr/local/lib/python3.7/dist-packages (from SQLAlchemy<2.0.0,>=1.3.23->mendeleev>=0.7->graphdot) (4.0.1)
    Requirement already satisfied: MarkupSafe>=0.9.2 in /usr/local/lib/python3.7/dist-packages (from mako->pycuda>=2019->graphdot) (2.0.1)
    Requirement already satisfied: zipp>=0.5 in /usr/local/lib/python3.7/dist-packages (from importlib-metadata; python_version < "3.8"->SQLAlchemy<2.0.0,>=1.3.23->mendeleev>=0.7->graphdot) (3.4.1)
    Requirement already satisfied: typing-extensions>=3.6.4; python_version < "3.8" in /usr/local/lib/python3.7/dist-packages (from importlib-metadata; python_version < "3.8"->SQLAlchemy<2.0.0,>=1.3.23->mendeleev>=0.7->graphdot) (3.7.4.3)
    Requirement already satisfied: gdown in /usr/local/lib/python3.7/dist-packages (3.6.4)
    Requirement already satisfied: tqdm in /usr/local/lib/python3.7/dist-packages (from gdown) (4.61.0)
    Requirement already satisfied: requests in /usr/local/lib/python3.7/dist-packages (from gdown) (2.23.0)
    Requirement already satisfied: six in /usr/local/lib/python3.7/dist-packages (from gdown) (1.15.0)
    Requirement already satisfied: chardet<4,>=3.0.2 in /usr/local/lib/python3.7/dist-packages (from requests->gdown) (3.0.4)
    Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /usr/local/lib/python3.7/dist-packages (from requests->gdown) (1.24.3)
    Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.7/dist-packages (from requests->gdown) (2020.12.5)
    Requirement already satisfied: idna<3,>=2.5 in /usr/local/lib/python3.7/dist-packages (from requests->gdown) (2.10)

```
%matplotlib inline
import io
import sys
sys.path.append('/usr/local/lib/python3.6/site-packages/')
import os
import urllib
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

import graphdot
from graphdot import Graph
from graphdot.graph.adjacency import AtomicAdjacency
from graphdot.graph.reorder import rcm
from graphdot.kernel.marginalized import MarginalizedGraphKernel # https://graphdot.readthedocs.io/en/latest/apidoc/graphdot.kernel.marginalized.html
from graphdot.kernel.marginalized.starting_probability import Uniform
from graphdot.model.gaussian_process import (
    GaussianProcessRegressor,
    LowRankApproximateGPR
)
from graphdot.kernel.fix import Normalization
import graphdot.microkernel as uX
import ase.io

# for getting all file names into a list under a directory
from os import listdir
# for getting file names that match certain pattern
import glob
import time
```

```
from google.colab import drive
drive.mount('/content/gdrive', force_remount=True)
```

    Mounted at /content/gdrive

```
#cd gdrive/MyDrive/Google\ Colab/Covid-Data
%cd gdrive/MyDrive/Covid-Data/
```

    /content/gdrive/.shortcut-targets-by-id/1wtzMcocuK8kPsz8K0ktjCZPkv567W6M2/Covid-Data

```
!pwd
```

    /content/gdrive/.shortcut-targets-by-id/1wtzMcocuK8kPsz8K0ktjCZPkv567W6M2/Covid-Data

```
#!ls
```

```
#files  = ['uncharged_NSP15_6W01_A_3_H.Orderable_zinc_db_enaHLL.2col.csv.1.xz']
#files  = [f for f in listdir('/content/gdrive/.shortcut-targets-by-id/1wtzMcocuK8kPsz8K0ktjCZPkv567W6M2/Covid-Data')]
files = glob.glob("uncharged_NSP15_6W01_A_3_H.Orderable_zinc_db_enaHLL.2col.csv.*.xz")
#print(files[0:5])
# concatenate all files into 1 dataset
dataset = pd.DataFrame()
for i in range(len(files[0:5])):
  data = pd.read_pickle(files[i])
  dataset = pd.concat([dataset, data])
#frames = [pd.read_pickle(f) for f in files]
#dataset = pd.concat(frames)
```

```
len(dataset)
```

    500000

```
target = 'energy'
N_train = len(dataset)//2
N_test = len(dataset)//2
```

```
np.random.seed(0)
# select train and test data
train_sel = np.random.choice(len(dataset), N_train, replace=False)
test_sel = np.random.choice(np.setxor1d(np.arange(len(dataset)), train_sel), N_test, replace=False)
train = dataset.iloc[train_sel]
test = dataset.iloc[test_sel]
```

```
#uX.SquareExponential?
```

```
gpr = GaussianProcessRegressor(
    # kernel is the covariance function of the gaussian process (GP)
    kernel=Normalization( # kernel equals to normalization -> normalizes a kernel using the cosine of angle formula, k_normalized(x,y) = k(x,y)/sqrt(k(x,x)*k(y,y))
        # graphdot.kernel.fix.Normalization(kernel), set kernel as marginalized graph kernel, which is used to calculate the similarity between 2 graphs
        # implement the random walk-based graph similarity kernel as Kashima, H., Tsuda, K., & Inokuchi, A. (2003). Marginalized kernels between labeled graphs. ICML
        MarginalizedGraphKernel(
            # node_kernel - A kernelet that computes the similarity between individual nodes
            # uX - graphdot.microkernel - microkernels are positive-semidefinite functions between individual nodes and edges of graphs
            node_kernel=uX.Additive( # addition of kernal matrices: sum of k_a(X_a, Y_a) cross for a in features
                # uX.Constant - a kernel that returns a constant value, always mutlipled with other microkernels as an adjustable weight
                #   c, the first input arg. as 0.5, (0.01, 10) the lower and upper bounds of c that is allowed to vary during hyperpara. optimizartion
                # uX.KroneckerDelta - a kronecker delta returns 1 when two features are equal and return h (the first input arg here, which is 0.5 in this case) otherwise
                #   (0.1, 0.9) the lower and upper bounds that h is allowed to vary during hyperpara. optimization
                aromatic=uX.Constant(0.5, (0.01, 10.0)) * uX.KroneckerDelta(0.5,(0.1, 0.9)), # the 2nd element of graphdot.graph.Graph.nodes
                atomic_number=uX.Constant(0.5, (0.01, 10.0)) * uX.KroneckerDelta(0.8,(0.1, 0.9)), # the 3rd element of graphdot.graph.Graph.nodes
                # uX.SquareExponential - Equ. 26 in the paper
                # input arg. length_sacle is a float32, set as 1 in this case, which correspond to approx. 1 of the kernal value.
                # This is used to determins how quicklys should the kernel decay to zero.
                charge=uX.Constant(0.5, (0.01, 10.0)) * uX.SquareExponential(1.0), # the 4th element of graphdot.graph.Graph.nodes
                chiral=uX.Constant(0.5, (0.01, 10.0)) * uX.KroneckerDelta(0.5,(0.1, 0.9)), # the 5th element of graphdot.graph.Graph.nodes
                hcount=uX.Constant(0.5, (0.01, 10.0)) * uX.SquareExponential(1.0), # the 6th element of graphdot.graph.Graph.nodes
                hybridization=uX.Constant(0.5, (0.01, 10.0)) * uX.KroneckerDelta(0.5,(0.1, 0.9)), # the 7th element of graphdot.graph.Graph.nodes
                # uX.Convolution - a convolutional microkernel which averages evaluations of a base microkernel between pairs pf elememts of two variable-length feature sequences
                # uX.KroneckerDelta as the base kernel
                ring_list=uX.Constant(0.5, (0.01, 100.0)) * uX.Convolution(uX.KroneckerDelta(0.5,(0.1, 0.9))) # the 8th element of graphdot.graph.Graph.nodes
            ).normalized,
            # edge_kernel - A kernelet that computes the similarity between individual edge
            edge_kernel=uX.Additive(
                aromatic=uX.Constant(0.5, (0.01, 10.0)) * uX.KroneckerDelta(0.5,(0.1, 0.9)), # the 3rd element of graphdot.graph.Graph.nodes
                conjugated=uX.Constant(0.5, (0.01, 10.0)) * uX.KroneckerDelta(0.5,(0.1, 0.9)), # the 4th element of graphdot.graph.Graph.nodes
                order=uX.Constant(0.5, (0.01, 10.0)) * uX.KroneckerDelta(0.8,(0.1, 0.9)), # the 5th element of graphdot.graph.Graph.nodes
                ring_stereo=uX.Constant(0.5, (0.01, 10.0)) * uX.KroneckerDelta(0.8,(0.1, 0.9)), # the 6th element of graphdot.graph.Graph.nodes
                stereo=uX.Constant(0.5, (0.01, 10.0)) * uX.KroneckerDelta(0.8,(0.1, 0.9)) # the 7th element of graphdot.graph.Graph.nodes
            ).normalized,
            p=Uniform(1.0, p_bounds='fixed'), # the strating probability of the random walk on each node
            q=0.05 # the probability for the random walk to stop during each step
        )
    ),
    alpha=1e-4, # value added to the diagonal of the kernel matrix during fitting
    optimizer=True, # default optimizer of L-BFGS-B based on scipy.optimize.minimize
    normalize_y=True, # normalize the y values so taht the means and variance is 0 and 1, repsectively. Will be reversed when predicions are returned
    regularization='+', # alpha (1e-4 in this case) is added to the diagonals of the kernal matrix
)
```

    the total time consumption is 0.0034666061401367188.

```
#gpr.fit(train.graphs, train[target], repeat=3, verbose=True)
# using the molecular graph to predict the energy
start_time = time.time()
gpr.fit(train.graphs, train[target], repeat=5, verbose=True)
end_time = time.time()
print("the total time consumption is " + str(end_time - start_time) + ".")
```

```
gpr.kernel.hyperparameters
```

    starting_probability : Uniform
    	p : 1.0
    stopping_probability : 0.00010000000000000009
    node_kernel : Composite
    	aromatic : Multiply
    		lhs : Constant
    			c : 0.02343420535068002
    		rhs : KroneckerDelta
    			h : 0.18860200789175988
    	atomic_number : Multiply
    		lhs : Constant
    			c : 5.400776905055444
    		rhs : KroneckerDelta
    			h : 0.10000000000000002
    	charge : Multiply
    		lhs : Constant
    			c : 0.0145590563621646
    		rhs : SquareExponential
    			length_scale : 1.0
    	chiral : Multiply
    		lhs : Constant
    			c : 0.05149063984443944
    		rhs : KroneckerDelta
    			h : 0.12853164901299938
    	hcount : Multiply
    		lhs : Constant
    			c : 10.000000000000002
    		rhs : SquareExponential
    			length_scale : 0.07795674396128768
    	hybridization : Multiply
    		lhs : Constant
    			c : 0.02783411902444354
    		rhs : KroneckerDelta
    			h : 0.17414808329497075
    	ring_list : Multiply
    		lhs : Constant
    			c : 6.550981640628747
    		rhs : Convolution
    			base : KroneckerDelta
    				h : 0.10000000000000002
    edge_kernel : Composite
    	aromatic : Multiply
    		lhs : Constant
    			c : 2.331300736214766
    		rhs : KroneckerDelta
    			h : 0.10000000000000002
    	conjugated : Multiply
    		lhs : Constant
    			c : 3.166641607522053
    		rhs : KroneckerDelta
    			h : 0.10000000000000002
    	order : Multiply
    		lhs : Constant
    			c : 0.05549109210250382
    		rhs : KroneckerDelta
    			h : 0.25478481015091287
    	ring_stereo : Multiply
    		lhs : Constant
    			c : 0.033323606027544916
    		rhs : KroneckerDelta
    			h : 0.8
    	stereo : Multiply
    		lhs : Constant
    			c : 0.1324351226762118
    		rhs : KroneckerDelta
    			h : 0.14521546104851712

```
mu = gpr.predict(train.graphs)
```

```
plt.scatter(train[target], mu)
plt.show()
```

```
print('Training set')
print('MAE:', np.mean(np.abs(train[target] - mu)))
print('RMSE:', np.std(train[target] - mu))
```

    Training set
    MAE: 0.2074369392067814
    RMSE: 0.3195501910711287

```
mu_test = gpr.predict(test.graphs)
```

```
plt.scatter(test[target], mu_test)
plt.show()
```

```
print('Test set')
print('MAE:', np.mean(np.abs(test[target] - mu_test)))
print('RMSE:', np.std(test[target] - mu_test))
```

    Test set
    MAE: 1.2461703788060545
    RMSE: 1.6040210737240486

Workon the kernel. Find a kernel that trains and predicts well.

```
gpr2 = GaussianProcessRegressor(
    kernel=Normalization(
        MarginalizedGraphKernel(
            node_kernel=uX.Additive(
                aromatic=uX.Constant(0.5, (0.01, 10.0)) * uX.KroneckerDelta(0.5,(0.1, 0.9)),
                atomic_number=uX.Constant(0.5, (0.01, 10.0)) * uX.KroneckerDelta(0.8,(0.1, 0.9)),
                charge=uX.Constant(0.5, (0.01, 10.0)) * uX.SquareExponential(1.0),
                chiral=uX.Constant(0.5, (0.01, 10.0)) * uX.KroneckerDelta(0.5,(0.1, 0.9)),
                hcount=uX.Constant(0.5, (0.01, 10.0)) * uX.SquareExponential(1.0),
                hybridization=uX.Constant(0.5, (0.01, 10.0)) * uX.KroneckerDelta(0.5,(0.1, 0.9)),
                ring_list=uX.Constant(0.5, (0.01, 100.0)) * uX.Convolution(uX.KroneckerDelta(0.5,(0.1, 0.9)))
            ).normalized,
            edge_kernel=uX.Additive(
                aromatic=uX.Constant(0.5, (0.01, 10.0)) * uX.KroneckerDelta(0.5,(0.1, 0.9)),
                conjugated=uX.Constant(0.5, (0.01, 10.0)) * uX.KroneckerDelta(0.5,(0.1, 0.9)),
                order=uX.Constant(0.5, (0.01, 10.0)) * uX.KroneckerDelta(0.8,(0.1, 0.9)),
                ring_stereo=uX.Constant(0.5, (0.01, 10.0)) * uX.KroneckerDelta(0.8,(0.1, 0.9)),
                stereo=uX.Constant(0.5, (0.01, 10.0)) * uX.KroneckerDelta(0.8,(0.1, 0.9))
            ).normalized,
            p=Uniform(1.0, p_bounds='fixed'),
            q=0.05
        )
    ),
    alpha=1e-2, #different from gpr in alpha where gpr's alpha is 1e-4
    optimizer=True,
    normalize_y=True,
    regularization='+',
)
```

```
#gpr2.fit(train.graphs, train[target], repeat=3, verbose=True)
gpr2.fit(train.graphs, train[target], repeat=1, verbose=True)
```

    |        logP|       dlogP|     y^T.K.y|     log|K| |     Cond(K)|  GPU time|  CPU time|
    |------------|------------|------------|------------|------------|----------|----------|
    |   1.667e+05|   1.928e+05|  1.7773e+05|      -11034|  2.2742e+05|   1.3e+02|       1.7|
    |  1.5585e+05|  2.2171e+05|  1.6671e+05|      -10857|  2.2218e+05|   1.3e+02|       1.7|
    |  1.3711e+05|  2.4873e+05|  1.4756e+05|      -10447|  2.0803e+05|   1.2e+02|       1.8|
    |  1.3286e+05|  2.3627e+05|   1.432e+05|      -10338|  2.0336e+05|   1.1e+02|       1.7|
    |  1.2977e+05|  2.2744e+05|  1.4002e+05|      -10249|  1.9714e+05|   1.1e+02|       1.7|
    |  1.3006e+05|  2.1429e+05|  1.4032e+05|      -10258|  2.0119e+05|     1e+02|       1.7|
    |  1.2923e+05|  2.2103e+05|  1.3946e+05|      -10238|  1.9906e+05|   1.1e+02|       1.7|
    |  1.2888e+05|  2.2097e+05|  1.3911e+05|      -10228|  1.9865e+05|   1.1e+02|       1.7|
    |  1.2843e+05|  2.2338e+05|  1.3864e+05|      -10211|  1.9582e+05|   1.1e+02|       1.7|
    |  1.2837e+05|  2.2244e+05|  1.3858e+05|      -10212|   1.969e+05|   1.1e+02|       1.7|
    |  1.2836e+05|  2.2225e+05|  1.3857e+05|      -10212|  1.9696e+05|   1.1e+02|       1.7|
    |  1.2831e+05|  2.2155e+05|  1.3852e+05|      -10211|  1.9715e+05|   1.1e+02|       1.7|
    |  1.2826e+05|  2.2184e+05|  1.3847e+05|      -10209|  1.9704e+05|   1.1e+02|       1.7|
    |  1.2821e+05|  2.2181e+05|  1.3841e+05|      -10207|  1.9671e+05|   1.1e+02|       1.7|
    |  1.2819e+05|  2.2165e+05|   1.384e+05|      -10207|  1.9664e+05|   1.1e+02|       1.8|
    |  1.2818e+05|  2.2125e+05|  1.3838e+05|      -10207|  1.9671e+05|   1.1e+02|       1.8|
    |  1.2817e+05|  2.2114e+05|  1.3838e+05|      -10207|  1.9673e+05|   1.1e+02|       1.7|
    |  1.2815e+05|  2.2077e+05|  1.3836e+05|      -10207|  1.9677e+05|   1.1e+02|       1.7|
    |  1.2812e+05|   2.185e+05|  1.3833e+05|      -10209|  1.9695e+05|   1.1e+02|       1.7|
    |  1.2809e+05|   2.178e+05|   1.383e+05|      -10209|    1.97e+05|   1.1e+02|       1.7|
    |  1.2807e+05|  2.1764e+05|  1.3828e+05|      -10208|  1.9695e+05|   1.1e+02|       1.7|
    |  1.2805e+05|  2.1597e+05|  1.3826e+05|      -10209|  1.9693e+05|   1.1e+02|       1.7|
    |  1.2805e+05|   2.172e+05|  1.3825e+05|      -10208|  1.9694e+05|   1.1e+02|       1.7|
    |  1.2804e+05|  2.1693e+05|  1.3825e+05|      -10208|  1.9694e+05|   1.1e+02|       1.8|
    |  1.2804e+05|  2.1674e+05|  1.3825e+05|      -10208|  1.9694e+05|   1.1e+02|       1.7|
    |  1.2804e+05|  2.1691e+05|  1.3825e+05|      -10208|  1.9694e+05|   1.1e+02|       1.7|
    |  1.2805e+05|  2.1694e+05|  1.3825e+05|      -10208|  1.9694e+05|   1.1e+02|       1.7|
    |  1.2804e+05|  2.1694e+05|  1.3825e+05|      -10208|  1.9694e+05|   1.1e+02|       1.7|
    |  1.2804e+05|  2.1694e+05|  1.3825e+05|      -10208|  1.9694e+05|   1.1e+02|       1.7|
    |  1.2804e+05|  2.1694e+05|  1.3825e+05|      -10208|  1.9694e+05|   1.1e+02|       1.8|
    |  1.2805e+05|  2.1694e+05|  1.3825e+05|      -10208|  1.9694e+05|   1.1e+02|       1.7|
    Optimization result:
          fun: 128045.20193517115
     hess_inv: <25x25 LbfgsInvHessProduct with dtype=float64>
          jac: array([ 21.67035135,   5.42797631,   0.91584794,   6.62684845,
           636.88297304,  10.22203408,   0.        ,   6.13155297,
             0.80318432, -45.79780911,   0.        ,   9.32446636,
             2.06137402,   7.94609186, 767.483899  ,  -8.19180354,
            92.93654292,   7.92503084, 118.62629465,   3.36719643,
            38.71995733,   7.96834618,   0.        , -11.08475724,
             7.2860016 ])
      message: b'CONVERGENCE: REL_REDUCTION_OF_F_<=_FACTR*EPSMCH'
         nfev: 31
          nit: 21
       status: 0
      success: True
            x: array([-9.21034037, -4.51710969, -1.98267626,  1.72521606, -2.30258509,
           -4.60517019,  0.        , -4.60517019, -1.8070945 ,  2.30258509,
           -2.88031384, -3.6019383 , -2.30258509,  1.91177723, -2.30258509,
            0.28746812, -2.30258509,  0.54884256, -2.30258509, -0.5686784 ,
           -2.30258509, -4.35637808, -0.22314355, -2.55717239, -2.21179129])

    <graphdot.model.gaussian_process.gpr.GaussianProcessRegressor at 0x7f6bf00630d0>

```
mu = gpr2.predict(train.graphs)
plt.scatter(train[target], mu)
plt.show()
```

```
print('Training set')
print('MAE:', np.mean(np.abs(train[target] - mu)))
print('RMSE:', np.std(train[target] - mu))
```

    Training set
    MAE: 0.7238389142657052
    RMSE: 0.9634943206325994

```
mu_test = gpr2.predict(test.graphs)
plt.scatter(test[target], mu_test)
plt.show()
```

```
print('Test set')
print('MAE:', np.mean(np.abs(test[target] - mu_test)))
print('RMSE:', np.std(test[target] - mu_test))
```

    Test set
    MAE: 0.9561539409612109
    RMSE: 1.2284268143181998


```python
!pip install pennylane pennylane-ionq qiskit[visualization]
```

    Requirement already satisfied: pennylane in /usr/local/lib/python3.7/dist-packages (0.16.0)
    Requirement already satisfied: pennylane-ionq in /usr/local/lib/python3.7/dist-packages (0.16.0)
    Requirement already satisfied: qiskit[visualization] in /usr/local/lib/python3.7/dist-packages (0.27.0)
    Requirement already satisfied: autoray in /usr/local/lib/python3.7/dist-packages (from pennylane) (0.2.5)
    Requirement already satisfied: toml in /usr/local/lib/python3.7/dist-packages (from pennylane) (0.10.2)
    Requirement already satisfied: numpy in /usr/local/lib/python3.7/dist-packages (from pennylane) (1.19.5)
    Requirement already satisfied: autograd in /usr/local/lib/python3.7/dist-packages (from pennylane) (1.3)
    Requirement already satisfied: networkx in /usr/local/lib/python3.7/dist-packages (from pennylane) (2.5.1)
    Requirement already satisfied: scipy in /usr/local/lib/python3.7/dist-packages (from pennylane) (1.4.1)
    Requirement already satisfied: semantic-version==2.6 in /usr/local/lib/python3.7/dist-packages (from pennylane) (2.6.0)
    Requirement already satisfied: appdirs in /usr/local/lib/python3.7/dist-packages (from pennylane) (1.4.4)
    Requirement already satisfied: python-dateutil in /usr/local/lib/python3.7/dist-packages (from pennylane-ionq) (2.8.1)
    Requirement already satisfied: requests in /usr/local/lib/python3.7/dist-packages (from pennylane-ionq) (2.23.0)
    Requirement already satisfied: qiskit-terra==0.17.4 in /usr/local/lib/python3.7/dist-packages (from qiskit[visualization]) (0.17.4)
    Requirement already satisfied: qiskit-aqua==0.9.2 in /usr/local/lib/python3.7/dist-packages (from qiskit[visualization]) (0.9.2)
    Requirement already satisfied: qiskit-ignis==0.6.0 in /usr/local/lib/python3.7/dist-packages (from qiskit[visualization]) (0.6.0)
    Requirement already satisfied: qiskit-ibmq-provider==0.14.0 in /usr/local/lib/python3.7/dist-packages (from qiskit[visualization]) (0.14.0)
    Requirement already satisfied: qiskit-aer==0.8.2 in /usr/local/lib/python3.7/dist-packages (from qiskit[visualization]) (0.8.2)
    Requirement already satisfied: ipywidgets>=7.3.0; extra == "visualization" in /usr/local/lib/python3.7/dist-packages (from qiskit[visualization]) (7.6.3)
    Requirement already satisfied: pylatexenc>=1.4; extra == "visualization" in /usr/local/lib/python3.7/dist-packages (from qiskit[visualization]) (2.10)
    Requirement already satisfied: seaborn>=0.9.0; extra == "visualization" in /usr/local/lib/python3.7/dist-packages (from qiskit[visualization]) (0.11.1)
    Requirement already satisfied: pygments>=2.4; extra == "visualization" in /usr/local/lib/python3.7/dist-packages (from qiskit[visualization]) (2.6.1)
    Requirement already satisfied: pydot; extra == "visualization" in /usr/local/lib/python3.7/dist-packages (from qiskit[visualization]) (1.3.0)
    Requirement already satisfied: pillow>=4.2.1; extra == "visualization" in /usr/local/lib/python3.7/dist-packages (from qiskit[visualization]) (7.1.2)
    Requirement already satisfied: matplotlib>=2.1; extra == "visualization" in /usr/local/lib/python3.7/dist-packages (from qiskit[visualization]) (3.2.2)
    Requirement already satisfied: future>=0.15.2 in /usr/local/lib/python3.7/dist-packages (from autograd->pennylane) (0.16.0)
    Requirement already satisfied: decorator<5,>=4.3 in /usr/local/lib/python3.7/dist-packages (from networkx->pennylane) (4.4.2)
    Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.7/dist-packages (from python-dateutil->pennylane-ionq) (1.15.0)
    Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.7/dist-packages (from requests->pennylane-ionq) (2021.5.30)
    Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /usr/local/lib/python3.7/dist-packages (from requests->pennylane-ionq) (1.24.3)
    Requirement already satisfied: idna<3,>=2.5 in /usr/local/lib/python3.7/dist-packages (from requests->pennylane-ionq) (2.10)
    Requirement already satisfied: chardet<4,>=3.0.2 in /usr/local/lib/python3.7/dist-packages (from requests->pennylane-ionq) (3.0.4)
    Requirement already satisfied: jsonschema>=2.6 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.17.4->qiskit[visualization]) (2.6.0)
    Requirement already satisfied: retworkx>=0.8.0 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.17.4->qiskit[visualization]) (0.9.0)
    Requirement already satisfied: dill>=0.3 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.17.4->qiskit[visualization]) (0.3.4)
    Requirement already satisfied: fastjsonschema>=2.10 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.17.4->qiskit[visualization]) (2.15.1)
    Requirement already satisfied: ply>=3.10 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.17.4->qiskit[visualization]) (3.11)
    Requirement already satisfied: sympy>=1.3 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.17.4->qiskit[visualization]) (1.7.1)
    Requirement already satisfied: python-constraint>=1.4 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.17.4->qiskit[visualization]) (1.4.0)
    Requirement already satisfied: psutil>=5 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.17.4->qiskit[visualization]) (5.4.8)
    Requirement already satisfied: dlx<=1.0.4 in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.2->qiskit[visualization]) (1.0.4)
    Requirement already satisfied: setuptools>=40.1.0 in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.2->qiskit[visualization]) (57.0.0)
    Requirement already satisfied: h5py in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.2->qiskit[visualization]) (3.1.0)
    Requirement already satisfied: yfinance in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.2->qiskit[visualization]) (0.1.59)
    Requirement already satisfied: quandl in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.2->qiskit[visualization]) (3.6.1)
    Requirement already satisfied: fastdtw<=0.3.4 in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.2->qiskit[visualization]) (0.3.4)
    Requirement already satisfied: scikit-learn>=0.20.0 in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.2->qiskit[visualization]) (0.22.2.post1)
    Requirement already satisfied: pandas in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.2->qiskit[visualization]) (1.1.5)
    Requirement already satisfied: docplex<=2.20.204; sys_platform != "darwin" in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.2->qiskit[visualization]) (2.20.204)
    Requirement already satisfied: requests-ntlm>=1.1.0 in /usr/local/lib/python3.7/dist-packages (from qiskit-ibmq-provider==0.14.0->qiskit[visualization]) (1.1.0)
    Requirement already satisfied: websocket-client>=1.0.1 in /usr/local/lib/python3.7/dist-packages (from qiskit-ibmq-provider==0.14.0->qiskit[visualization]) (1.1.0)
    Requirement already satisfied: pybind11>=2.6 in /usr/local/lib/python3.7/dist-packages (from qiskit-aer==0.8.2->qiskit[visualization]) (2.6.2)
    Requirement already satisfied: jupyterlab-widgets>=1.0.0; python_version >= "3.6" in /usr/local/lib/python3.7/dist-packages (from ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (1.0.0)
    Requirement already satisfied: nbformat>=4.2.0 in /usr/local/lib/python3.7/dist-packages (from ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (5.1.3)
    Requirement already satisfied: traitlets>=4.3.1 in /usr/local/lib/python3.7/dist-packages (from ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (5.0.5)
    Requirement already satisfied: ipykernel>=4.5.1 in /usr/local/lib/python3.7/dist-packages (from ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (4.10.1)
    Requirement already satisfied: ipython>=4.0.0; python_version >= "3.3" in /usr/local/lib/python3.7/dist-packages (from ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (5.5.0)
    Requirement already satisfied: widgetsnbextension~=3.5.0 in /usr/local/lib/python3.7/dist-packages (from ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (3.5.1)
    Requirement already satisfied: pyparsing>=2.1.4 in /usr/local/lib/python3.7/dist-packages (from pydot; extra == "visualization"->qiskit[visualization]) (2.4.7)
    Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.7/dist-packages (from matplotlib>=2.1; extra == "visualization"->qiskit[visualization]) (0.10.0)
    Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib>=2.1; extra == "visualization"->qiskit[visualization]) (1.3.1)
    Requirement already satisfied: mpmath>=0.19 in /usr/local/lib/python3.7/dist-packages (from sympy>=1.3->qiskit-terra==0.17.4->qiskit[visualization]) (1.2.1)
    Requirement already satisfied: cached-property; python_version < "3.8" in /usr/local/lib/python3.7/dist-packages (from h5py->qiskit-aqua==0.9.2->qiskit[visualization]) (1.5.2)
    Requirement already satisfied: multitasking>=0.0.7 in /usr/local/lib/python3.7/dist-packages (from yfinance->qiskit-aqua==0.9.2->qiskit[visualization]) (0.0.9)
    Requirement already satisfied: lxml>=4.5.1 in /usr/local/lib/python3.7/dist-packages (from yfinance->qiskit-aqua==0.9.2->qiskit[visualization]) (4.6.3)
    Requirement already satisfied: more-itertools in /usr/local/lib/python3.7/dist-packages (from quandl->qiskit-aqua==0.9.2->qiskit[visualization]) (8.8.0)
    Requirement already satisfied: inflection>=0.3.1 in /usr/local/lib/python3.7/dist-packages (from quandl->qiskit-aqua==0.9.2->qiskit[visualization]) (0.5.1)
    Requirement already satisfied: joblib>=0.11 in /usr/local/lib/python3.7/dist-packages (from scikit-learn>=0.20.0->qiskit-aqua==0.9.2->qiskit[visualization]) (1.0.1)
    Requirement already satisfied: pytz>=2017.2 in /usr/local/lib/python3.7/dist-packages (from pandas->qiskit-aqua==0.9.2->qiskit[visualization]) (2018.9)
    Requirement already satisfied: cryptography>=1.3 in /usr/local/lib/python3.7/dist-packages (from requests-ntlm>=1.1.0->qiskit-ibmq-provider==0.14.0->qiskit[visualization]) (3.4.7)
    Requirement already satisfied: ntlm-auth>=1.0.2 in /usr/local/lib/python3.7/dist-packages (from requests-ntlm>=1.1.0->qiskit-ibmq-provider==0.14.0->qiskit[visualization]) (1.5.0)
    Requirement already satisfied: ipython-genutils in /usr/local/lib/python3.7/dist-packages (from nbformat>=4.2.0->ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (0.2.0)
    Requirement already satisfied: jupyter-core in /usr/local/lib/python3.7/dist-packages (from nbformat>=4.2.0->ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (4.7.1)
    Requirement already satisfied: tornado>=4.0 in /usr/local/lib/python3.7/dist-packages (from ipykernel>=4.5.1->ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (5.1.1)
    Requirement already satisfied: jupyter-client in /usr/local/lib/python3.7/dist-packages (from ipykernel>=4.5.1->ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (5.3.5)
    Requirement already satisfied: prompt-toolkit<2.0.0,>=1.0.4 in /usr/local/lib/python3.7/dist-packages (from ipython>=4.0.0; python_version >= "3.3"->ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (1.0.18)
    Requirement already satisfied: pickleshare in /usr/local/lib/python3.7/dist-packages (from ipython>=4.0.0; python_version >= "3.3"->ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (0.7.5)
    Requirement already satisfied: pexpect; sys_platform != "win32" in /usr/local/lib/python3.7/dist-packages (from ipython>=4.0.0; python_version >= "3.3"->ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (4.8.0)
    Requirement already satisfied: simplegeneric>0.8 in /usr/local/lib/python3.7/dist-packages (from ipython>=4.0.0; python_version >= "3.3"->ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (0.8.1)
    Requirement already satisfied: notebook>=4.4.1 in /usr/local/lib/python3.7/dist-packages (from widgetsnbextension~=3.5.0->ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (5.3.1)
    Requirement already satisfied: cffi>=1.12 in /usr/local/lib/python3.7/dist-packages (from cryptography>=1.3->requests-ntlm>=1.1.0->qiskit-ibmq-provider==0.14.0->qiskit[visualization]) (1.14.5)
    Requirement already satisfied: pyzmq>=13 in /usr/local/lib/python3.7/dist-packages (from jupyter-client->ipykernel>=4.5.1->ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (22.1.0)
    Requirement already satisfied: wcwidth in /usr/local/lib/python3.7/dist-packages (from prompt-toolkit<2.0.0,>=1.0.4->ipython>=4.0.0; python_version >= "3.3"->ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (0.2.5)
    Requirement already satisfied: ptyprocess>=0.5 in /usr/local/lib/python3.7/dist-packages (from pexpect; sys_platform != "win32"->ipython>=4.0.0; python_version >= "3.3"->ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (0.7.0)
    Requirement already satisfied: nbconvert in /usr/local/lib/python3.7/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (5.6.1)
    Requirement already satisfied: terminado>=0.8.1 in /usr/local/lib/python3.7/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (0.10.1)
    Requirement already satisfied: Send2Trash in /usr/local/lib/python3.7/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (1.5.0)
    Requirement already satisfied: jinja2 in /usr/local/lib/python3.7/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (2.11.3)
    Requirement already satisfied: pycparser in /usr/local/lib/python3.7/dist-packages (from cffi>=1.12->cryptography>=1.3->requests-ntlm>=1.1.0->qiskit-ibmq-provider==0.14.0->qiskit[visualization]) (2.20)
    Requirement already satisfied: mistune<2,>=0.8.1 in /usr/local/lib/python3.7/dist-packages (from nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (0.8.4)
    Requirement already satisfied: defusedxml in /usr/local/lib/python3.7/dist-packages (from nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (0.7.1)
    Requirement already satisfied: bleach in /usr/local/lib/python3.7/dist-packages (from nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (3.3.0)
    Requirement already satisfied: entrypoints>=0.2.2 in /usr/local/lib/python3.7/dist-packages (from nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (0.3)
    Requirement already satisfied: testpath in /usr/local/lib/python3.7/dist-packages (from nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (0.5.0)
    Requirement already satisfied: pandocfilters>=1.4.1 in /usr/local/lib/python3.7/dist-packages (from nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (1.4.3)
    Requirement already satisfied: MarkupSafe>=0.23 in /usr/local/lib/python3.7/dist-packages (from jinja2->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (2.0.1)
    Requirement already satisfied: packaging in /usr/local/lib/python3.7/dist-packages (from bleach->nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (20.9)
    Requirement already satisfied: webencodings in /usr/local/lib/python3.7/dist-packages (from bleach->nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets>=7.3.0; extra == "visualization"->qiskit[visualization]) (0.5.1)

```python
import os
import pennylane as qml
from pennylane import numpy as np
from pennylane.templates import RandomLayers
from pennylane_ionq import ops
import matplotlib.pyplot as plt
from qiskit import *
import torch
from torch.autograd import Variable
from torchvision import datasets, transforms
import torch.optim as optim
import torch.nn.functional as F
```

```python
use_cuda = torch.cuda.is_available()
print(use_cuda)
```

    True

```python
n_epochs = 30   # Number of optimization epochs
n_layers = 1    # Number of random layers
n_train = 128    # Size of the train dataset
n_test = 32     # Size of the test dataset

SAVE_PATH = "quanvolution_pqc/" # Data saving folder
PREPROCESS = True           # If False, skip quantum processing and load data from SAVE_PATH
# np.random.seed(0)           # Seed for NumPy random number generator
# tf.random.set_seed(0)       # Seed for TensorFlow random number generator
```

```python
BATCH_SIZE = 16
from torch.utils.data import SubsetRandomSampler
train_dataset = datasets.MNIST(root = "./data",
                               train = True,
                               download = True,
                               transform = transforms.ToTensor())

test_dataset = datasets.MNIST(root = "./data",
                              train = False,
                              transform = transforms.ToTensor())

# train_dataset = Subset(train_dataset,range(n_train))
# test_dataset = Subset(test_dataset,range(n_test))

train_sampler = SubsetRandomSampler(range(n_train))
test_sampler = SubsetRandomSampler(range(n_test))

train_loader = torch.utils.data.DataLoader(dataset = train_dataset,
                                           batch_size = BATCH_SIZE,
                                           shuffle = False,
                                           sampler = train_sampler)

test_loader = torch.utils.data.DataLoader(dataset = test_dataset,
                                          batch_size = BATCH_SIZE,
                                          shuffle = False,
                                          sampler = test_sampler)
```

    Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz
    Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz to ./data/MNIST/raw/train-images-idx3-ubyte.gz

    HBox(children=(FloatProgress(value=0.0, max=9912422.0), HTML(value='')))

    Extracting ./data/MNIST/raw/train-images-idx3-ubyte.gz to ./data/MNIST/raw

    Downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz
    Downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz to ./data/MNIST/raw/train-labels-idx1-ubyte.gz

    HBox(children=(FloatProgress(value=0.0, max=28881.0), HTML(value='')))

    Extracting ./data/MNIST/raw/train-labels-idx1-ubyte.gz to ./data/MNIST/raw

    Downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz
    Downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz to ./data/MNIST/raw/t10k-images-idx3-ubyte.gz
    Failed to download (trying next):
    HTTP Error 503: Service Unavailable

    Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-images-idx3-ubyte.gz
    Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-images-idx3-ubyte.gz to ./data/MNIST/raw/t10k-images-idx3-ubyte.gz

    HBox(children=(FloatProgress(value=0.0, max=1648877.0), HTML(value='')))

    Extracting ./data/MNIST/raw/t10k-images-idx3-ubyte.gz to ./data/MNIST/raw

    Downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz
    Failed to download (trying next):
    HTTP Error 503: Service Unavailable

    Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-labels-idx1-ubyte.gz
    Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-labels-idx1-ubyte.gz to ./data/MNIST/raw/t10k-labels-idx1-ubyte.gz

    HBox(children=(FloatProgress(value=0.0, max=4542.0), HTML(value='')))

    Extracting ./data/MNIST/raw/t10k-labels-idx1-ubyte.gz to ./data/MNIST/raw

    /usr/local/lib/python3.7/dist-packages/torchvision/datasets/mnist.py:498: UserWarning: The given NumPy array is not writeable, and PyTorch does not support non-writeable tensors. This means you can write to the underlying (supposedly non-writeable) NumPy array using the tensor. You may want to copy the array to protect its data or make it writeable before converting it to a tensor. This type of warning will be suppressed for the rest of this program. (Triggered internally at  /pytorch/torch/csrc/utils/tensor_numpy.cpp:180.)
      return torch.from_numpy(parsed.astype(m[2], copy=False)).view(*s)

```python
os.environ['IONQ_API_KEY']='1LCa7Dvzz5P35g6B3gwoxzFO04n7gWYH'
dev = qml.device("ionq.qpu", wires=9)

# Random circuit parameters

@qml.qnode(dev, interface='torch')
def pqc(data,params):
    # Encoding of 9 classical input values
    # len(params) = 2 * 9
    # print("data: ",data)
    # print("params: ",params)
    n_qubits = 9
    for j in range(n_qubits):
        qml.RY(np.pi * data[j], wires=j)

    # rand_params = np.random.uniform(high=2 * np.pi, size=(n_layers, 9))
    # print("rand", rand_params)
    # PQC
    for i in range(n_qubits):
        qml.RY(params[i], wires=i)
    for i in range(n_qubits-1):
        qml.CNOT(wires=[i,i+1])
    qml.CNOT(wires=[n_qubits-1,0])
    for i in range(n_qubits):
        qml.RY(params[i+n_qubits], wires=i)
    # Measurement producing 9 classical output values
    return qml.expval(qml.PauliZ(0))
```

    1LCa7Dvzz5P35g6B3gwoxzFO04n7gWYH

```python
print(pqc([1,0,2,1,2,3,1,2,0],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]))
```

```python
class QuanvNet(torch.nn.Module):
    def __init__(self,qc=True,opt=True):
        super().__init__()
        self.n_qubits = 9
        self.filters = 1
        self.conv_opt = torch.nn.Conv2d(in_channels=self.filters,out_channels=self.filters,kernel_size=3)
        self.conv1 = torch.nn.Conv2d(in_channels=self.filters,out_channels=8,kernel_size=3)
        self.pre_pool = torch.nn.AvgPool2d(2)
        self.pool = torch.nn.MaxPool2d(2)
        self.conv2 = torch.nn.Conv2d(in_channels=8,out_channels=8,kernel_size=3)
        if qc == True:
          self.fc1 = torch.nn.Linear(32,16)
        else:
          self.fc1 = torch.nn.Linear(32,16)
        self.fc2 = torch.nn.Linear(16,10)
        self.dropout = torch.nn.Dropout(0.4)
        self.q_params = torch.nn.Parameter(2*np.pi*torch.rand(12,12,self.filters,2*self.n_qubits))
        self.q_params.requires_grad = True

    def forward(self, inputs):
        inputs = self.pre_pool(inputs)/255
        qc = False
        if qc == True:
          out = torch.zeros((BATCH_SIZE,self.filters,12,12))
          for bat, image in enumerate(inputs):
              for j in range(1, 13, 1):
                  for k in range(1, 13, 1):
                      for i in range(self.filters):
                          q_results = pqc(
                          [
                              image[0, j - 1, k - 1].item(),
                              image[0, j - 1, k].item(),
                              image[0, j - 1, k + 1].item(),
                              image[0, j, k - 1].item(),
                              image[0, j, k].item(),
                              image[0, j, k + 1].item(),
                              image[0, j + 1, k - 1].item(),
                              image[0, j + 1, k].item(),
                              image[0, j + 1, k + 1].item()
                          ],
                              self.q_params[j-1,k-1,i]
                          )
                          out[bat,i,j - 1, k - 1] = q_results
        else:
          out = torch.zeros((BATCH_SIZE,self.filters,14,14))
          out = inputs
        # print(out.size())
        if opt==True:
          out = self.conv_opt(inputs)
        x = self.pool(F.relu(self.conv1(out)))
        # print(x.size())
        x = self.pool(F.relu(self.conv2(x)))
        x = torch.flatten(x,1)
        # print(x.size())
        x = F.relu(self.fc1(x))
        x = self.dropout(x)
        x = F.softmax(self.fc2(x))
        return x

```

```python
from torchsummary import summary
criterion = torch.nn.CrossEntropyLoss()
model = QuanvNet(qc=False,opt=True)
if use_cuda:
    model.cuda()
opt = optim.Adam(model.parameters(),lr=0.01)
summary(model,(1,28,28))
```

    ----------------------------------------------------------------
            Layer (type)               Output Shape         Param #
    ================================================================
             AvgPool2d-1            [-1, 1, 14, 14]               0
                Conv2d-2            [-1, 8, 12, 12]              80
             MaxPool2d-3              [-1, 8, 6, 6]               0
                Conv2d-4              [-1, 8, 4, 4]             584
             MaxPool2d-5              [-1, 8, 2, 2]               0
                Linear-6                   [-1, 16]             528
               Dropout-7                   [-1, 16]               0
                Linear-8                   [-1, 10]             170
    ================================================================
    Total params: 1,362
    Trainable params: 1,362
    Non-trainable params: 0
    ----------------------------------------------------------------
    Input size (MB): 0.00
    Forward/backward pass size (MB): 0.01
    Params size (MB): 0.01
    Estimated Total Size (MB): 0.02
    ----------------------------------------------------------------

    /usr/local/lib/python3.7/dist-packages/torch/nn/functional.py:718: UserWarning: Named tensors and all their associated APIs are an experimental feature and subject to change. Please do not use them for anything important until they are released as stable. (Triggered internally at  /pytorch/c10/core/TensorImpl.h:1156.)
      return torch.max_pool2d(input, kernel_size, stride, padding, dilation, ceil_mode)
    /usr/local/lib/python3.7/dist-packages/ipykernel_launcher.py:57: UserWarning: Implicit dimension choice for softmax has been deprecated. Change the call to include dim=X as an argument.

```python
for p in model.parameters():
    print(p.shape)
```

    torch.Size([12, 12, 1, 18])
    torch.Size([1, 1, 3, 3])
    torch.Size([1])
    torch.Size([8, 1, 3, 3])
    torch.Size([8])
    torch.Size([8, 8, 3, 3])
    torch.Size([8])
    torch.Size([16, 32])
    torch.Size([16])
    torch.Size([10, 16])
    torch.Size([10])

```python
losses = []
accs = []
for epoch in range(10000):
  train_loss = 0
  acc = 0
  for (x_train, y_train) in train_loader:
    # print(y_train)
    opt.zero_grad()
    outputs = model(x_train.cuda() if use_cuda else x_train)
    _, preds = torch.max(outputs,1)
    acc += (preds==(y_train.cuda() if use_cuda else y_train)).sum().item()
    loss = criterion(outputs,(y_train.cuda() if use_cuda else y_train))
    loss.backward()
    opt.step()
    train_loss += loss
    del loss
  acc /= n_train
  train_loss /= (n_train/BATCH_SIZE)
  if epoch%10 == 9:
    if epoch%100 == 99:
      print(epoch+1,train_loss)
    losses.append(train_loss.item())
  if epoch%10 == 9:
    accs.append(acc)
  del acc
```

    /usr/local/lib/python3.7/dist-packages/ipykernel_launcher.py:57: UserWarning: Implicit dimension choice for softmax has been deprecated. Change the call to include dim=X as an argument.

    100 tensor(2.2774, device='cuda:0', grad_fn=<DivBackward0>)
    200 tensor(2.0464, device='cuda:0', grad_fn=<DivBackward0>)
    300 tensor(1.8611, device='cuda:0', grad_fn=<DivBackward0>)
    400 tensor(1.8236, device='cuda:0', grad_fn=<DivBackward0>)
    500 tensor(1.7977, device='cuda:0', grad_fn=<DivBackward0>)
    600 tensor(1.7520, device='cuda:0', grad_fn=<DivBackward0>)
    700 tensor(1.7200, device='cuda:0', grad_fn=<DivBackward0>)
    800 tensor(1.7683, device='cuda:0', grad_fn=<DivBackward0>)
    900 tensor(1.7078, device='cuda:0', grad_fn=<DivBackward0>)
    1000 tensor(1.7500, device='cuda:0', grad_fn=<DivBackward0>)
    1100 tensor(1.7332, device='cuda:0', grad_fn=<DivBackward0>)
    1200 tensor(1.7049, device='cuda:0', grad_fn=<DivBackward0>)
    1300 tensor(1.7317, device='cuda:0', grad_fn=<DivBackward0>)
    1400 tensor(1.7285, device='cuda:0', grad_fn=<DivBackward0>)
    1500 tensor(1.7367, device='cuda:0', grad_fn=<DivBackward0>)
    1600 tensor(1.7035, device='cuda:0', grad_fn=<DivBackward0>)
    1700 tensor(1.7171, device='cuda:0', grad_fn=<DivBackward0>)
    1800 tensor(1.7270, device='cuda:0', grad_fn=<DivBackward0>)
    1900 tensor(1.7131, device='cuda:0', grad_fn=<DivBackward0>)
    2000 tensor(1.7252, device='cuda:0', grad_fn=<DivBackward0>)
    2100 tensor(1.7049, device='cuda:0', grad_fn=<DivBackward0>)
    2200 tensor(1.7134, device='cuda:0', grad_fn=<DivBackward0>)
    2300 tensor(1.6944, device='cuda:0', grad_fn=<DivBackward0>)
    2400 tensor(1.7162, device='cuda:0', grad_fn=<DivBackward0>)
    2500 tensor(1.7796, device='cuda:0', grad_fn=<DivBackward0>)
    2600 tensor(1.7119, device='cuda:0', grad_fn=<DivBackward0>)
    2700 tensor(1.6704, device='cuda:0', grad_fn=<DivBackward0>)
    2800 tensor(1.7935, device='cuda:0', grad_fn=<DivBackward0>)
    2900 tensor(1.7494, device='cuda:0', grad_fn=<DivBackward0>)
    3000 tensor(1.7575, device='cuda:0', grad_fn=<DivBackward0>)
    3100 tensor(1.7545, device='cuda:0', grad_fn=<DivBackward0>)
    3200 tensor(1.7485, device='cuda:0', grad_fn=<DivBackward0>)
    3300 tensor(1.7043, device='cuda:0', grad_fn=<DivBackward0>)
    3400 tensor(1.6991, device='cuda:0', grad_fn=<DivBackward0>)
    3500 tensor(1.7404, device='cuda:0', grad_fn=<DivBackward0>)
    3600 tensor(1.7043, device='cuda:0', grad_fn=<DivBackward0>)
    3700 tensor(1.7025, device='cuda:0', grad_fn=<DivBackward0>)
    3800 tensor(1.7457, device='cuda:0', grad_fn=<DivBackward0>)
    3900 tensor(1.7696, device='cuda:0', grad_fn=<DivBackward0>)
    4000 tensor(1.7692, device='cuda:0', grad_fn=<DivBackward0>)
    4100 tensor(1.7070, device='cuda:0', grad_fn=<DivBackward0>)
    4200 tensor(1.6875, device='cuda:0', grad_fn=<DivBackward0>)
    4300 tensor(1.6958, device='cuda:0', grad_fn=<DivBackward0>)
    4400 tensor(1.7299, device='cuda:0', grad_fn=<DivBackward0>)
    4500 tensor(1.7323, device='cuda:0', grad_fn=<DivBackward0>)
    4600 tensor(1.7272, device='cuda:0', grad_fn=<DivBackward0>)
    4700 tensor(1.7499, device='cuda:0', grad_fn=<DivBackward0>)
    4800 tensor(1.7509, device='cuda:0', grad_fn=<DivBackward0>)
    4900 tensor(1.6996, device='cuda:0', grad_fn=<DivBackward0>)
    5000 tensor(1.6813, device='cuda:0', grad_fn=<DivBackward0>)
    5100 tensor(1.7018, device='cuda:0', grad_fn=<DivBackward0>)
    5200 tensor(1.7215, device='cuda:0', grad_fn=<DivBackward0>)
    5300 tensor(1.7707, device='cuda:0', grad_fn=<DivBackward0>)
    5400 tensor(1.7116, device='cuda:0', grad_fn=<DivBackward0>)
    5500 tensor(1.6995, device='cuda:0', grad_fn=<DivBackward0>)
    5600 tensor(1.7852, device='cuda:0', grad_fn=<DivBackward0>)
    5700 tensor(1.6981, device='cuda:0', grad_fn=<DivBackward0>)
    5800 tensor(1.7513, device='cuda:0', grad_fn=<DivBackward0>)
    5900 tensor(1.7203, device='cuda:0', grad_fn=<DivBackward0>)
    6000 tensor(1.6599, device='cuda:0', grad_fn=<DivBackward0>)
    6100 tensor(1.7213, device='cuda:0', grad_fn=<DivBackward0>)
    6200 tensor(1.7631, device='cuda:0', grad_fn=<DivBackward0>)
    6300 tensor(1.7060, device='cuda:0', grad_fn=<DivBackward0>)
    6400 tensor(1.7958, device='cuda:0', grad_fn=<DivBackward0>)
    6500 tensor(1.6994, device='cuda:0', grad_fn=<DivBackward0>)
    6600 tensor(1.7302, device='cuda:0', grad_fn=<DivBackward0>)
    6700 tensor(1.7280, device='cuda:0', grad_fn=<DivBackward0>)
    6800 tensor(1.7143, device='cuda:0', grad_fn=<DivBackward0>)
    6900 tensor(1.7274, device='cuda:0', grad_fn=<DivBackward0>)
    7000 tensor(1.7194, device='cuda:0', grad_fn=<DivBackward0>)
    7100 tensor(1.7159, device='cuda:0', grad_fn=<DivBackward0>)
    7200 tensor(1.7235, device='cuda:0', grad_fn=<DivBackward0>)
    7300 tensor(1.6964, device='cuda:0', grad_fn=<DivBackward0>)
    7400 tensor(1.7048, device='cuda:0', grad_fn=<DivBackward0>)
    7500 tensor(1.7398, device='cuda:0', grad_fn=<DivBackward0>)
    7600 tensor(1.7498, device='cuda:0', grad_fn=<DivBackward0>)
    7700 tensor(1.6925, device='cuda:0', grad_fn=<DivBackward0>)
    7800 tensor(1.6970, device='cuda:0', grad_fn=<DivBackward0>)
    7900 tensor(1.6918, device='cuda:0', grad_fn=<DivBackward0>)
    8000 tensor(1.9402, device='cuda:0', grad_fn=<DivBackward0>)
    8100 tensor(1.7627, device='cuda:0', grad_fn=<DivBackward0>)
    8200 tensor(1.7777, device='cuda:0', grad_fn=<DivBackward0>)
    8300 tensor(1.7291, device='cuda:0', grad_fn=<DivBackward0>)
    8400 tensor(1.7341, device='cuda:0', grad_fn=<DivBackward0>)
    8500 tensor(1.7646, device='cuda:0', grad_fn=<DivBackward0>)
    8600 tensor(1.7169, device='cuda:0', grad_fn=<DivBackward0>)
    8700 tensor(1.6884, device='cuda:0', grad_fn=<DivBackward0>)
    8800 tensor(1.6726, device='cuda:0', grad_fn=<DivBackward0>)
    8900 tensor(1.7408, device='cuda:0', grad_fn=<DivBackward0>)
    9000 tensor(1.6919, device='cuda:0', grad_fn=<DivBackward0>)
    9100 tensor(1.7121, device='cuda:0', grad_fn=<DivBackward0>)
    9200 tensor(1.8130, device='cuda:0', grad_fn=<DivBackward0>)
    9300 tensor(1.6796, device='cuda:0', grad_fn=<DivBackward0>)
    9400 tensor(1.7852, device='cuda:0', grad_fn=<DivBackward0>)
    9500 tensor(1.7346, device='cuda:0', grad_fn=<DivBackward0>)
    9600 tensor(1.7184, device='cuda:0', grad_fn=<DivBackward0>)
    9700 tensor(1.7418, device='cuda:0', grad_fn=<DivBackward0>)
    9800 tensor(1.7182, device='cuda:0', grad_fn=<DivBackward0>)
    9900 tensor(1.7344, device='cuda:0', grad_fn=<DivBackward0>)
    10000 tensor(1.7457, device='cuda:0', grad_fn=<DivBackward0>)

```python
from matplotlib.pyplot import plot
x = np.arange(0,10000,10)
plot(x,losses)
```

```python
x = np.arange(0,10000,10)
plot(x,accs)
```


#  4 Trajectory Analysis

***

** Important Note **

Before proceeding to the rest of the analysis, it is a good time to define a path that points to the location of the MD simulation data, which we will analyze here.

If you successfully ran the MD simulation, the correct path should be:

```python
# Execute the cell to define the path to your simulation files
path="OxCompBio-Datafiles/run"
```

If however, you need/want to use the data from the simulation that has been already performed, uncomment the command below to instead define the path that points to the prerun simulation.

```python
# Uncomment the line below and execute the cell to define the path to the prerun simulation files
#path="OxCompBio-Datafiles/prerun/run"
```

##  4.1 Visualize the simulation

The simplest and easiest type of analysis you should always do is to look at it with your eyes! Your eyes will tell you if something strange is happening immediately. A numerical analysis may not.

###   4.1.1 VMD

*Note: Again, this step is optional. If you don't have VMD, go to section 4.1.2 below to visualize the trajectory with NGLView instead.*

Let us look at the simulations on VMD.

Open your vmd, by typing on your terminal:

`% vmd`

When it has finished placing all the windows on the screen. Click on `File` in the VMD main menu window and select `New Molecule`. The Molecule File Browser window should appear. Click on `Browse...` then select the `OxCompBio-Datafiles` and then the `run` directory and finally select `em.gro` (i.e. the file you made that has protein system energy minimized). Click `OK` and then click `Load`. It should load up the starting coordinates into the main window. Then click `Browse...` in the Molecule File Browser window. Select again the `OxCompBio-Datafiles`, then the `run` directory and then `md.xtc`. Select `OK` and then hit `Load`. The trajectory should start loading into the main VMD window.

Although things will be moving, you can see that it is quite difficult to visualize the individual components. That is one of the problems with simulating such large and complicated systems. VMD makes it quite easy to look at individual components of a system. For example, let us consider the protein only. On the VMD Main menu, left-click on Graphics and select `Representations`. A new menu will appear (`Graphical Representations`). In the box entitled `Selected Atoms` type protein and hit enter. Only those atoms that form part of the protein are now selected. Various other selections and drawing methods will help to visualize different aspects of the simulation.

 **Questions**

* How would you say the protein behaves?

* Is it doing anything unexpected? What would you consider unexpected behaviour?

* Can you add representations for the ASP and the ARG residues only? Can you observe if they form any inter-subunit interactions? We will quantify those later on.

###  4.1.2 NGLView

You have already tested NGLView at the Python tutorial (Notebook `12_ProteinAnalysis`) and at the beginning of this tutorial. This time however, you can visualize the trajectory you generated after carrying out the MD simulation.

You should also be familiar now with the MDAnalysis Python library that we will use to analyze the MD trajectory. We will also use it below, to create a Universe and load it on NGLView.

```python
# Import MDAnalysis and NGLView
import MDAnalysis
import nglview

# Load the protein structure and the trajectory as a universe named protein
protein=MDAnalysis.Universe(f"{path}/em.gro", f"{path}/md_fit.xtc")
protein_view = nglview.show_mdanalysis(protein)
protein_view.gui_style = 'ngl'

#Color the protein based on its secondary structure
protein_view.update_cartoon(color='sstruc')
protein_view
```

 **Questions**

* How would you say the protein behaves?

* Is it doing anything unexpected? What would you consider unexpected behaviour?

* Can you add representations for the ASP and the ARG residues only? Can you observe if they form any inter-subunit interactions? We will quantify those later on.

Now that we are sure the simulation is not doing anything ridiculous, we can start to ask questions about the simulation. The first thing to establish is whether the simulation has equilibrated to some state. So what are some measures of the system
being equilibrated? And what can we use to test the reliability of the simulation?

##  4.2 System Equilibration

###  4.2.1 Temperature fluctuation

The system temperature as a function of time was calculated in the previous section, with the built-in GROMACS tool `gmx energy`, but we still have not looked at it. It is now time to plot the temperature *vs* time and assess the results.

 **Questions**

* Does the temperature fluctuate around an equilibrium  value?

* Does this value correspond to the temperature that we predefined in the `md.mdp` input file?

Import numpy and pyplot from matplotlib, required to read and plot the data, respectively.

```python
# We declare matplotlib inline to make sure it plots properly
%matplotlib inline
# We need to import numpy
import numpy as np
# We need pyplot from matplotlib to generate our plots
from matplotlib import pyplot
```

Now, using numpy, we can read the data from the `1hsg_temperature.xvg` file; the first column is the time (in ps) and the secong is the system temperature (in K).

```python
# Read the file that contains the system temperature for each frame
time=np.loadtxt(f"{path}/1hsg_temperature.xvg", comments=['#','@'])[:, 0]
temperature=np.loadtxt(f"{path}/1hsg_temperature.xvg", comments=['#','@'])[:, 1]
```

You can use numpy again to compute the average temperature and its standard deviation.

```python
# Calculate and print the mean temperature and the standard deviation
# Keep only two decimal points
mean_temperature=round(np.mean(temperature), 2)
std_temperature=round(np.std(temperature), 2)
print(f"The mean temperature is {mean_temperature} ± {std_temperature} K")
```

Finally, you can plot the temperature *vs* simulation time.

```python
# Plot the temperature
pyplot.plot(time, temperature, color='darkred')
pyplot.title("Temperature over time")
pyplot.xlabel("Time [ps]")
pyplot.ylabel("Temperature [K]")
pyplot.show()
```

###  4.2.2 Energy of the system

Another set of properties that is quite useful to examine is the various energetic contributions to the energy. The total
energy should be constant. but the various contributions can change and this can sometimes indicate something
interesting or strange happening in your simulation. Let us look at some energetic properties of the simulation.

We have already exctracted the Lennard-Jones energy, the Coulomb energy and the potential energy using again the GROMACS built-in tool `gmx energy`. The data of these three energetic components are saved in the same file called `1hsg_energies.xvg`; the first column contains the time (in ps) and the columns that follow contain the energies (in kJ/mol), in the same order as they were generated.

We can now read the data from the `1hsg_energies.xvg` file using numpy.

```python
# Read the file that contains the various energetic components for each frame
time=np.loadtxt(f"{path}/1hsg_energies.xvg", comments=['#','@'])[:, 0]
lennard_jones=np.loadtxt(f"{path}/1hsg_energies.xvg", comments=['#','@'])[:, 1]
coulomb=np.loadtxt(f"{path}/1hsg_energies.xvg", comments=['#','@'])[:, 2]
potential=np.loadtxt(f"{path}/1hsg_energies.xvg", comments=['#','@'])[:, 3]
```

And now that we read the data file, we can plot the energetic components *vs* simulation time in separate plots using matplotlib.

```python
# Plot the Lennard-Jones energy
pyplot.plot(time, lennard_jones, color='blue')
pyplot.title("Lennard Jones energy over time")
pyplot.xlabel("Time [ps]")
pyplot.ylabel("LJ energy [kJ/mol]")
pyplot.show()

# Plot the electrostatic energy

# Plot the potential energy

```

 **Questions**

* Can you plot the Coulomb energy and the potential energy, following the same steps as above?

* Is the total energy stable in this simulation?

* What is the dominant contribution to the potential energy?

##  4.3 Analysis of Protein

*Hint:* Ideally, you should visualize the trajectory with either VMD or NGLView and combine the information you extract from the plots with what you observe visually. That applies to all the structural analysis that you perform. So feel free at any point to go back to VMD or NGLView to verify the results you get from the analysis below.

###  4.3.1 Root mean square deviation (RMSD) of 1HSG

The RMSD gives us an idea of how 'stable' our protein is when compared to our starting, static, structure. The lower the RMSD is, the more stable we can say our protein is.

The RMSD as a function of time, $\rho (t)$, can be defined by the following equation:

\begin{equation}
\\
\rho (t) = \sqrt{\frac{1}{N}\sum^N_{i=1}w_i\big(\mathbf{x}_i(t) - \mathbf{x}^{\text{ref}}_i\big)^2}
\end{equation}

Luckily MDAnalysis has its own built-in function to calculate this and we can import it.

```python
# Import built-in MDAnalysis tools for alignment and RMSD.
from MDAnalysis.analysis import align
from MDAnalysis.analysis.rms import RMSD as rmsd

# Define the simulation universe and the reference structure (protein structure at first frame)
protein = MDAnalysis.Universe(f"{path}/md.gro", f"{path}/md_fit.xtc")
protein_ref = MDAnalysis.Universe(f"{path}/em.gro", f"{path}/md_fit.xtc")
protein_ref.trajectory[0]

# Call the MDAnalysis align function to align the MD simulation universe to the reference (first frame) universe
align_strucs = align.AlignTraj(protein, protein_ref, select="backbone", weights="mass", in_memory=True, verbose=True)

R = align_strucs.run()
rmsd_data = R.rmsd

# Plot the RMSD
pyplot.plot(rmsd_data)
pyplot.title("RMSD over time")
pyplot.xlabel("Frame number")
pyplot.ylabel("RMSD (Angstrom)")
pyplot.show()

```

 **Questions**

* What does this tell you about the stability of the protein? Is it in a state of equilibrium and if so why and at what time?

* Can you think of a situation where this approach might not be a very good indication of stability?

###  4.3.2 Root mean square fluctuation (RMSF) of 1HSG

A similar property that is particularly useful is the root mean square fluctuation (RMSF), which shows how each residue flucuates over its average position.

The RMSF for an atom, $\rho_i$, is given by:

\begin{equation}
\rho_i = \sqrt{\sum^N_{i=1} \big\langle(\mathbf{x}_i - \langle \mathbf{x}_i \rangle )^2 \big\rangle }
\end{equation}

```python
from MDAnalysis.analysis.rms import RMSF as rmsf

# Define again the simulation universe, using however the renumbered .gro file that you had generated earlier
protein = MDAnalysis.Universe(f"{path}/em.gro", f"{path}/md_fit.xtc")

# Reset the trajectory to the first frame
protein.trajectory[0]

# We will need to select the alpha Carbons only
calphas = protein.select_atoms("name CA")

# Compute the RMSF of alpha carbons. Omit the first 20 frames,
# assuming that the system needs this amount of time (200 ps) to equilibrate
rmsf_calc = rmsf(calphas, verbose=True).run(start=20)

# Plot the RMSF
pyplot.plot(calphas.resindices+1, rmsf_calc.rmsf, color='darkorange' )
pyplot.title("Per-Residue Alpha Carbon RMSF")
pyplot.xlabel("Residue Number")
pyplot.ylabel("RMSF (Angstrom)")
pyplot.show()
```

 **Questions**

* Can you identify structural regions alone from this plot and does that fit in with the structure?

* Residues 43-58 form part of the flexible flap that covers the binding site. How does this region behave in the simulation? Remember that you have a homodimer, so chain A contains residues 1-99 and chain B contains residues 100 to 198.

###  4.3.3 Hydrogen Bond Formation

We can also use the simulation to monitor the formation of any hydrogen bonds that may be of interest.

In the case of HIV-1 protease, the hydrogen bonds (HB) that are formed between the ARG8', the ASP29 and the ARG87 amino acids at the interface of the two subunits act in stabilising the dimer.

We can analyse the trajectory and monitor the stability of these interactions *vs* simulation time.

```python
# Import the MDAnalysis built-in tool for HB Analysis
from MDAnalysis.analysis.hydrogenbonds.hbond_analysis import HydrogenBondAnalysis as HBA

# Define the protein universe
# Note that when using this tool, it is recommended to include the .tpr file instead of the .gro file,
# because it contains bond information, required for the identification of donors and acceptors.
protein = MDAnalysis.Universe(f"{path}/md.tpr", f"{path}/md.xtc")

# Define the atom selections for the HB calculation.
# In this case, the ARG hydrogens and the ASP oxygens, which act as the HB acceptors are specifically defined.
hbonds = HBA(universe=protein, hydrogens_sel='resname ARG and name HH21 HH22', acceptors_sel='resname ASP and name OD1 OD2')

# Perform the HB calculation
hbonds.run()

# Plot the total number of ASP-ARG HBs vs time
hbonds_time=hbonds.times
hbonds_data=hbonds.count_by_time()

pyplot.plot(hbonds_time, hbonds_data, color='cyan')
pyplot.title("ASP-ARG Hydrogen Bonds")
pyplot.xlabel("Time [ps]")
pyplot.ylabel("# Hydrogen Bonds")
pyplot.show()

# Compute and print the average number of HBs and the standard deviation
aver_hbonds=round(np.mean(hbonds_data), 2)
std_hbonds=round(np.std(hbonds_data), 2)
print(f"The average number of ASP-ARG HBs is {aver_hbonds} ± {std_hbonds}")
```

 **Questions**

* How much variation is there in the number of hydrogen bonds?

* Do any break and not reform?

* Using VMD, can you observe the HB formation and breakage throughout the simulation?

***

This concludes the analysis section, but the aim was only to give you an idea of the numerous information that we can gain when analysing an MD trajectory. Feel free to ask and attempt to answer your own questions, utilising the tools that you were introduced to during the tutorial.

##  4.4 Further Reading

The texts recommended here are the same as those mentioned in the lecture:
* "Molecular Modelling. Principles and Applications". Andrew Leach. Publisher: Prentice Hall. ISBN: 0582382106. This book has rapidly become the defacto introductory text for all aspects of simulation.
* "Computer simulation of liquids". Allen, Michael P., and Dominic J. Tildesley. Oxford university press, 2017.
* "Molecular Dynamics Simulation: Elementary Methods". J.M. Haile. Publisher: Wiley. ISBN: 047118439X. This text provides a more focus but slightly more old-fashioned view of simulation. It has some nice simple examples of how to code (in fortran) some of the algorithms though.

##  End of Tutorial

Congratulations, you have finished the MD tutorial. Hopefully, by you are familiar with the molecular dynamics method, the GROMACS software that we have used to perform the simulation, and you have an idea of the type of information that we can extract from an MD run and how we can visualize, compute and plot the data of interest.