# Lab 1: Single-qubit and multi-qubit states, quantum teleportation

In this lab, you will learn how to write `Qiskit` code and investigate single-qubit and multi-qubit states using the `qpshere` visualization that you learned in lecture 1.

If you have not used Jupyter notebooks before, take a look at the following video to quickly get started.
- https://www.youtube.com/watch?v=jZ952vChhuI

Remember, to run a cell in Jupyter notebooks, you press `Shift` + `Return/Enter` on your keyboard.

### Installing necessary packages

Before we begin, you will need to install some prerequisites into your environment. Run the cell below to complete these installations. At the end, the cell outputs will be cleared.

```python
!pip install -U -r grading_tools/requirements.txt

from IPython.display import clear_output
clear_output()
```

    Requirement already satisfied, skipping upgrade: networkx>=2.2; python_version > "3.5" in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from qiskit-terra==0.14.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (2.4)
    Requirement already satisfied, skipping upgrade: retworkx>=0.3.2 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from qiskit-terra==0.14.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (0.3.4)
    Requirement already satisfied, skipping upgrade: python-dateutil>=2.8.0 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from qiskit-terra==0.14.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (2.8.1)
    Requirement already satisfied, skipping upgrade: ply>=3.10 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from qiskit-terra==0.14.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (3.11)
    Requirement already satisfied, skipping upgrade: cython>=0.27.1 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from qiskit-aer==0.5.1->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (0.29.20)
    Requirement already satisfied, skipping upgrade: pybind11>=2.4 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from qiskit-aer==0.5.1->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (2.5.0)
    Requirement already satisfied, skipping upgrade: requests>=2.19 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from qiskit-ibmq-provider==0.7.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (2.24.0)
    Requirement already satisfied, skipping upgrade: nest-asyncio!=1.1.0,>=1.0.0 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from qiskit-ibmq-provider==0.7.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (1.3.3)
    Requirement already satisfied, skipping upgrade: urllib3>=1.21.1 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from qiskit-ibmq-provider==0.7.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (1.25.9)
    Requirement already satisfied, skipping upgrade: websockets<8,>=7 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from qiskit-ibmq-provider==0.7.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (7.0)
    Requirement already satisfied, skipping upgrade: requests-ntlm>=1.1.0 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from qiskit-ibmq-provider==0.7.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (1.1.0)
    Requirement already satisfied, skipping upgrade: setuptools>=40.1.0 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from qiskit-ignis==0.3.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (47.3.1)
    Requirement already satisfied, skipping upgrade: cplex; python_version >= "3.6" and python_version < "3.8" in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from qiskit-aqua==0.7.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (12.10.0.2)
    Requirement already satisfied, skipping upgrade: h5py in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from qiskit-aqua==0.7.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (2.10.0)
    Requirement already satisfied, skipping upgrade: scikit-learn>=0.20.0 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from qiskit-aqua==0.7.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (0.23.1)
    Requirement already satisfied, skipping upgrade: quandl in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from qiskit-aqua==0.7.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (3.5.0)
    Requirement already satisfied, skipping upgrade: fastdtw in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from qiskit-aqua==0.7.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (0.3.4)
    Requirement already satisfied, skipping upgrade: dlx in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from qiskit-aqua==0.7.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (1.0.4)
    Requirement already satisfied, skipping upgrade: docplex in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from qiskit-aqua==0.7.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (2.14.186)
    Requirement already satisfied, skipping upgrade: pytz>=2017.2 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from pandas>=0.22.0->seaborn==0.10->-r grading_tools/requirements.txt (line 2)) (2020.1)
    Requirement already satisfied, skipping upgrade: cycler>=0.10 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from matplotlib>=2.1.2->seaborn==0.10->-r grading_tools/requirements.txt (line 2)) (0.10.0)
    Requirement already satisfied, skipping upgrade: kiwisolver>=1.0.1 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from matplotlib>=2.1.2->seaborn==0.10->-r grading_tools/requirements.txt (line 2)) (1.2.0)
    Requirement already satisfied, skipping upgrade: pillow>=6.2.0 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from matplotlib>=2.1.2->seaborn==0.10->-r grading_tools/requirements.txt (line 2)) (7.2.0)
    Requirement already satisfied, skipping upgrade: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.3 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from matplotlib>=2.1.2->seaborn==0.10->-r grading_tools/requirements.txt (line 2)) (2.4.7)
    Requirement already satisfied, skipping upgrade: pygments in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from ipython>=4.0.0; python_version >= "3.3"->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (2.6.1)
    Requirement already satisfied, skipping upgrade: prompt-toolkit!=3.0.0,!=3.0.1,<3.1.0,>=2.0.0 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from ipython>=4.0.0; python_version >= "3.3"->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (3.0.5)
    Requirement already satisfied, skipping upgrade: decorator in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from ipython>=4.0.0; python_version >= "3.3"->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (4.4.2)
    Requirement already satisfied, skipping upgrade: jedi>=0.10 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from ipython>=4.0.0; python_version >= "3.3"->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (0.17.0)
    Requirement already satisfied, skipping upgrade: pickleshare in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from ipython>=4.0.0; python_version >= "3.3"->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (0.7.5)
    Requirement already satisfied, skipping upgrade: backcall in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from ipython>=4.0.0; python_version >= "3.3"->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (0.1.0)
    Requirement already satisfied, skipping upgrade: colorama; sys_platform == "win32" in c:\users\codie\appdata\roaming\python\python37\site-packages (from ipython>=4.0.0; python_version >= "3.3"->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (0.4.1)
    Requirement already satisfied, skipping upgrade: jupyter-core in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from nbformat>=4.2.0->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (4.6.3)
    Requirement already satisfied, skipping upgrade: ipython-genutils in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from nbformat>=4.2.0->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (0.2.0)
    Requirement already satisfied, skipping upgrade: jupyter-client in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from ipykernel>=4.5.1->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (6.1.3)
    Requirement already satisfied, skipping upgrade: tornado>=4.2 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from ipykernel>=4.5.1->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (6.0.4)
    Requirement already satisfied, skipping upgrade: six in c:\users\codie\appdata\roaming\python\python37\site-packages (from traitlets>=4.3.1->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (1.12.0)
    Requirement already satisfied, skipping upgrade: notebook>=4.4.1 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from widgetsnbextension~=3.5.0->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (6.0.3)
    Requirement already satisfied, skipping upgrade: mpmath>=0.19 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from sympy>=1.3->qiskit-terra==0.14.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (1.1.0)
    Requirement already satisfied, skipping upgrade: attrs>=17.4.0 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from jsonschema>=2.6->qiskit-terra==0.14.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (19.3.0)
    Requirement already satisfied, skipping upgrade: pyrsistent>=0.14.0 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from jsonschema>=2.6->qiskit-terra==0.14.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (0.16.0)
    Requirement already satisfied, skipping upgrade: importlib-metadata; python_version < "3.8" in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from jsonschema>=2.6->qiskit-terra==0.14.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (1.6.0)
    Requirement already satisfied, skipping upgrade: chardet<4,>=3.0.2 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from requests>=2.19->qiskit-ibmq-provider==0.7.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (3.0.4)
    Requirement already satisfied, skipping upgrade: idna<3,>=2.5 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from requests>=2.19->qiskit-ibmq-provider==0.7.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (2.9)
    Requirement already satisfied, skipping upgrade: certifi>=2017.4.17 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from requests>=2.19->qiskit-ibmq-provider==0.7.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (2020.6.20)
    Requirement already satisfied, skipping upgrade: ntlm-auth>=1.0.2 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from requests-ntlm>=1.1.0->qiskit-ibmq-provider==0.7.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (1.5.0)
    Requirement already satisfied, skipping upgrade: cryptography>=1.3 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from requests-ntlm>=1.1.0->qiskit-ibmq-provider==0.7.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (2.8)
    Requirement already satisfied, skipping upgrade: joblib>=0.11 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from scikit-learn>=0.20.0->qiskit-aqua==0.7.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (0.15.1)
    Requirement already satisfied, skipping upgrade: threadpoolctl>=2.0.0 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from scikit-learn>=0.20.0->qiskit-aqua==0.7.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (2.1.0)
    Requirement already satisfied, skipping upgrade: more-itertools in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from quandl->qiskit-aqua==0.7.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (8.4.0)
    Requirement already satisfied, skipping upgrade: inflection>=0.3.1 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from quandl->qiskit-aqua==0.7.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (0.5.0)
    Requirement already satisfied, skipping upgrade: wcwidth in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from prompt-toolkit!=3.0.0,!=3.0.1,<3.1.0,>=2.0.0->ipython>=4.0.0; python_version >= "3.3"->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (0.2.2)
    Requirement already satisfied, skipping upgrade: parso>=0.7.0 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from jedi>=0.10->ipython>=4.0.0; python_version >= "3.3"->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (0.7.0)
    Requirement already satisfied, skipping upgrade: pywin32>=1.0; sys_platform == "win32" in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from jupyter-core->nbformat>=4.2.0->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (227)
    Requirement already satisfied, skipping upgrade: pyzmq>=13 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from jupyter-client->ipykernel>=4.5.1->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (19.0.1)
    Requirement already satisfied, skipping upgrade: prometheus-client in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (0.8.0)
    Requirement already satisfied, skipping upgrade: Send2Trash in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (1.5.0)
    Requirement already satisfied, skipping upgrade: jinja2 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (2.11.2)
    Requirement already satisfied, skipping upgrade: nbconvert in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (5.6.1)
    Requirement already satisfied, skipping upgrade: terminado>=0.8.1 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (0.8.3)
    Requirement already satisfied, skipping upgrade: zipp>=0.5 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from importlib-metadata; python_version < "3.8"->jsonschema>=2.6->qiskit-terra==0.14.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (3.1.0)
    Requirement already satisfied, skipping upgrade: cffi!=1.11.3,>=1.8 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from cryptography>=1.3->requests-ntlm>=1.1.0->qiskit-ibmq-provider==0.7.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (1.14.0)
    Requirement already satisfied, skipping upgrade: MarkupSafe>=0.23 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from jinja2->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (1.1.1)
    Requirement already satisfied, skipping upgrade: entrypoints>=0.2.2 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (0.3)
    Requirement already satisfied, skipping upgrade: bleach in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (3.1.5)
    Requirement already satisfied, skipping upgrade: defusedxml in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (0.6.0)
    Requirement already satisfied, skipping upgrade: testpath in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (0.4.4)
    Requirement already satisfied, skipping upgrade: pandocfilters>=1.4.1 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (1.4.2)
    Requirement already satisfied, skipping upgrade: mistune<2,>=0.8.1 in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (0.8.4)
    Requirement already satisfied, skipping upgrade: pywinpty>=0.5; os_name == "nt" in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from terminado>=0.8.1->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (0.5.7)
    Requirement already satisfied, skipping upgrade: pycparser in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from cffi!=1.11.3,>=1.8->cryptography>=1.3->requests-ntlm>=1.1.0->qiskit-ibmq-provider==0.7.0->qiskit==0.19->-r grading_tools/requirements.txt (line 1)) (2.20)
    Requirement already satisfied, skipping upgrade: packaging in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from bleach->nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (20.4)
    Requirement already satisfied, skipping upgrade: webencodings in c:\users\codie\appdata\local\programs\python\python37\lib\site-packages (from bleach->nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets==7.5.1->-r grading_tools/requirements.txt (line 3)) (0.5.1)

# Single-qubit states

In lecture, you learned that single qubit states can be written down generally as

$$\sqrt{1-p}\vert0\rangle + e^{i\phi}\sqrt{p}\vert1\rangle$$

Here, $p$ is the probability that a measurement of the state in the computational basis $\{\vert0\rangle, \vert1\rangle\}$ will have the outcome $1$, and $\phi$ is the phase between the two computational basis states.

Single-qubit gates can then be used to manipulate this quantum state by changing either $p$, $\phi$, or both.

Let's begin by creating a single-qubit quantum circuit. We can do this in `Qiskit` using the following:

```python
from qiskit import QuantumCircuit

mycircuit = QuantumCircuit(1)
mycircuit.draw('mpl')
```

The above quantum circuit does not contain any gates. Therefore, if you start in any state, say $\vert0\rangle$, applying this circuit to your state doesn't change the state.

To see this clearly, let's create the statevector $\vert0\rangle$. In `Qiskit`, you can do this using the following:

```python
from qiskit.quantum_info import Statevector

sv = Statevector.from_label('0')
```

You can see what's contained in the object `sv`:

```python
sv
```

    Statevector([1.+0.j, 0.+0.j],
                dims=(2,))

The vector itself can be found by writing

```python
sv.data
```

    array([1.+0.j, 0.+0.j])

As you can see, the above matches what you learned in lecture. Recall that $$\vert0\rangle = \begin{bmatrix}1\\0\end{bmatrix}$$

We can now apply the quantum circuit `mycircuit` to this state by using the following:

```python
new_sv = sv.evolve(mycircuit)
```

Once again, you can look at the new statevector by writing

```python
new_sv
```

    Statevector([1.+0.j, 0.+0.j],
                dims=(2,))

As you can see, the statevector hasn't changed. Recall the concept of state projection that you learned in lecture. You can compute the projection of `new_sv` onto `sv` by writing

```python
from qiskit.quantum_info import state_fidelity

state_fidelity(sv, new_sv)
```

    1.0

As you can see, the projection of `new_sv` onto `sv` is 1, indicating that the two states are identical. You can visualize this state using the `qsphere` by writing

```python
from qiskit.visualization import plot_state_qsphere

plot_state_qsphere(sv.data)
```

As you learned in lecture 1, applying an $X$ gate flips the qubit from the state $\vert0\rangle$ to the state $\vert1\rangle$. To see this clearly, we will first create a single-qubit quantum circuit with the $X$ gate.

```python
mycircuit = QuantumCircuit(1)
mycircuit.x(0)

mycircuit.draw('mpl')
```

Now, we can apply this circuit onto our state by writing

```python
sv = Statevector.from_label('0')
new_sv = sv.evolve(mycircuit)
new_sv
```

    Statevector([0.+0.j, 1.+0.j],
                dims=(2,))

As you can see, the statevector now corresponds to that of the state $\vert1\rangle$. Recall that

$$\vert1\rangle = \begin{bmatrix}0\\1\end{bmatrix}$$

Now, the projection of `new_sv` onto `sv` is

```python
state_fidelity(new_sv, sv)
```

    0.0

This is not surprising. Recall from the lecture that the states $\vert0\rangle$ and $\vert1\rangle$ are orthogonal. Therefore, $\langle0\vert1\rangle = 0$. The state can be shown on the `qsphere` by writing

```python
plot_state_qsphere(new_sv.data)
```

Similarly, we can create the state $$\frac{1}{\sqrt{2}}\left(\vert0\rangle + \vert1\rangle\right)$$
by applying a Hadamard gate as you learned in lecture. Here is how we can create the state and visualize it in `Qiskit`:

```python
sv = Statevector.from_label('0')
mycircuit = QuantumCircuit(1)
mycircuit.h(0)
mycircuit.draw('mpl')
```

```python
new_sv = sv.evolve(mycircuit)
print(new_sv)
plot_state_qsphere(new_sv.data)
```

As you can see above, the state has equal components of $\vert0\rangle$ and $\vert1\rangle$. The size of the circle is proportional to the probability of measuring each basis state in the statevector. As a result, you can see that the size of the circles is half of the size of the circles in our previous visualizations.

Recall from lecture that we can also create other superpositions with different phase. Let's create $$\frac{1}{\sqrt{2}}\left(\vert0\rangle - \vert1\rangle\right)$$ which can be done by applying the Hadamard gate on the state $\vert1\rangle$.

```python
sv = Statevector.from_label('1')
mycircuit = QuantumCircuit(1)
mycircuit.h(0)

new_sv = sv.evolve(mycircuit)
print(new_sv)
plot_state_qsphere(new_sv.data)
```

This time, the bottom circle, corresponding to the basis state $\vert1\rangle$ has a different color corresponding to the phase of $\phi = \pi$. This is because the coefficient of $\vert1\rangle$ in the state $$\frac{1}{\sqrt{2}}\left(\vert0\rangle - \vert1\rangle\right)$$ is $-1$, which is equal to $e^{i\pi}$.

Other phases can also be created by applying different gates. The $T$ and $S$ gates apply phases of $+\pi/4$ and $+\pi/2$, respectively. The widget below helps you see different gates, and their actions on single-qubit quantum states.

```python
from resources.qiskit_textbook.widgets import gate_demo
gate_demo(qsphere=True)
```

    VBox(children=(HBox(children=(Button(description='I', layout=Layout(height='3em', width='3em'), style=ButtonSt…

    Image(value=b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x01\xf8\x00\x00\x01\xf8\x08\x06\x00\x00\x00\xa6(\xff…

A summary of the operations of the most common gates on single-qubit states is given by the handy image below, where the phases are shown in degrees.

# Multi-qubit states

Similar to the discussion above, you can also explore multi-qubit gates in `Qiskit`. In lecture, you learned about Bell states, and how they can be generated using quantum gates. We will demonstrate below how to create the Bell state $$\frac{1}{\sqrt{2}}\left(\vert00\rangle + \vert11\rangle\right)$$ from the state $\vert00\rangle$. We'll start by visualizing the state $\vert00\rangle$ using the same procedure:

```python
sv = Statevector.from_label('00')
plot_state_qsphere(sv.data)
```

Next, we use the Hadamard gate described above, along with a controlled-X gate, to create the Bell state.

```python
mycircuit = QuantumCircuit(2)
mycircuit.h(0)
mycircuit.cx(0,1)
mycircuit.draw('mpl')
```

The result of this quantum circuit on the state $\vert00\rangle$ is found by writing

```python
new_sv = sv.evolve(mycircuit)
print(new_sv)
plot_state_qsphere(new_sv.data)
```

Note how this looks very similar to a single-qubit superposition with zero phase. Following entanglement, it is no longer possible to treat the two qubits individually, and they must be considered to be one system.

To see this clearly, we can see what would happen if we measured the Bell state above 1000 times.

```python
counts = new_sv.sample_counts(shots=1000)

from qiskit.visualization import plot_histogram
plot_histogram(counts)
```

As you can see above, all measurements give either the result `00` or `11`. In other words, if the measurement outcome for one of the qubits is known, then the outcome for the other is fully determined.

### Ungraded exercise 1

Can you create the state $$\frac{1}{\sqrt{2}}\left(\vert01\rangle + \vert10\rangle\right)$$ using a similar procedure?

### Ungraded exercise 2

Can you create the state $$\frac{1}{\sqrt{2}}\left(\vert01\rangle - \vert10\rangle\right)$$ using a similar procedure?

# Measurements

In the above example, we simulated the action of a measurement by sampling counts from the statevector. A measurement can explicitly be inserted into a quantum circuit as well. Here is an example that creates the same Bell state and applies a measurement.

```python
mycircuit = QuantumCircuit(2, 2)
mycircuit.h(0)
mycircuit.cx(0,1)
mycircuit.measure([0,1], [0,1])
mycircuit.draw('mpl')
```

Two new features appeared in the circuit compared to our previous examples.

- First, note that we used a second argument in the `QuantumCircuit(2,2)` command. The second argument says that we will be creating a quantum circuit that contains two qubits (the first argument), and two classical bits (the second argument).
- Second, note that the `measure` command takes two arguments. The first argument is the set of qubits that will be measured. The second is the set of classical bits onto which the outcomes from the measurements of the qubits will be stored.

Since the above quantum circuit contains non-unitaries (the measurement gates), we will use `Qiskit`'s built-in `Aer` simulators to run the circuit. To get the measurement counts, we can use the following code:

```python
from qiskit import Aer, execute
simulator = Aer.get_backend('qasm_simulator')
result = execute(mycircuit, simulator, shots=10000).result()
counts = result.get_counts(mycircuit)
plot_histogram(counts)
```

As you can see, the measurement outcomes are similar to when we sampled counts from the statevector itself.

# Graded exercise 1: Quantum teleportation

In this graded exercise, you will teleport the quantum state
$$\sqrt{0.70}\vert0\rangle + \sqrt{0.30}\vert1\rangle$$ from Alice's qubit to Bob's qubit. Recall that the teleportation algorithm consists of four major components:

1. Initializing the state to be teleported. We will do this on Alice's qubit `q0`.
2. Creating entanglement between two qubits. We will use qubits `q1` and `q2` for this. Recall that Alice owns `q1`, and Bob owns `q2`.
3. Applying a Bell measurement on Alice's qubits `q0` and `q1`.
4. Applying classically controlled operations on Bob's qubit `q2` depending on the outcomes of the Bell measurement on Alice's qubits.

This exercise guides you through each of these steps.

### Initializing the state to be teleported

First, create a quantum circuit that creates the state $$\sqrt{0.70}\vert0\rangle + \sqrt{0.30}\vert1\rangle$$ You can do this by using `Qiskit`'s `initialize` function.

```python
import math
def initialize_qubit(given_circuit, qubit_index):

    import numpy as np
    ### WRITE YOUR CODE BETWEEN THESE LINES - START
    initial_vec = [math.sqrt(0.7),math.sqrt(0.3)]
    given_circuit.initialize(initial_vec,qubit_index)
    #given_circuit.u3(11 * np.pi / 30, 0, 0, qubit_index)
    ### WRITE YOUR CODE BETWEEN THESE LINES - END

    return given_circuit
```

Next, we need to create entanglement between Alice's and Bob's qubits.

```python
def entangle_qubits(given_circuit, qubit_Alice, qubit_Bob):

    ### WRITE YOUR CODE BETWEEN THESE LINES - START

    given_circuit.h(qubit_Alice)
    given_circuit.cx(qubit_Alice,qubit_Bob)
    ### WRITE YOUR CODE BETWEEN THESE LINES - END

    return given_circuit
```

Next, we need to do a Bell measurement of Alice's qubits.

```python
def bell_meas_Alice_qubits(given_circuit, qubit1_Alice, qubit2_Alice, clbit1_Alice, clbit2_Alice):

    ### WRITE YOUR CODE BETWEEN THESE LINES - START

    given_circuit.cx(qubit1_Alice,qubit2_Alice)
    given_circuit.h(qubit1_Alice)
    given_circuit.measure(qubit1_Alice, clbit1_Alice)
    given_circuit.measure(qubit2_Alice, clbit2_Alice)
    #given_circuit.measure([qubit1_Alice,qubit2_Alice], [qubit2_Alice,clbit2_Alice])

    ### WRITE YOUR CODE BETWEEN THESE LINES - END

    return given_circuit
```

Finally, we apply controlled operations on Bob's qubit. Recall that the controlled operations are applied in this order:

- an $X$ gate is applied on Bob's qubit if the measurement coutcome of Alice's second qubit, `clbit2_Alice`, is `1`.
- a $Z$ gate is applied on Bob's qubit if the measurement coutcome of Alice's first qubit, `clbit1_Alice`, is `1`.

```python
def controlled_ops_Bob_qubit(given_circuit, qubit_Bob, clbit1_Alice, clbit2_Alice):

    ### WRITE YOUR CODE BETWEEN THESE LINES - START

    given_circuit.x(qubit_Bob).c_if(clbit2_Alice, 1)
    given_circuit.z(qubit_Bob).c_if(clbit1_Alice, 1)

    ### WRITE YOUR CODE BETWEEN THESE LINES - END

    return given_circuit
```

The next lines of code put everything together. **You do not need to modify anything below, but you will need to run the cell to submit your solution.**

```python
### imports
from qiskit import QuantumRegister, ClassicalRegister

### set up the qubits and classical bits
all_qubits_Alice = QuantumRegister(2)
all_qubits_Bob = QuantumRegister(1)
creg1_Alice = ClassicalRegister(1)
creg2_Alice = ClassicalRegister(1)

### quantum teleportation circuit here
# Initialize
mycircuit = QuantumCircuit(all_qubits_Alice, all_qubits_Bob, creg1_Alice, creg2_Alice)
initialize_qubit(mycircuit, 0)
mycircuit.barrier()
# Entangle
entangle_qubits(mycircuit, 1, 2)
mycircuit.barrier()
# Do a Bell measurement
bell_meas_Alice_qubits(mycircuit, all_qubits_Alice[0], all_qubits_Alice[1], creg1_Alice, creg2_Alice)
mycircuit.barrier()
# Apply classically controlled quantum gates
controlled_ops_Bob_qubit(mycircuit, all_qubits_Bob[0], creg1_Alice, creg2_Alice)

### Look at the complete circuit
print(mycircuit.draw(output='text'))

### store the circuit as the submitted answer
answer = mycircuit
```

          ┌─────────────────────────────┐ ░            ░      ┌───┐┌─┐ ░        »
    q0_0: ┤ initialize(0.83666,0.54772) ├─░────────────░───■──┤ H ├┤M├─░────────»
          └─────────────────────────────┘ ░ ┌───┐      ░ ┌─┴─┐└┬─┬┘└╥┘ ░        »
    q0_1: ────────────────────────────────░─┤ H ├──■───░─┤ X ├─┤M├──╫──░────────»
                                          ░ └───┘┌─┴─┐ ░ └───┘ └╥┘  ║  ░  ┌───┐ »
    q1_0: ────────────────────────────────░──────┤ X ├─░────────╫───╫──░──┤ X ├─»
                                          ░      └───┘ ░        ║   ║  ░  └─┬─┘ »
    c0_0: ══════════════════════════════════════════════════════╬═══╩═══════╪═══»
                                                                ║        ┌──┴──┐»
    c1_0: ══════════════════════════════════════════════════════╩════════╡ = 1 ╞»
                                                                         └─────┘»
    «
    «q0_0: ───────
    «
    «q0_1: ───────
    «       ┌───┐
    «q1_0: ─┤ Z ├─
    «       └─┬─┘
    «      ┌──┴──┐
    «c0_0: ╡ = 1 ╞
    «      └─────┘
    «c1_0: ═══════
    «

Then, grade your solution by running the cell below. Provide always the same name and email, as the one you wrote during the course sign up.

```python
name = 'Rohit Prasad'
email = 'rohitprasad231@gmail.com'

from grading_tools import grade
grade(answer, name, email, 'lab1', 'ex1')
```

    lab1/ex1 - 🎉  Correct

# Additional reading

- You can watch a video on building the quantum teleportation quantum circuit here: https://www.youtube.com/watch?v=mMwovHK2NrE&list=PLOFEBzvs-Vvp2xg9-POLJhQwtVktlYGbY&index=6&t=0s

- For additional details about the quantum teleportation algorithm, including the principle of deferred measurement, you can refer to the Qiskit Textbook's section on the algorithm here: https://qiskit.org/textbook/ch-algorithms/teleportation.html

- The `1 minute Qiskit` episode entitled `What is the qsphere?` succinctly describes the Qsphere visualization tool that we used in this lab. You can find it here: https://youtu.be/4SoK2h4a7us


# Managing Complexity with BondGraphTools

https://github.com/peter-cudmore/seminars/CellML-2019

    Dr. Peter Cudmore.
    Systems Biology Labratory,
    The School of Chemical and Biomedical Engineering,
    The University of Melbourne.

```python
## Make sympy print pretty text
import sympy as sp
sp.init_printing()

# Load the examples
from examples import *

# Import the source-code inspector
from inspect import getsourcelines

# Start the julia interpreter
from BondGraphTools.config import config
_ = config.start_julia()

# Parameters from Safaei et.al. 2018
blood = Fluid(density=0.004, viscosity=1050)

# Approximate parameters for 10cm worth of artery.
artery = Vessel(radius=0.03, thickness=0.005, youngs_modulus=0.16e6, length=0.1)

```

## The problem with big systems is that they're _big_...

<center>  </center>

## Complex Physical Systems

A _complex physical system_ has:
* many parts or subsystems (High-dimensional).
* subsystems which are not all of the same (Heterogenenous).
* subsystems which are complicated (Nonlinear and/or Noisy).
* well defined boundaries between the subsystems (Network Topology).
* **subsystems interact via resource exchange (Conservation Laws).**

Examples include: Biochemical Networks, Ecosystems, Electrical Grids, Hydraulic networks, etc.

## Some Obvious Questions

Human Metabolism Map @ https://www.vmh.life
<center>  </center>

1. Why?
2. Where do we get the topology from?
3. What are the dynamic features?
4. How do we paramaterise them?
5. What is a useful representation?
6. How do we manipulate and refine our model?
7. How should one manage complexity at scale?

## Why?

To predict, understand and control systemic phenomenon such as emergence, multiscale dynamics and long-range interactions.

To _rationally engineer_ systems in general and biological systems in particular.

##  Where do we get network data?

For Systems Biology:
- Databases (Brenda, KEGG, BIGG, SABIO-RK, reactome)
- Model Repositories (Physiome Project, BioModels)
- Publications (supp. materials, images, tables)
- Collaborators.

More generally: connectivity maps.

## A Subtle Issue: Dynamics.

Recall that Complex Physical Systems have a _network topology_ of _conservative interactions_.

- As edges are 'resource exchange',
- _effort_ must be imposed to move resources from one node to another,
- which move at some corresponding _flow_ rate.
- Nodes must either store resources, or conservatively pass them along.
- The exceptions are the boundary conditions such as resource sources and sinks (including dissipation).

## A Major Issue: Parameterisation.

Ideally we would use parameters that:
- are physically meaningful,
- are able to be theoretically estimated,
- can be derived from underlying physics/chemistry,
- or that have been shown to be consistent across many experiemental conditions.
- and hence tabulated (or able to be derived from tablated data)

(but this is easier said than done)

## The Relevant Questions for Today.

- What is a useful representation of a complex physical system?
- What is a good way to manipulate models?
- How do we manage complexity and scale?

_Object Oriented Modelling via_ `BondGraphTools`.

## 'Energetic Systems' as an Object Oriented Programming.

Object Oriented Programming (OOP) is a software development paradigm that seeks to manage large, complicated projects by breaking problems into _data_ plus _methods_ that act on the data.

Three big ideas in OOP are:
1. _Inheritance_ or is-a relationships.
2. _Composition_ or has-a relationships.
3. _Encapsulation_ or infomation hiding.

This allows for _hierarchical_ and _modular_ design which reduces model complexity.

```python
import BondGraphTools
help(BondGraphTools)
```

    Help on package BondGraphTools:

    NAME
        BondGraphTools

    DESCRIPTION
        BondGraphTools
        ==============
        BondGraphTools is a python library for symbolic modelling
        of energetic systems.

        Package Documentation::

            https://bondgraphtools.readthedocs.io/

        Source::

            https://github.com/BondGraphTools/BondGraphTools

        Bug reports:

            https://github.com/BondGraphTools/BondGraphTools/issues

        Simple Example
        --------------

        Build and simulate a RLC driven RLC circuit::

            import BondGraphTools as bgt

            # Create a new model
            model = bgt.new(name="RLC")

            # Create components
            # 1 Ohm Resistor
            resistor = bgt.new("R", name="R1", value=1.0)

            # 1 Henry Inductor
            inductor = bgt.new("L", name="L1", value=1.0)
            # 1 Farad Capacitor
            capacitor = bgt.new("C", name="C1", value=1.0)
            # Conservation Law
            law = bgt.new("0") # Common voltage conservation law

            # Connect the components
            connect(law, resistor)
            connect(law, capacitor)
            connect(law, inductor)

            # produce timeseries data
            t, x = simulate(model, x0=[1,1], timespan=[0, 10])

        Bugs
        ----

        Please report any bugs `here <https://github.com/BondGraphTools/BondGraphTools/issues>`_,
        or fork the repository and submit a pull request.

        License
        -------
        Released under the Apache 2.0 License::

            Copyright (C) 2018
            Peter Cudmore <peter.cudmore@uqconnect.edu.au>

    PACKAGE CONTENTS
        actions
        algebra
        atomic
        base
        component_manager
        compound
        config
        exceptions
        fileio
        port_hamiltonian
        reaction_builder
        sim_tools
        version
        view

    DATA
        version = '0.3.7'

    FILE
        /Users/pete/Workspace/BondGraphTools/BondGraphTools/__init__.py

### Bond Graphs, Port Hamiltonians and BondGraphTools

_Bond graphs_ are a **graphical** framework for modelling energetic systems.

_Port Hamiltonians_ are a **geometric** framework for modelling energetic systems.

_BondGraphTools_ is a **programmatic** framework for modelling energetic systems.

## Goals of this talk.

In the remaining time i hope to convince you that:
- Object oriented modelling is suited to complex physical systems.
- `BondGraphTools` is a useful library for this purpose.
- Incorporating scripting into your work is worthwhile.
-  `BondGraphTools` and `libCellML`

# Object Oriented Modelling for Energetic Systems

Inheritance, Composition and Encapsulation

## Inheritance

For networked systems, _inheritance_ means that for each node or subsystems have:
- conditions on the interals.
- a description of the interface.

## Inheritance

### Nodes are particular _energetic systems_
Each node is described by a set of differential-algebraic equations; the constitutive relations

$$\Phi(\dot{x},x,e,f) = 0.$$

## Inheritance

### Edges are constraints on port variables.

An edge represents how state is shared between systems.

## Inheritance

#### Example Node Subclasses:
- Resistive dissipation.
- Elastic defomation of vessel walls.
- Conservation of mass.

_This_ chemical reation or _that particular_ aeortic compliance are **instances** of a particular subclass.

## Anatomy of an Energetic System

Nodes can have _state_, represented by the variables $(\dot{x}, x)$

Examples with state:
- Charge accumulation.
- Chemical concentration.
- Elastic deformation.

## Anatomy of an Energetic System

Nodes can alternatively be stateless.

Examples without state:
- resistance / friction
- semiconductance
- elementary chemical reactions

## Anatomy of an Energetic System

Nodes can have _external ports_ (here labeled $[1]$ , $[2]$ and $[3]$) which provide an interface to the external environment.

Examples of ports:
- The poles of a dielectic membrane
- The open end of a vessel segment.
- The enzyme/substrate/cofactor mix of a biochemical reaction.

## Anatomy of an Energetic System

$\Phi$ relates _internal state_ to _external environment_.

The relation $\Phi$ may have parameters such as:
- Temperature and pressure
- Gibbs formation energy
- Vessel wall compliance
- Electrical resistance

## Composition

_Composition_ means that we can replace subgraphs with a single node and vice-versa.

_This means we both abstract parts of the model, or refine parts of the model as necessary!_

## Composition

Recall that each node is a set of DAE's
$$\Phi_j(\dot{x},x,e,f) = 0.$$

One can simply take the direct sum of the systems to produce a composite system

$$
\Phi_0 = \left(
\Phi_6,
\Phi_7,\Phi_8,
\Phi_{edges}\right)^T = 0
$$

## Compostion

For
$$
\Phi_0 = \left(
\Phi_6,
\Phi_7, \Phi_8
\Phi_{edges}\right)^T = 0
$$
the relation
$$\Phi_{edges} = (e^i_\alpha - e^j_\beta, f^i_\alpha + f^j_\beta,\ldots)$$
turns edges between node-ports pairs $(i,\alpha)$ and $(j,\beta)$ into constraints upon the composed system $\Phi_0$.

## Compositon

_Like joining pipe segments!_
- $e^i_\alpha - e^j_\beta = 0$ implies 'pressure'(effort) is identical at the join.
- $f^i_\alpha + f^j_\beta = 0$ implies the flow goes losslessly from one, to the other.

## Encapsulation

Encapsulation = Modularity!

- Model Sharing.
- Scalablity!

## Encapsulation

Encapsulation allows Model Comparison.

- In-place model swaps.
- Model re-use.

## Object Oriented Modelling and Energetic Systems

Energetic systems provide:
- _Inheritance_; an abstract base representation of energetic systems.
- _Composition_; a way to hierarchically compose systems of systems.
- _Encapsulation_; a framework inside which simplifications can occur.

# `BondGraphTools`

Modelling Object Oriented Physical System

## Energetic Modelling as Object Oriented Programming.

`BondGraphTools` provides the infrastructure to
- Represent complex physical systems as object oriented python code.
- Manipulate and organise models of complex phyiscal systems programmitcally.
- Algorithmically simplify the resulting models.

## What `BondGraphTools` is good for

(and why you should use it, or pinch ideas from it)

- automated model reduciton
- scripted model building
- formal (code) modelling of systems.
- tool integration

```python
from BondGraphTools import draw
segment1 = VesselSegmentA(
    "Example_1", artery, blood
)
draw(segment1)
```

```python
source, _  = getsourcelines(VesselSegmentA)
for line in source:
    print(line[:-1])
```

    class VesselSegmentA(bgt.BondGraph):
        """A vascular vessel segment.

        This class is an example of Vessel Segment A from:
        Safaei, Sorous. Blanco, Pablo J. Müller, Lucas O. Hellevik, Leif R. and Hunter, Peter J.
        Bond Graph Model of Cerebral Circulation: Toward Clinically Feasible Systemic Blood Flow Simulations
        Frontiers in Physiology, 2018, volume 9, page 148

        The vessel segment is of the $uv$ type that has components:
            - pressure inlet $u_i$
            - flow outlet $v_o$
            - fluid interia $I$
            - wall dissipation $R$
            - and compliance $C$.

        The linear resistance, compliance and inertance are computed as per Safaei et.al..

        See Also: BondGraph
        """

        def __init__(self, name, vessel, fluid):
            """
            Args:
                name (str):      The name of this vessel segement
                vessel (Vessel): The vessel material properties
                fluid (Fluid):   The fluid properties
            """
            # Parameters
            resistance = 8 * fluid.viscosity * vessel.length / (pi * vessel.radius**4)
            inertance = 2 * pi * vessel.radius**3 / (vessel.thickness * vessel.youngs_modulus)
            compliance = fluid.density * vessel.length / (pi* vessel.radius**2)

            # Instantiating Components
            R_component = bgt.new('R', value=resistance, name=f'R')
            C_component = bgt.new('C', value=compliance, name=f'C')
            I_component = bgt.new('I', value=inertance, name=f'I')

            conserved_flow = bgt.new("1", name=f'1')
            conserved_pressure = bgt.new("0", name=f'0')

            u_in = bgt.new('SS', name=f'u_i')
            v_out = bgt.new('SS', name=f'v_o')

            bonds = [
                (u_in, conserved_flow),
                (conserved_flow, R_component),
                (conserved_flow, I_component),
                (conserved_flow, conserved_pressure),
                (conserved_pressure, C_component),
                (conserved_pressure, v_out)
            ]

            # Build the BondGraph via the inherited initialise function
            super().__init__(
                name=name,
                components=(R_component, C_component, I_component, conserved_flow, conserved_pressure, u_in, v_out)
            )

            # wire it up
            for bond in bonds:
                bgt.connect(*bond)

            # expose the ports
            bgt.expose(u_in, label="u_i")
            bgt.expose(v_out, label="v_o")

## Scripting the construction of an artery model

```python
from BondGraphTools import new, add, connect
length = 1
current_length = 0
segment_counter = 0

artery_model = new()
inlet = new('Se', name='inlet', label='u_i')
add(artery_model, inlet)

outlet = bgt.new('Sf', name='outlet', label='v_o')
add(artery_model, outlet)
last_outlet = inlet

```

```python
while current_length < length:
    # Add a new segment
    this_segment = VesselSegmentA(
        name=f"Segment_{{{segment_counter}}}",
        vessel=artery, fluid=blood)
    add(artery_model, this_segment)
    current_inlet_port = (this_segment, 'u_i')

    # and connect it to the previous one
    connect(last_outlet, current_inlet_port)

    # Update the counter variables
    last_outlet = (this_segment, 'v_o')
    current_length = current_length + artery.length
    segment_counter = segment_counter + 1

connect(last_outlet, outlet)
```

## Automatically Generating Equations

```python
artery_model.constitutive_relations
```

## Algorithmic Substitution

```python
from BondGraphTools import (
    BondGraph, expose, new, connect)

class Voigt_Model(BondGraph):
    def __init__(self, name,
                 compliance, dissipation):
        # ------ Define the Subcomponents
        C = new("C", name='C', value=compliance)
        R = new("R", name='R',value=dissipation)
        law = new('1')
        port = new("SS", name='SS')
        # ------ Build the model
        super().__init__(name=name,
            components=(C, R, law, port)
        )
        # ------ Wire it up
        connect(port, law)
        connect(law, R)
        connect(law, C)
        # ----- Expose the port
        expose(port, label="C_v")
```

```python
from BondGraphTools import swap
# simple iterator function
def next_segment(model):
    i = 0
    try:
        while True:
            yield model / f"Segment_{{{i}}}"
            i += 1
    except ValueError:
        return StopIteration

# swap the components out for each segment
for segment in next_segment(artery_model):
    C = segment / "C"
    C_v = Voigt_Model('C_v',
                      C.params['C'],
                      0.001)

    swap(C, C_v)
```

```python
print_tree(artery_model)
```

    BG: BG1
    |-BG: Segment_{10}
    |--BG: C_v
    |---SS: SS
    |---1: 124
    |---R: R
    |---C: C
    |--SS: v_o
    |--SS: u_i
    |--0: 0
    |--1: 1
    |--I: I
    |--R: R
    |-BG: Segment_{9}
    |--BG: C_v
    |---SS: SS
    |---1: 123
    |---R: R
    |---C: C
    |--SS: v_o
    |--SS: u_i
    |--0: 0
    |--1: 1
    |--I: I
    |--R: R
    |-BG: Segment_{8}
    |--BG: C_v
    |---SS: SS
    |---1: 122
    |---R: R
    |---C: C
    |--SS: v_o
    |--SS: u_i
    |--0: 0
    |--1: 1
    |--I: I
    |--R: R
    |-BG: Segment_{7}
    |--BG: C_v
    |---SS: SS
    |---1: 121
    |---R: R
    |---C: C
    |--SS: v_o
    |--SS: u_i
    |--0: 0
    |--1: 1
    |--I: I
    |--R: R
    |-BG: Segment_{6}
    |--BG: C_v
    |---SS: SS
    |---1: 120
    |---R: R
    |---C: C
    |--SS: v_o
    |--SS: u_i
    |--0: 0
    |--1: 1
    |--I: I
    |--R: R
    |-BG: Segment_{5}
    |--BG: C_v
    |---SS: SS
    |---1: 119
    |---R: R
    |---C: C
    |--SS: v_o
    |--SS: u_i
    |--0: 0
    |--1: 1
    |--I: I
    |--R: R
    |-BG: Segment_{4}
    |--BG: C_v
    |---SS: SS
    |---1: 118
    |---R: R
    |---C: C
    |--SS: v_o
    |--SS: u_i
    |--0: 0
    |--1: 1
    |--I: I
    |--R: R
    |-BG: Segment_{3}
    |--BG: C_v
    |---SS: SS
    |---1: 117
    |---R: R
    |---C: C
    |--SS: v_o
    |--SS: u_i
    |--0: 0
    |--1: 1
    |--I: I
    |--R: R
    |-BG: Segment_{2}
    |--BG: C_v
    |---SS: SS
    |---1: 116
    |---R: R
    |---C: C
    |--SS: v_o
    |--SS: u_i
    |--0: 0
    |--1: 1
    |--I: I
    |--R: R
    |-BG: Segment_{1}
    |--BG: C_v
    |---SS: SS
    |---1: 115
    |---R: R
    |---C: C
    |--SS: v_o
    |--SS: u_i
    |--0: 0
    |--1: 1
    |--I: I
    |--R: R
    |-BG: Segment_{0}
    |--BG: C_v
    |---SS: SS
    |---1: 114
    |---R: R
    |---C: C
    |--SS: v_o
    |--SS: u_i
    |--0: 0
    |--1: 1
    |--I: I
    |--R: R
    |-SS: outlet
    |-SS: inlet

## Automated Model Building

```python
TCA_reactions = {
    "Citrate synthase":
        ["acetyl-CoA + oxaloacetate + H2O = citrate + CoA-SH"],
    "Aconitase":
        ["Citrate = cis-Aconitate + H2O", "cis-Aconitate + H2O = Isocitrate"],
    "Isocitrate dehydrogenase":
        ["Isocitrate + NAD = Oxalosuccinate + NADH + H",
         "Oxalosuccinate = a-Ketoglutarate + CO2" ],
    "a-Ketoglutarate dehydrogenase":
        ["a-Ketoglutarate + NAD + CoA-SH = Succinyl-CoA + NADH + H + CO2"],
     "Succinyl-CoA synthetase":
        ["Succinyl-CoA + ADP + Pi = Succinate + CoA-SH + ATP"],
     "Succinate dehydrogenase":
        ["Succinate + Q = Fumarate + QH2"],
     "Fumarase":
        ["Fumarate + H2O = L-Malate"],
     "Malate dehydrogenase":
        ["L-Malate + NAD = Oxaloacetate + NADH + H"]
}
```

```python
from BondGraphTools.reaction_builder import (
    Reaction_Network)

def TCA_Cycle():
    reaction_net = Reaction_Network(
        name="TCA_Cycle"
    )
    # loop through each enzyme
    for enzyme in TCA_reactions:
        for i, reaction in enumerate(TCA_reactions[enzyme]):
            # add each reaction.
            reaction_net.add_reaction(
                reaction,
                name=f"{enzyme} - {i}"
            )
    return reaction_net
```

```python
from BondGraphTools import draw
tca_model = TCA_Cycle().as_network_model()
draw(tca_model)
```

## ...from data to equations

```python
tca_model.constitutive_relations
```

```python
# Parameters
tca_model.params
```

    {0: (C: acetyl-CoA, 'k'),
     1: (C: acetyl-CoA, 'R'),
     2: (C: acetyl-CoA, 'T'),
     3: (C: oxaloacetate, 'k'),
     4: (C: oxaloacetate, 'R'),
     5: (C: oxaloacetate, 'T'),
     6: (C: H2O, 'k'),
     7: (C: H2O, 'R'),
     8: (C: H2O, 'T'),
     9: (C: citrate, 'k'),
     10: (C: citrate, 'R'),
     11: (C: citrate, 'T'),
     12: (C: CoA-SH, 'k'),
     13: (C: CoA-SH, 'R'),
     14: (C: CoA-SH, 'T'),
     15: (C: Citrate, 'k'),
     16: (C: Citrate, 'R'),
     17: (C: Citrate, 'T'),
     18: (C: cis-Aconitate, 'k'),
     19: (C: cis-Aconitate, 'R'),
     20: (C: cis-Aconitate, 'T'),
     21: (C: Isocitrate, 'k'),
     22: (C: Isocitrate, 'R'),
     23: (C: Isocitrate, 'T'),
     24: (C: NAD, 'k'),
     25: (C: NAD, 'R'),
     26: (C: NAD, 'T'),
     27: (C: Oxalosuccinate, 'k'),
     28: (C: Oxalosuccinate, 'R'),
     29: (C: Oxalosuccinate, 'T'),
     30: (C: NADH, 'k'),
     31: (C: NADH, 'R'),
     32: (C: NADH, 'T'),
     33: (C: H, 'k'),
     34: (C: H, 'R'),
     35: (C: H, 'T'),
     36: (C: a-Ketoglutarate, 'k'),
     37: (C: a-Ketoglutarate, 'R'),
     38: (C: a-Ketoglutarate, 'T'),
     39: (C: CO2, 'k'),
     40: (C: CO2, 'R'),
     41: (C: CO2, 'T'),
     42: (C: Succinyl-CoA, 'k'),
     43: (C: Succinyl-CoA, 'R'),
     44: (C: Succinyl-CoA, 'T'),
     45: (C: ADP, 'k'),
     46: (C: ADP, 'R'),
     47: (C: ADP, 'T'),
     48: (C: Pi, 'k'),
     49: (C: Pi, 'R'),
     50: (C: Pi, 'T'),
     51: (C: Succinate, 'k'),
     52: (C: Succinate, 'R'),
     53: (C: Succinate, 'T'),
     54: (C: ATP, 'k'),
     55: (C: ATP, 'R'),
     56: (C: ATP, 'T'),
     57: (C: Q, 'k'),
     58: (C: Q, 'R'),
     59: (C: Q, 'T'),
     60: (C: Fumarate, 'k'),
     61: (C: Fumarate, 'R'),
     62: (C: Fumarate, 'T'),
     63: (C: QH2, 'k'),
     64: (C: QH2, 'R'),
     65: (C: QH2, 'T'),
     66: (C: L-Malate, 'k'),
     67: (C: L-Malate, 'R'),
     68: (C: L-Malate, 'T'),
     69: (C: Oxaloacetate, 'k'),
     70: (C: Oxaloacetate, 'R'),
     71: (C: Oxaloacetate, 'T'),
     72: (R: Citrate synthase - 0, 'r'),
     73: (R: Citrate synthase - 0, 'R'),
     74: (R: Citrate synthase - 0, 'T'),
     75: (R: Aconitase - 0, 'r'),
     76: (R: Aconitase - 0, 'R'),
     77: (R: Aconitase - 0, 'T'),
     78: (R: Aconitase - 1, 'r'),
     79: (R: Aconitase - 1, 'R'),
     80: (R: Aconitase - 1, 'T'),
     81: (R: Isocitrate dehydrogenase - 0, 'r'),
     82: (R: Isocitrate dehydrogenase - 0, 'R'),
     83: (R: Isocitrate dehydrogenase - 0, 'T'),
     84: (R: Isocitrate dehydrogenase - 1, 'r'),
     85: (R: Isocitrate dehydrogenase - 1, 'R'),
     86: (R: Isocitrate dehydrogenase - 1, 'T'),
     87: (R: a-Ketoglutarate dehydrogenase - 0, 'r'),
     88: (R: a-Ketoglutarate dehydrogenase - 0, 'R'),
     89: (R: a-Ketoglutarate dehydrogenase - 0, 'T'),
     90: (R: Succinyl-CoA synthetase - 0, 'r'),
     91: (R: Succinyl-CoA synthetase - 0, 'R'),
     92: (R: Succinyl-CoA synthetase - 0, 'T'),
     93: (R: Succinate dehydrogenase - 0, 'r'),
     94: (R: Succinate dehydrogenase - 0, 'R'),
     95: (R: Succinate dehydrogenase - 0, 'T'),
     96: (R: Fumarase - 0, 'r'),
     97: (R: Fumarase - 0, 'R'),
     98: (R: Fumarase - 0, 'T'),
     99: (R: Malate dehydrogenase - 0, 'r'),
     100: (R: Malate dehydrogenase - 0, 'R'),
     101: (R: Malate dehydrogenase - 0, 'T')}

```python
from BondGraphTools import set_param, swap, new

# Set Parameters to 1
value = 1

for param in tca_model.params:
    set_param(tca_model, param, value)

# Swap acetyl_CoA for a effort source
acetyl_CoA = tca_model / "C: acetyl-CoA"
flow_control = new("Se", value=None)
swap(acetyl_CoA, flow_control)
```

```python
tca_model.constitutive_relations
```

## Basic Simulation

```python
import numpy as np
x_dim = len(tca_model.state_vars)
x0 = np.exp(np.random.randn(x_dim))

from BondGraphTools import simulate
t, x = simulate(tca_model,
                timespan=[0,1],
                x0=x0,
                control_vars=["t > 0.2 ? 2 : 0"])
```

```python
from matplotlib.pyplot import plot
_ = plot(t, x)
```

## BondGraphTools Development Philosophy

BondGraphTools ideals:
- working is better than right.
- ... it should just do the thing.
- ... it does what it says on the box.
- don't make the user fight the tools.

## What `BondGraphTools` does not do

- dimensional anaysis
- ensure realistic models
- graphical user interfaces
- parameter fitting
- ontologies, metadata...

## `BondGraphTools` in literature

Used in forthcoming work by:
- Prof. Peter Gawthrop (Physically Plausible Models)
- Michael Pan (Algorithmic Model Evalutition)
- PC (`BondGraphTools`)

## Current Status:

Currently version: 0.3.8

The next version 0.4 will include:
- Symbolics overhaul.
- Improved model reduction.
- Cleaner parameter handline.
- Observables.

# Thanks
- Andre and the CellML workshop organisers
- Prof. Peter Hunter and the ABI
- Prof. Edmund Crampin, Prof. Peter Gawthrop and Michael Pan & The Systems Biology Lab

<table >
    <tr style="background-color:#FFFFFF;">
        <td></td>
        <td></td>
    </tr>
</table>

## Please check out `BondGraphTools`

Docs: https://bondgraphtools.readthedocs.io/

GitHub: https://github.com/BondGraphTools