```python
import qutip
qutip.about()
```

    QuTiP: Quantum Toolbox in Python
    ================================
    Copyright (c) QuTiP team 2011 and later.
    Current admin team: Alexander Pitchford, Nathan Shammah, Shahnawaz Ahmed, Neill Lambert, Eric Giguère, Boxi Li, Jake Lishman and Simon Cross.
    Board members: Daniel Burgarth, Robert Johansson, Anton F. Kockum, Franco Nori and Will Zeng.
    Original developers: R. J. Johansson & P. D. Nation.
    Previous lead developers: Chris Granade & A. Grimsmo.
    Currently developed through wide collaboration. See https://github.com/qutip for details.

    QuTiP Version:      4.6.2
    Numpy Version:      1.20.1
    Scipy Version:      1.6.2
    Cython Version:     0.29.23
    Matplotlib Version: 3.3.4
    Python Version:     3.8.8
    Number of CPUs:     6
    BLAS Info:          INTEL MKL
    OPENMP Installed:   False
    INTEL MKL Ext:      False
    Platform Info:      Windows (AMD64)
    Installation path:  C:\Users\QINFOLAB0\anaconda3\lib\site-packages\qutip
    ================================================================================
    Please cite QuTiP in your publication.
    ================================================================================
    For your convenience a bibtex reference can be easily generated using `qutip.cite()`

```python
from qutip import *
import numpy as np
import matplotlib.pyplot as plt
```

```python
print(Qobj([[1],[2],[3],[4],[5]]))
```

    Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
    Qobj data =
    [[1.]
     [2.]
     [3.]
     [4.]
     [5.]]

```python
tensor(fock_dm(2,0),fock_dm(2,1))
```

Quantum object: dims = [[2, 2], [2, 2]], shape = (4, 4), type = oper, isherm = True\begin{equation*}\left(\begin{array}{*{11}c}0.0 & 0.0 & 0.0 & 0.0\\0.0 & 1.0 & 0.0 & 0.0\\0.0 & 0.0 & 0.0 & 0.0\\0.0 & 0.0 & 0.0 & 0.0\\\end{array}\right)\end{equation*}

```python
fock(2,0)
```

Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket\begin{equation*}\left(\begin{array}{*{11}c}1.0\\0.0\\\end{array}\right)\end{equation*}

H:hamiltonian;
W:oscillator;
W=1

\begin{equation}
H=-\frac{W}{2}\sigma_{z}
\end{equation}

```python
H=-(1/2)*sigmaz()#hamlitonian H=(-w/2)*sigmaz,oscillator frequency=1
P=0.36
H
```

Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True\begin{equation*}\left(\begin{array}{*{11}c}-0.500 & 0.0\\0.0 & 0.500\\\end{array}\right)\end{equation*}

```python
rho=P*fock_dm(2,0)+(1-P)*fock_dm(2,1)
psi0=fock(2,0)
rho
```

Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True\begin{equation*}\left(\begin{array}{*{11}c}0.360 & 0.0\\0.0 & 0.640\\\end{array}\right)\end{equation*}

```python
times = np.linspace(0.0, 10.0, 100)
result = mesolve(H, psi0, times, [], [])
result.states
```

    [Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[1.]
      [0.]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.9987249+0.05048334j]
      [0.       +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.99490286+0.10083794j]
      [0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.98854363+0.15093538j]
      [0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.97966342+0.20064791j]
      [0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.96828488+0.24984875j]
      [0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.95443702+0.29841242j]
      [0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.93815517+0.34621509j]
      [0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.91948083+0.39313484j]
      [0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.89846165+0.43905201j]
      [0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.87515121+0.48384953j]
      [0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.84960896+0.52741313j]
      [0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.82190005+0.56963172j]
      [0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.79209514+0.61039765j]
      [0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.76027023+0.64960694j]
      [0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.72650648+0.68715961j]
      [0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.69089+0.72295989j]
      [0.     +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.65351162+0.75691648j]
      [0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.61446666+0.78894279j]
      [0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.57385468+0.81895714j]
      [0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.53177927+0.84688299j]
      [0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.48834772+0.87264913j]
      [0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.44367078+0.89618984j]
      [0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.3978624+0.9174451j]
      [0.       +0.j       ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.3510394+0.93636069j]
      [0.       +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.30332117+0.95288838j]
      [0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.25482942+0.96698602j]
      [0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.2056878+0.97861766j]
      [0.       +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.15602164+0.98775364j]
      [0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.10595759+0.99437065j]
      [0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.05562334+0.99845182j]
      [0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.00514723+0.99998675j]
      [0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.04534201+0.99897152j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.09571561+0.99540872j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.14584512+0.98930743j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.1956027+0.98068322j]
      [ 0.       +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.24486146+0.96955808j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.29349576+0.95596037j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.3413816+0.93992479j]
      [ 0.       +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.38839685+0.92149221j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.43442161+0.90070964j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.47933852+0.8776301j]
      [ 0.        +0.j       ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.52303301+0.85231242j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.56539367+0.82482119j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.60631247+0.7952265j]
      [ 0.        +0.j       ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.64568505+0.76360383j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.68341102+0.73003382j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.71939415+0.69460209j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.75354268+0.65739898j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.78576954+0.61851938j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.81599253+0.57806244j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.84413459+0.53613133j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.87012393+0.49283297j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.8938943+0.4482778j]
      [ 0.       +0.j       ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.91538506+0.40257943j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.93454141+0.35585441j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.9513145+0.30822189j]
      [ 0.       +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.96566155+0.25980334j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.97754598+0.21072224j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.98693747+0.16110377j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.99381209+0.11107444j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.99815229+0.06076186j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.99994701+0.01029432j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.99919167-0.04019948j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.9958882-0.09059075j]
      [ 0.       +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.99004503-0.140751j]
      [ 0.        +0.j      ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.98167704-0.19055231j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.97080559-0.23986768j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.9574584-0.28857133j]
      [ 0.       +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.9416695-0.33653907j]
      [ 0.       +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.92347917-0.38364858j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.90293378-0.4297797j]
      [ 0.        +0.j       ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.88008574-0.4748148j]
      [ 0.        +0.j       ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.8549933-0.51863904j]
      [ 0.       +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.82772047-0.56114064j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.79833679-0.60221123j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.7669172-0.64174606j]
      [ 0.       +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.73354182-0.67964431j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.69829577-0.71580934j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.66126893-0.75014892j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.62255572-0.78257547j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.58225488-0.81300631j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.54046918-0.84136382j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.49730517-0.86757568j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.45287294-0.89157507j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.40728579-0.91330076j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.36065999-0.93269736j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.31311443-0.94971541j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.26477038-0.96431149j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.2157511-0.97644839j]
      [ 0.       +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.16618162-0.98609516j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.11618835-0.9932272j]
      [ 0.        +0.j       ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.06589877-0.99782631j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[-0.01544113-0.99988078j]
      [ 0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.03505588-0.99938535j]
      [0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.08546349-0.9963413j]
      [0.        +0.j       ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.13565315-0.99075639j]
      [0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.18549687-0.98264485j]
      [0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.23486754-0.97202739j]
      [0.        +0.j        ]],
     Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
     Qobj data =
     [[0.28363925-0.95893106j]
      [0.        +0.j        ]]]

```python
result2= mesolve(H, rho, times, [], [])
result2.states
```

    [Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]]]

```python
ket=basis(2,0)
ket1=basis(2,1)
jumpOP=ket*ket1.dag()
jumpOP
```

Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = False\begin{equation*}\left(\begin{array}{*{11}c}0.0 & 1.0\\0.0 & 0.0\\\end{array}\right)\end{equation*}

```python
result3= mesolve(H, rho, times, [jumpOP], [])
result3.states
```

    [Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.36 0.  ]
      [0.   0.64]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.42148843 0.        ]
      [0.         0.57851157]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.47706949 0.        ]
      [0.         0.52293051]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.52731068 0.        ]
      [0.         0.47268932]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.57272494 0.        ]
      [0.         0.42727506]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.61377596 0.        ]
      [0.         0.38622404]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.65088296 0.        ]
      [0.         0.34911704]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.68442486 0.        ]
      [0.         0.31557514]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.71474416 0.        ]
      [0.         0.28525584]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.74215049 0.        ]
      [0.         0.25784951]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.76692367 0.        ]
      [0.         0.23307633]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.78931671 0.        ]
      [0.         0.21068329]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.8095583 0.       ]
      [0.        0.1904417]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.82785515 0.        ]
      [0.         0.17214485]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.84439412 0.        ]
      [0.         0.15560588]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.85934409 0.        ]
      [0.         0.14065591]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.87285772 0.        ]
      [0.         0.12714228]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.88507303 0.        ]
      [0.         0.11492697]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.89611473 0.        ]
      [0.         0.10388527]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.90609559 0.        ]
      [0.         0.09390441]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.91511756 0.        ]
      [0.         0.08488244]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.92327274 0.        ]
      [0.         0.07672726]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.93064435 0.        ]
      [0.         0.06935565]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.93730775 0.        ]
      [0.         0.06269225]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.94333094 0.        ]
      [0.         0.05666906]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.94877547 0.        ]
      [0.         0.05122453]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.95369689 0.        ]
      [0.         0.04630311]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.95814551 0.        ]
      [0.         0.04185449]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.96216669 0.        ]
      [0.         0.03783331]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.96580156 0.        ]
      [0.         0.03419844]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.96908719 0.        ]
      [0.         0.03091281]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.97205717 0.        ]
      [0.         0.02794283]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.97474179 0.        ]
      [0.         0.02525821]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.9771685 0.       ]
      [0.        0.0228315]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.97936204 0.        ]
      [0.         0.02063796]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.98134486 0.        ]
      [0.         0.01865514]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.98313716 0.        ]
      [0.         0.01686284]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.98475727 0.        ]
      [0.         0.01524273]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.98622172 0.        ]
      [0.         0.01377828]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.98754548 0.        ]
      [0.         0.01245452]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.98874206 0.        ]
      [0.         0.01125794]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.98982367 0.        ]
      [0.         0.01017633]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.99080137 0.        ]
      [0.         0.00919863]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.99168514 0.        ]
      [0.         0.00831486]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.99248399 0.        ]
      [0.         0.00751601]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.9932061 0.       ]
      [0.        0.0067939]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.99385883 0.        ]
      [0.         0.00614117]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.99444884 0.        ]
      [0.         0.00555116]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.99498218 0.        ]
      [0.         0.00501782]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.99546427 0.        ]
      [0.         0.00453573]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.99590004 0.        ]
      [0.         0.00409996]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.99629395 0.        ]
      [0.         0.00370605]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.99665001 0.        ]
      [0.         0.00334999]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.99697186 0.        ]
      [0.         0.00302814]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.99726279 0.        ]
      [0.         0.00273721]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.99752577 0.        ]
      [0.         0.00247423]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.99776348 0.        ]
      [0.         0.00223652]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.99797836 0.        ]
      [0.         0.00202164]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.99817259 0.        ]
      [0.         0.00182741]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.99834816 0.        ]
      [0.         0.00165184]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.99850686 0.        ]
      [0.         0.00149314]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.99865032 0.        ]
      [0.         0.00134968]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.99877999 0.        ]
      [0.         0.00122001]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[0.9988972 0.       ]
      [0.        0.0011028]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99003146e-01 0.00000000e+00]
      [0.00000000e+00 9.96853576e-04]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99098917e-01 0.00000000e+00]
      [0.00000000e+00 9.01083483e-04]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99185488e-01 0.00000000e+00]
      [0.00000000e+00 8.14511522e-04]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99263744e-01 0.00000000e+00]
      [0.00000000e+00 7.36256262e-04]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99334480e-01 0.00000000e+00]
      [0.00000000e+00 6.65519838e-04]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.9939842e-01 0.0000000e+00]
      [0.0000000e+00 6.0157988e-04]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99456216e-01 0.00000000e+00]
      [0.00000000e+00 5.43784305e-04]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99508457e-01 0.00000000e+00]
      [0.00000000e+00 4.91543106e-04]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99555681e-01 0.00000000e+00]
      [0.00000000e+00 4.44319018e-04]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99598370e-01 0.00000000e+00]
      [0.00000000e+00 4.01630145e-04]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99636956e-01 0.00000000e+00]
      [0.00000000e+00 3.63043540e-04]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99671836e-01 0.00000000e+00]
      [0.00000000e+00 3.28163572e-04]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99703367e-01 0.00000000e+00]
      [0.00000000e+00 2.96632972e-04]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99731868e-01 0.00000000e+00]
      [0.00000000e+00 2.68131617e-04]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99757632e-01 0.00000000e+00]
      [0.00000000e+00 2.42368239e-04]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99780921e-01 0.00000000e+00]
      [0.00000000e+00 2.19079335e-04]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99801973e-01 0.00000000e+00]
      [0.00000000e+00 1.98026635e-04]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99821005e-01 0.00000000e+00]
      [0.00000000e+00 1.78994838e-04]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99838210e-01 0.00000000e+00]
      [0.00000000e+00 1.61790117e-04]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99853761e-01 0.00000000e+00]
      [0.00000000e+00 1.46238795e-04]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99867814e-01 0.00000000e+00]
      [0.00000000e+00 1.32186106e-04]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99880514e-01 0.00000000e+00]
      [0.00000000e+00 1.19486455e-04]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99891992e-01 0.00000000e+00]
      [0.00000000e+00 1.08007850e-04]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99902367e-01 0.00000000e+00]
      [0.00000000e+00 9.76329159e-05]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99911744e-01 0.00000000e+00]
      [0.00000000e+00 8.82561814e-05]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99920219e-01 0.00000000e+00]
      [0.00000000e+00 7.97814936e-05]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99927880e-01 0.00000000e+00]
      [0.00000000e+00 7.21200063e-05]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99934807e-01 0.00000000e+00]
      [0.00000000e+00 6.51931285e-05]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99941069e-01 0.00000000e+00]
      [0.00000000e+00 5.89307647e-05]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99946730e-01 0.00000000e+00]
      [0.00000000e+00 5.32703056e-05]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99951848e-01 0.00000000e+00]
      [0.00000000e+00 4.81520789e-05]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99956476e-01 0.00000000e+00]
      [0.00000000e+00 4.35240005e-05]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99960660e-01 0.00000000e+00]
      [0.00000000e+00 3.93404049e-05]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99964439e-01 0.00000000e+00]
      [0.00000000e+00 3.55614922e-05]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99967852e-01 0.00000000e+00]
      [0.00000000e+00 3.21479149e-05]],
     Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
     Qobj data =
     [[9.99970937e-01 0.00000000e+00]
      [0.00000000e+00 2.90631698e-05]]]

```python
result3= mesolve(H, rho, times, [np.sqrt(0.0004) *jumpOP], [sigmax(),sigmay(),sigmaz()])
fig, ax = plt.subplots()
ax.plot(times, result3.expect[2])
```

```python
fig, ax = plt.subplots()
ax.plot(times, result3.expect[2])
```


#
 NISQAI: One-Qubit Quantum Classifier

 Ryan LaRose, Yousif Almulla, Nic Ezzell, Joe Iosue, Arkin Tikku

"Quantum computing needs more quantum software engineers to implement, test, and optimize quantum algorithms."
    -- Matthias Troyer.

"Experimentation on quantum testbeds is needed." -- John Preskill.

#
 What is NISQAI?

Quantum machine learning is an exciting but conjectural field that lacks testing on quantum computers. NISQAI is a library written to facilitate research in artificial intelligence on current quantum computers and NISQ (noisy intermediate-scale quantum) devices.

In this notebook, we demonstrate the steps toward a quantum neural network working as a simple classifier. We then demonstrate how easily the NISQAI library can facilitate this task.

#
 Requirements for this Notebook

Since you're reading this, you probably have a working installation of [Python](https://www.python.org/) and/or [Jupyter](http://jupyter.org/). In order to run this notebook, the following external packages are necessary. Installation instructions can be found by following the hyperlinks for each.

* [NumPy](http://www.numpy.org/)
* [SciPy](https://www.scipy.org/)
* [pyQuil](https://pyquil.readthedocs.io/en/stable/) 2.1.0
* [Matplotlib](https://matplotlib.org/)
* [QuTiP](http://qutip.org/docs/4.1/index.html) 4.1.0 (only for Bloch sphere visualization features)

```python
# builtins
import time

# standard imports
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import minimize

# library imports
from pyquil.quil import Program
from pyquil import api
import pyquil.gates as ops
from qutip import Bloch, ket

# option for notebook plotting
%matplotlib inline
```

#
 Quantum Neural Networks: A Five Step Process

To implement a neural network for classical data on a quantum computer (i.e., a _quantum neural network_), the following steps need to be performed.

1. Data encoding.
    * Encode the classical data into a form suitable for the quantum circuit.
1. State preparation.
    * Implement a quantum circuit preparing the state of a particular datum.
1. Unitary evolution.
    * Implement a parameterized gate sequence to transform the data.
1. Measurement/non-linearity.
    * Measure the state of the quantum data after unitary evolution to revert back to classical information.       * Non-linearity can be introduced at this point via classical processing.
1. Training/cost function.
    * Define a cost function and optimize the parameters of the unitary to minimize the cost.

In the rest of the notebook, we'll go over how to do each of these steps in turn for a simple classification problem. At the end of the notebook, we'll show how easily this can be done with the NISQAI library and discuss other features of NISQAI.

#
 Problem Description

The specific problem we look it in this notebook falls under the category of _supervised machine learning_. Specifically, we ask:

_Given $N$ data points $p = (x, y) \in \mathbb{R}^2$ with labels $z(p) = 1$ if $x \le 0.5$ and $z(p) = 0$ otherwise, learn the decision boundary and classify new points._

##
 1. Data Encoding

In order to run a quantum neural network on classical data, the classical data needs to be suitably encoded to allow it to be "uploaded" to a quantum computer. We demonstrate a simple encoding scheme below for $(x, y)$ Cartesian coordinates distributed uniformly in a unit square.

###
 Generating Data

First we generate a random set of classical data. For reproducibility, we'll seed our random number generator.

```python
# set random seed for reproducible results
SEED = 1059123109
np.random.seed(seed=SEED)
```

```python
# generate data points distributed uniformly at random in [0, 1) x [0, 1)
npoints = 400
data = np.zeros((npoints, 2))
dx = np.linspace(0, 1, 20)

for j in range(20):
    data[j * len(dx) : (j + 1) * len(dx), 0] = dx[j]
    data[j * len(dx) : (j + 1) * len(dx), 1] = dx

# npoints = 100
# data = np.random.rand(npoints, 2)

def predicate(point):
    """Returns true if the point satisfies the predicate, else false."""
    return True if point[0] <= point[1] else False

# separate the data with a linear boundary y = x
labels = np.array([1 if predicate(p) else 0 for p in data])

# plot the line y = x
xs = np.linspace(0, 1, 100)
ys = 0.5 * np.ones_like(xs)
plt.plot(xs, xs, '--k')

# plot the data with the color key BLUE = 0 = LEFT, GREEN = 1 = RIGHT
for i in range(npoints):
    if labels[i] == 0:
        ckey = 'g'
    else:
        ckey = 'b'
    plt.scatter(data[i, 0], data[i, 1], color=ckey)

# title and axis lables
#plt.title("Random Data Points in Unit Square", fontweight="bold", fontsize=16)

# put on a grid and show the plot
plt.grid()
# plt.savefig("graph.pdf", format="pdf")
plt.show()
```

###
 Qubit Encoding

Here we implement a method of data encoding that we call "qubit encoding." Qubit encoding works by writing two bits of classical information into one bit of quantum information. How is this done? Note that any qubit can be written

\begin{equation}
|\psi\rangle = \alpha |0\rangle + \beta |1\rangle
\end{equation}

where $\alpha, \beta \in \mathbb{C}$ satisfying $|\alpha|^2 + |\beta|^2 = 1$. Because of this normalization condition, we may equivalently write

\begin{equation}
|\psi\rangle = \cos(\theta / 2) |0\rangle + e^{i \phi} \sin(\theta / 2)|1\rangle
\end{equation}

We then encode information into the phases $0 \le \theta \le \pi$ and $ 0 \le \phi \le 2 \pi$.

For the $(x, y)$ coordinates of our points, we will use the encoding

\begin{align}
\theta &= \pi x \\
\phi &= 2 \pi y
\end{align}

This is a simple encoding, but the results of the classification will speak to it's effectivenss. Other encodings, for example

\begin{align}
\theta &= \frac{1}{2} \tan^{-1}\left( \frac{y}{x} \right) \\
\phi &= \pi (x^2 + y^2),
\end{align}

can be used for other data sets.

In code, we may make this transformation as follows:

```python
# encode the classical data via a simple linear "qubit encoding"
qdata = np.zeros_like(data)
for (index, point) in enumerate(data):
    qdata[index][0] = np.pi * (point[0] + 0.0 * point[1]) / 1.0
    qdata[index][1] = 2 * np.pi * (0.0 * point[0] + point[1]) / 1.0
#     qdata[index][0] = np.pi * point[0]
#     qdata[index][1] = 2 * np.pi * point[1]
#     qdata[index][0] = 2 * np.arcsin(point[0])
#     qdata[index][1] = 4 * np.arccos(point[1])
```

It's now possible to visualize the data as points on the surface of the Bloch sphere.

```python
# break the data into two lists depending on label and turn into (x, y, z) points

# empty lists to store values
gxs = []
gys = []
gzs = []
bxs = []
bys = []
bzs = []

# loop over all points, convert to cartesian coords, and append to correct list
for (index, point) in enumerate(qdata):
    theta = point[0]
    phi = point[1]
    sin = np.sin(theta)
    # convert to cartesian coords for plotting
    x = np.sin(theta) * np.cos(phi)
    y = np.sin(theta) * np.sin(phi)
    z = np.cos(theta)
    if labels[index] == 0:
        gxs.append(x)
        gys.append(y)
        gzs.append(z)
    else:
        bxs.append(x)
        bys.append(y)
        bzs.append(z)

# format points correctly for bloch sphere
lpoints = [gxs, gys, gzs]
rpoints = [bxs, bys, bzs]

# get a Bloch sphere
bloch = Bloch()

# options for Bloch sphere
bloch.frame_color = "grey"
bloch.sphere_color = "white"
bloch.point_size = [40]
bloch.sphere_alpha = 0.50
bloch.point_color = ["g", "b"]
bloch.point_marker = ["o"]
bloch.view = [-55, 10]

# add the points on the Bloch sphere
bloch.add_points(lpoints)
bloch.add_points(rpoints)

# show the Bloch sphere
#bloch.save("lin-comb-bloch.pdf", format="pdf")
%matplotlib notebook
bloch.show()
```

##
 2. State Preparation

Now that we have encoded our data, we still need to prepare it in quantum form. Conventionally, all qubits start in the $|0\rangle$ state. The problem we have to solve is:

Given angles $\theta, \phi$, perform the mapping

\begin{equation}
S(\theta, \phi) |0\rangle \rightarrow |\psi\rangle = \cos(\theta / 2) |0\rangle + e^{i \phi} \sin(\theta / 2)|1\rangle
\end{equation}

We call $S$ a _state preparation unitary_ or _state preparation circuit_.

It is clear from the equation above that the matrix representation for $S$ in the computational basis is

\begin{equation}
S(\theta, \phi) = \left[ \begin{matrix}
\cos(\theta / 2) & e^{-i \phi} \sin(\theta / 2)\\
e^{i \phi} \sin(\theta / 2) & - \cos(\theta / 2)  \\
  \end{matrix} \right]
\end{equation}

On current NISQ computers, circuits need to be as short-depth as possible, meaning they contain as few gates as possible. The "qubit encoding" performed above allows for a constant-depth state preparation circuit for any given values of $\theta, \phi$.

Why is this? In general we need to perform some arbitrary unitary transformation $S \in SU(2)$. It is known that such a unitary can be implemented with five standard rotations that can be implemented by current quantum computers. Namely,

\begin{equation}
S = R_z(\gamma_1) R_x(\pi / 2) R_z(\gamma_2) R_x(\pi / 2) R_z(\gamma_3)
\end{equation}

where $0 \le \gamma_i \le 2 \pi$ for $i = 1, 2, 3$. We can define our gate $S$ above in pyquil and compile it to a sequence of five implementable rotations by using the Quil compiler. First we'll write a function to give us our state preparation matrix.

```python
# define the matrix S as a function of theta and phi
def state_prep_mtx(theta, phi):
    """Returns the state preparation matrix according to the qubit encoding above."""
    return np.array([[np.cos(theta / 2), np.exp(-1j * phi) * np.sin(theta / 2)],
                     [np.exp(1j * phi) * np.sin(theta / 2), - np.cos(theta / 2)]])
```

Next we'll define this as a pyquil gate. We do this by first making a program then defining a gate for a particular encoded data point.

```python
# get a pyquil program
qprog = Program()

# pick a particular encoded data point
theta, phi = qdata[0]

# get the state prep matrix for this point
S = state_prep_mtx(theta, phi)

# define a gate in pyquil for the state preparation
qprog.defgate("S", state_prep_mtx(theta, phi))
```

We can now use this gate in a quantum program to input our classical data into the quantum computer. To do this, we simply write:

```python
# prepare the first encoded data point in quantum form
qprog += ("S", 0)
```

To see our program, we can print it out:

```python
print(qprog)
```

If we measure this qubit now, we get either a zero or a one with probability proportional to it's amplitudes. We'll add this measurement to our program and then run it many times to get an estimate of the probability distribution of it's outcome.

```python
# add a measurement on the qubit encoding our data
creg = qprog.declare("ro", memory_size=1)
qprog += (ops.MEASURE(0, creg[0]))

# print out the new program
print(qprog)
```

```python
# run the program many times
shots = 1000
qvm = api.QVMConnection()
dist = qvm.run(qprog, trials=shots)
```

```python
def histogram(dist):
    """Makes a histogram of the probability of obtaining 0 and 1."""
    # get the zero and one probabilities
    prob0 = dist.count([0]) / shots
    prob1 = dist.count([1]) / shots

    # make a bar plot
    plt.bar([0, 1], [prob0, prob1])

    # make it look nice
    plt.grid()
    plt.title("Output Probability Distribution", fontsize=16, fontweight="bold")
    plt.xlabel("Measurement Outcomes", fontsize=14)
    plt.ylabel("Probability", fontsize=14)
    plt.ylim(0, 1)
    plt.xticks([0, 1])

    # show it
    plt.show()

# make a histrogram of the output distribution
histogram(dist)
```

We want our output distribution to move towards either zero or one, depending on what label is assigned to that particular data point. To do this, we implement unitary evolution on the circuit, which corresponds to implementing another sequence of gates in our circuit.

##
 3. Unitary Evolution

After the classical data has been encoded (step 1) and prepared into the quantum system (step 2), step 3 is to perform unitary evolution on the quantum state representing the data. In the language of classical learning theory, this corresponds to implementing a layer of the neural network.

In the quantum neural network case, we simply need to implement a sequence of parameterized gates.

First we write a function to easily implement such a unitary.

```python
def unitary(angles):
    """Returns a circuit implementing the unitary Rz(theta0) P Rz(theta1) P Rz(theta2)
    where thetea0 = angles[0], theta1 = angles[1], and theta2 = angles[2] and
    P = Rx(pi / 2) is a pi / 2 pulse.
    """
    return Program(
        ops.RZ(angles[0], 0),
        ops.RX(np.pi / 2, 0),
        ops.RZ(angles[1], 0),
        ops.RX(np.pi / 2, 0),
        ops.RZ(angles[2], 0)
    )
```

Next we use it to add unitary evolution to our quantum neural network for some given angles.

```python
# test angles
angles = 2 * np.pi * np.random.rand(3)

# pop off measurement
qprog.pop()

# append the unitary circuit to our quantum neural network program
qprog += unitary(angles)
qprog += [ops.MEASURE(0, creg[0])]
```

```python
print(qprog)
```

Now we'll run this new circuit with the unitary evolution implemented.

```python
# run the quantum neural network program
histogram(qvm.run(qprog, trials=shots))
```

Now we want to use this unitary evolution to move our output probability towards the desired label. We'll suppose for a moment that this point is supposed to be mapped to the 0 output. We'll define an objective function ```obj_simple(angles)``` to capture the amount of 1 outputs, then we'll train over the angles in the unitary to minimize the objective.

```python
def make_program(pangles, uangles):
    """Returns a pyquil program that prepares the state according
    to pangles and applies the unitary according to uangles.
    """
    # instantiate a program
    qprog = Program()
    creg = qprog.declare("ro", memory_size=1)

    # define a gate in pyquil for the state preparation
    qprog.defgate("S", state_prep_mtx(pangles[0], pangles[1]))

    # write the program(
    qprog += [("S", 0),
             unitary(uangles),
             ops.MEASURE(0, creg[0])]

    return qprog

def obj_simple(angles, shots=1000, verbose=False):
    """Returns the number of zero outputs of a single training example."""
    # make the program
    qprog = make_program([theta, phi], angles)
    if verbose:
        print(qprog)
    dist = qvm.run(qprog, trials=shots)
    obj = dist.count([1]) / shots
    print("The current value of the objective function is:", obj, end="\r")
    return obj
```

Now we'll minimize the objective function `obj_simple` by using the modifed `Powell` algorithm builtin to SciPy. The minimization here should take no more than 30 seconds.

```python
out = minimize(obj_simple, x0=2 * np.pi * np.random.rand(3), method="Powell")
```

Now we can verify that the output distribution skews this point towards the "zero bin."

```python
# do the circuit (neural network) with the optimal parameters
%matplotlib inline
opt_angles = out['x']
qprog = make_program([theta, phi], opt_angles)

# show the output distribution
dist = qvm.run(qprog, trials=shots)
histogram(dist)
```

Indeed it does! Here we demonstrated that we can use our neural network to "steer" a point in a particular direction. The idea of training is to "steer" _all_ points in the desired direction. Before we train our quantum neural network, we first discuss the measurement process and it's importance in quantum neural network implementations.

##
 4. Measurement

Measurement is used in our circuit above to translate from quantum to classical information. In other quantum neural networks, measurement can be used to introduce non-linearity.

NISQAI treats measurements as both a way to keep circuit-depth low (for implementations on current/near-term quantum computers) as well as introduce non-linearity between layers of a network. Specifically, measuremnets lead to (intermediate) classical data. On a classical computer, we can introduce any non-linear activation function we wish. The new classical data from the output of the activation function can then be prepared into quantum form again via steps 1 and 2 (data encoding and state preparation).

This intermediate classical post-processing is a trademark of NISQAI. It allows for:

1. Short-depth circuits suitable for NISQ computers.
1. Non-linearity between layers of a quantum neural network.
1. Deep learning (many layers) with shallow circuits.

In this simple binary classifier example, we'll restrict to just one layer of the neural network for simplicity.

##
 5. Training

We saw above that it's easy to steer one point towards the output we want to get. But training the quantum neural network involves training over all points in the training set. For this, we need to define a cost function that captures the total loss over the entire training set.

To do this, define the _indicator function_ $I(z_i = \hat{z}_i)$ to be 0 if $z_i = \hat{z}_i$ and 1 otherwise. Here, $z_i$ is the exact label of the $i$th training data $(x_i, y_i)$ and $\hat{z}_i$ is the prediction of this label by our neural network. (In code, we use the variables `labels` for $z_i$ and `predictions` for $\hat{z}_i$.)

To define the cost now, we simply sum over all points (say there are $M$ points) in the training data:

\begin{equation}
C = \sum_{i = 1}^{M} I(z_i = \hat{z}_i)
\end{equation}

Note that the cost $C$ depends on the unitary evolution $U$, i.e. $C = C(U)$, because the prediction $\hat{z}_i$ depends on $U$.

We now need to define a cost (objective) function ```obj(...)``` that takes into account all data in the training set. This function will encapsulate everything we've done for a single training point, but now for all of them.

```python
# fraction of total data to use as training data
train_frac = 0.7

def obj(uangles):
    """Returns the objective function C defined above over all training data.

    Args:
        uangles [type: list<float>]
            the angles in the unitary evolution.

    rtype: int
    """
    # grab some training data from the overall data set
    tpoints = int(train_frac * len(qdata))
    tdata = qdata[:tpoints]
    tlabels = labels[:tpoints]

    # initialize a variable to store the output predictions of the neural net
    predictions = np.zeros_like(tlabels, dtype=int)

    # loop over all training data to get the predictions
    for i, pangles in enumerate(tdata):
        # write the program
        qprog = make_program(pangles, uangles)

        # run the program
        out = qvm.run(qprog, trials=1000)

        # get the output probabilities
        p0 = out.count([0])
        p1 = out.count([1])

        # take the prediction to be max(p0, p1)
        if p0 >= p1:
            predictions[i] = 0
        else:
            predictions[i] = 1

    # compute the difference of the labels and return the cost
    cost = sum(abs(predictions - tlabels)) / tpoints
    print("The current value of the cost function is:", cost, end="\r")
    return cost
```

Now let's compute the objective function for some random test angles.

```python
# get some random angles
angs = 2 * np.pi * np.random.rand(3)
cost = obj(angs)
```

We don't want just any random angles for our unitary evolution, however. We want to compute the optimal angles, which we can do by minimizing the cost function. Again we'll use the modified ```Powell``` algorithm for minimization.

Training the neural network here will take more time than simply optimizing the output of a single point. On our computer, it takes around 15 seconds to evaluate the objective function for one set of angles. The `Powell` optimization algorithm generally takes on the order of 20-30 cost function evaluations--for us the optimization takes around 15 minutes on average. You can expect this training to take 15-20 minutes.

If you're in a hurry and don't want to wait for this training, we've saved a set of optimal angles from previous attempts. These angles are for a horizontal boundary $x = 0.5$ trained on 70/100 data points. They will only be optimal for the first set of random points generated by the given seed. We reiterate: _Only use these angles if you haven't changed anything in the notebook and only ran each cell once!_

```python
optimal_angles = [7.85082205, 0.01934754, 9.62729993]
```

If you chose to skip the training, you should *not* execute the next two cells. Otherwise, continue through the notebook.

```python
# train the quantum neural network and time how long it takes
start = time.time()
out = minimize(fun=obj, x0=angs, method="Powell")
print("\nTotal training runtime took {} minutes.".format((time.time() - start) / 60))
```

```python
# grab the optimal angles and minimal cost value
optimal_angles = out['x']
fval = out['fun']

# print them out
print(fval)
print(optimal_angles)
```

#
 Results

Now that we've trained on a subset of our data, we can see how the predictions do on the whole dataset.

First, we'll write a function that performs this task.

```python
def get_all_predictions(angles):
    """Returns a numpy array of all predictions."""
    # initialize a variable to store the output predictions of the neural net
    zhats = np.zeros_like(labels, dtype=int)

    # loop over all data to get predictions
    for i, pangles in enumerate(qdata):
        # write the program
        qprog = make_program(pangles, angles)

        # run the program
        out = qvm.run(qprog, trials=1000)

        # get the output probabilities
        p0 = out.count([0])
        p1 = out.count([1])

        # take the prediction to be max(p0, p1)
        if p0 >= p1:
            zhats[i] = 0
        else:
            zhats[i] = 1
    return zhats
```

Then we'll call the function to get the results.

```python
# compute all the predictions of the quantum neural network
predictions = get_all_predictions(optimal_angles)
```

We have now trained our neural network and classifeid all data points. Let's display the statistics below to see how our QNN performed.

```python

num = 0

for a in np.linspace(0, 2 * np.pi, 25):
    for b in np.linspace(0, 2 * np.pi, 25):
        num += 1

        # compute all the predictions of the quantum neural network
        predictions = get_all_predictions([a, b, 0])

# # compute statistics of the QNN
# ntrain = int(train_frac * npoints)
# ncorrect = npoints - sum(abs(predictions - labels))
# acc = ncorrect / npoints * 100

# # print them out
# print(" Results of quantum neural network classification ".center(80, "="))
# print("Out of {} total data points:".format(npoints))
# print("The QNN was trained on {}% of the total data ({} training points).".format(train_frac * 100, ntrain))
# print("The QNN classified {} data points correctly ({}% accuracy).".format(ncorrect, acc))
# print("".center(80, "="))
# % matplotlib inline
# # plot the points, line y = x, and prediction
# #plt.plot(xs, xs, '--k')
        for i in range(npoints):
            if predictions[i] == 0:
                ckey = 'g'
            else:
                ckey = 'b'
            plt.scatter(data[i, 0], data[i, 1], color=ckey)

        plt.grid()
        plt.title("a = %0.2f, b = %0.2f" %(a, b), fontsize=16, fontweight="bold")
        plt.savefig(str(num) + ".png", format="png")
        plt.close()
```

##
 Discussion of Results

How did your quantum neural network perform? If you followed through this notebook sequentially, you should have seen 100% accuracy in the predictions of the network. A saved plot of our results obtained by running this notebook is included below:

Here, the exact decision boundary (not the learned one) is shown in the plot, and data points are colored according to the quantum neural network predictions. Blue means predicted left of the boundary (0 bin), and green means predicted right of the boundary (1 bin). As can be seen in our example results, all data points are correctly classified.

#
 Example Done with NISQAI

The above example involved five steps to implementing a neural network on a quantum computer. While the steps aren't hard, programming each one for every particular example is tedious and time consuming. More time could be spent testing quantum neural networks if there were a library to implement all of these steps.

This is where NISQAI comes in. NISQAI is to quantum machine learning what TensorFlow/pyTorch is to classical machine learning. Just like OpenFermion provides a library of code to simplify quantum chemistry on quantum computers, NISQAI provides a library of code to simplify neural networks and other machine learning algorithms on quantum computers.

The above classifier example in NISQAI could be done with the following few lines of code. Here, we assume that ```classical_data``` exists in the program.

## Prototype NISQAI Code

```
# imports
from nisqai import qnn

# get a quantum neural network
network = qnn.qnn(nodes=1, layers=1)

# encode the classical data into quantum form
network.encode(data=classical_data, scheme=qnn.encoding_schemes.SIMPLE_LINEAR)

# add the unitary evolution
network.add_unitary(qnn.ansatze.UNIVERSAL)

# add measurements to the network
network.add_measurements(basis=qnn.bases.Z)

# do the training on 70% of the total data
network.train(optimizer="Powell", fraction=0.7)

# test the neural network on all the data or on new input data
statistics = network.classify()
```

These few lines of code show the power of NISQAI. One of it's greatest strengths is the flexibility to research other quantum neural network implementations, not just the one qubit quantum classifier.

## Features of NISQAI

* Shatters domain barriers.
    * Whether you're a machine learning researcher interested in quantum or a quantum researcher interested in machine learning, NISQAI is built for you.
* Powerful builtins.
    * Numerous prototypes of quantum neural network architectures, including methods for data encoding, state preparation, unitary evolution, measurement, and training.
* Fully modular.
    * For methods like `qnn.add_unitary(...)`, the user can write a function to specify whichever unitary ansatz is desired.
* Loaded with examples.
    * Many instructive code snippets and notebooks to get you started in quantum machine learning.
* Open-source.
    * NISQAI is currently under development with expected release in early 2019. After this, NISQAI will be free and open-source. Always.
* Cross platform.
    * NISQAI works for Windows, Mac, and Linux.
* Python/Matlab interfaces.
    * Two of the most popular languages for quantum computing and machine learning researchers.

# Conclusions

In this example, we've seen that a quantum neural network is able to successfully classify classical data in $\mathbb{R}^2$. The qubit encoding strategy is able to write two bits of classical information into one bit of quantum information. Additionally, the state preparation circuit for the qubit encoding is short-depth, particularly useful for NISQ computers. We've demonstrated how to train a quantum neural network using the modified Powell algorithm on a simple example. We've also discussed how the NISQAI library greatly simplifies quantum neural network implementations.

# Acknowledgements

The development of NISQAI is supported by the [unitary.fund](http://unitary.fund/). We thank [Will Zeng](https://twitter.com/wjzeng) for creating and running this program, as well as [John Hering](https://twitter.com/johnhering), Jeff Cordova, Nima Alidoust, and [PLOS](https://www.plos.org/) for sponsoring it.


[Sascha Spors](https://orcid.org/0000-0001-7225-9992),
Professorship Signal Theory and Digital Signal Processing,
[Institute of Communications Engineering (INT)](https://www.int.uni-rostock.de/),
Faculty of Computer Science and Electrical Engineering (IEF),
[University of Rostock, Germany](https://www.uni-rostock.de/en/)

# Tutorial Signals and Systems (Signal- und Systemtheorie)

Summer Semester 2021 (Bachelor Course #24015)

- lecture: https://github.com/spatialaudio/signals-and-systems-lecture
- tutorial: https://github.com/spatialaudio/signals-and-systems-exercises

WIP...
The project is currently under heavy development while adding new material for the summer semester 2021

Feel free to contact lecturer [frank.schultz@uni-rostock.de](https://orcid.org/0000-0002-3010-0294)

## Solving an Electric System's 2nd-order ODE

```python
import numpy as np
import matplotlib.pyplot as plt
import sympy as sp
import scipy.signal as signal
```

## Plots for Specific Manually Derived Results

See `solving_2nd_order_ode.tex` for manual calculus

All results are valid for $t\geq 0$, functions are zero for $t<0$.

### Impulse Response
\begin{equation}
\frac{16}{25} \ddot{y} + \frac{24}{25} \dot{y} + y = x
\end{equation}
for $x = \delta(t)$
\begin{equation}
y_p = h = \frac{25}{16} \mathrm{e}^{-\frac{3}{4} t} \sin(t)
\end{equation}

### Step Response
\begin{equation}
\frac{16}{25} \ddot{y} + \frac{24}{25} \dot{y} + y = x
\end{equation}
for $x = 1$, $\dot{y}(0)=0$, $y(0)=0$
\begin{equation}
y_p + y_h = h_\epsilon = 1 - \mathrm{e}^{-\frac{3}{4} t} \left(\frac{3}{4} \sin(t) + \cos(t)\right)
\end{equation}

```python
t = np.arange(0,10,0.1)
h = 25/16 * np.exp(-3/4*t) * np.sin(t)
he = 1 + np.exp(-3/4*t) * (-3/4*np.sin(t) - np.cos(t))
plt.figure(figsize=(8,4))
plt.plot(t,h,'--',label='impulse response',lw=3)
plt.plot(t,he, label='step response',lw=3)
plt.xlabel('t / s')
plt.ylabel('y(t)')
plt.grid(True)
plt.xlim((0,7))
plt.ylim((-0.2,1.2))
plt.title('ODE: 16/25 y\'\'(t)+ 24/25 y\'(t) + y(t)')
plt.legend()
plt.savefig('impulse_step_response.pdf')
```

### Signal Parts for Step Response with Zero Initial Conditions
\begin{equation}
\frac{16}{25} \ddot{y} + \frac{24}{25} \dot{y} + y = x
\end{equation}
for $x=1$, $\dot{y}(0)=0$, $y(0)=0$
\begin{equation}
h_\epsilon = 1 - \mathrm{e}^{-\frac{3}{4} t} \left(\frac{3}{4} \sin(t) + \cos(t)\right)
\end{equation}
Superposition of black, green and red graph yield result in orange graph.

```python
t = np.arange(0,10,0.1)
he = 1 + np.exp(-3/4*t) * (-3/4*np.sin(t) - np.cos(t))
heps = t*0 + 1
hsin = -3/4 * np.sin(t) * np.exp(-3/4*t)
hcos = -np.cos(t) * np.exp(-3/4*t)
hexp11 = +np.exp(-3/4*t)
hexp34 = +3/4*np.exp(-3/4*t)
plt.figure(figsize=(8,4))
plt.plot(t,heps,'-',label='step',lw=2, color='k')
plt.plot(t,hsin,'-d',label='damped negative sine',lw=1, color='C2')
plt.plot(t,hcos,'-*',label='damped negative cosine',lw=1, color='C3')
plt.plot(t,he,'-',label='step response h$_\epsilon(t)$',lw=3, color='C1')
plt.plot(t,hexp11,'--',label='',lw=1, color='gray')
plt.plot(t,-np.cos(t),'--',label='',lw=1, color='gray')
plt.plot(t,hexp34,':',label='',lw=1, color='gray')
plt.plot(t,-np.sin(t),':',label='',lw=1, color='gray')
plt.xlabel('t / s')
plt.ylabel('y(t)')
plt.grid(True)
plt.xlim((-0.1,7))
plt.ylim((-1,1.2))
plt.title('ODE: 16/25 y\'\'(t)+ 24/25 y\'(t) + y(t) = 1, y\'(0)=0, y(0)=0')
plt.legend()
plt.savefig('step_response_parts.pdf')
```

### Signal Parts for Initial Conditions Only
\begin{equation}
\frac{16}{25} \ddot{y} + \frac{24}{25} \dot{y} + y = 0
\end{equation}
for $\dot{y}(0)=2$, $y(0)=1$
\begin{equation}
y = \mathrm{e}^{-\frac{3}{4} t} \left( \frac{11}{4} \sin(t) + \cos(t)\right)
\end{equation}
Superposition of green/diamonds and red/stars graph yields final result depicted in brown.

```python
t = np.arange(0,10,0.1)
hdec = np.exp(-3/4*t) * (11/4*np.sin(t) + np.cos(t))
hcos = +np.exp(-3/4*t) * np.cos(t)
hsin = +11/4*np.exp(-3/4*t) * np.sin(t)
plt.figure(figsize=(8,4))
plt.plot(t,hdec,'-',label='$y(t)$',lw=2, color='C5')
plt.plot(t,hsin,'-d',label='damped sine',lw=1, color='C2')
plt.plot(t,hcos,'-*',label='damped cosine',lw=1, color='C3')
plt.xlabel('t / s')
plt.ylabel('y(t)')
plt.grid(True)
plt.xlim((0,7))
plt.ylim((-0.2,1.6))
plt.title('ODE: 16/25 y\'\'(t)+ 24/25 y\'(t) + y(t) = 0, y\'(0)=2, y(0)=1')
plt.legend()
plt.savefig('initial_conditions_response_parts.pdf')
```

### Signal Parts for Step Response with Initial Conditions
\begin{equation}
\frac{16}{25} \ddot{y} + \frac{24}{25} \dot{y} + y = x
\end{equation}
for $x=1$, $\dot{y}(0)=2$, $y(0)=1$
\begin{equation}
y = 1+\mathrm{e}^{-\frac{3}{4} t} \, 2 \sin(t)
\end{equation}

Superposition of black and green/diamond graphs yield the final result shown in magenta.

```python
t = np.arange(0,10,0.1)
hstep = t*0+1
hsin = 2*np.exp(-3/4*t) * np.sin(t)
hresp = hstep + hsin
plt.figure(figsize=(8,4))
plt.plot(t,hresp,'-',label='full response $y(t)$',lw=3, color='C6')
plt.plot(t,hstep,'-',label='step',lw=2, color='k')
plt.plot(t,hsin,'-d',label='damped sine',lw=1, color='C2')
plt.xlabel('t / s')
plt.ylabel('y(t)')
plt.grid(True)
plt.xlim((0,7))
plt.ylim((-0.2,2))
plt.title('ODE: 16/25 y\'\'(t)+ 24/25 y\'(t) + y(t) = 1, y\'(0)=2, y(0)=1')
plt.legend()
plt.savefig('response_full.pdf')
```

### Signal Parts for Sine Excitation Response with Zero Initial Conditions
\begin{equation}
\frac{16}{25} \ddot{y} + \frac{24}{25} \dot{y} + y = \sin(t)
\end{equation}
for $\dot{y}(0)=0$, $y(0)=0$
\begin{equation}
y = \frac{25}{73} \mathrm{e}^{-\frac{3}{4} t} \sin(t) +
\frac{200}{219} \mathrm{e}^{-\frac{3}{4} t} \cos(t) +
\frac{25}{73} \sin(t) -
\frac{200}{219} \cos(t)
\end{equation}

```python
t = np.arange(0,10*np.pi,0.1)
A = 25/3/np.sqrt(73)
phi = np.arctan((200/219)/(25/73))
phi = np.arctan(8/3)  # nicer
hrefsine = A * np.sin(t-phi)
hsin1 = 25/73 * np.exp(-3/4*t) * np.sin(t)
hcos1 = 200/219 * np.exp(-3/4*t) * np.cos(t)
hsin2 = 25/73 * np.sin(t)
hcos2 = -200/219 * np.cos(t)
hresp = hsin1 + hcos1 + hsin2 + hcos2
plt.figure(figsize=(8,4))
plt.plot(t,hresp,'-',label='full response $y(t)$',lw=4, color='C0')
plt.plot(t,hsin1,'-',label='damped sine',lw=1, color='C1')
plt.plot(t,hcos1,'-',label='damped cosine',lw=1, color='C2')
plt.plot(t,hsin2,'-',label='sine',lw=1, color='C5')
plt.plot(t,hcos2,'-',label='cosine',lw=1, color='C4')
plt.plot(t,hrefsine,':',label='0.975 sin(t-1.212)',lw=2, color='C3')
plt.plot([phi, phi],[-1, 0],color='k')
plt.xlabel('t / s')
plt.ylabel('y(t)')
plt.grid(True)
plt.xlim((0,30))
plt.ylim((-1,1))
tick = np.arange(0,11)
tick_label = tick.astype(str)
s = '$\pi$'
tick_label = [tick + s for tick in tick_label]
plt.xticks(tick*np.pi, tick_label)
plt.title('ODE: 16/25 y\'\'(t)+ 24/25 y\'(t) + y(t) = $\sin(t)$, y\'(0)=0, y(0)=0')
plt.legend(loc='lower center')
plt.savefig('sine_excitation_response.pdf')
print(A,phi)
```

## Sympy Computations

with code taken from
https://github.com/spatialaudio/signals-and-systems-lecture/blob/master/systems_time_domain/network_analysis.ipynb

```python
sp.init_printing()
t, L, R, C = sp.symbols('t L R C', real=True)
x = sp.Function('x')(t)
y = sp.Function('y')(t)
ode = sp.Eq(L*C*y.diff(t, 2) + R*C*y.diff(t) + y, x)
RLC = {R: 3, L: 2, C: sp.Rational('0.32')}  # specific example
```

### Impulse Response / Task a

```python
h_ynyp = sp.dsolve(
    ode.subs(x, sp.DiracDelta(t)).subs(y, sp.Function('h')(t)))
integration_constants = sp.solve((
    h_ynyp.rhs.limit(t, 0, '-').subs(RLC) - 0, # here initial condition y(0-)=0
    h_ynyp.rhs.diff(t).limit(t, 0, '-').subs(RLC) - 0), # here initial condition y'(0-)=0
    ['C1', 'C2'])
print(integration_constants)
h = h_ynyp.subs(integration_constants)
print('h(t) is the particular solution yp or the full solution y for zero-initial conditions using the lhs limit:')
sp.trigsimp(h.rhs.subs(RLC)).expand()
```

This resolves to $h(t) = \frac{25}{16} \cdot \mathrm{e}^{-\frac{3}{4} t} \sin(t)$ for $t\geq0$

```python
sp.plot(h.rhs.subs(RLC), (t,0,10), ylabel=r'h(t)',
        title='impulse response', axis_center=(0,0));
```

### Step Response / Task b

```python
heps_ynyp = sp.dsolve(
    ode.subs(x, 1).subs(y, sp.Function('heps')(t)))

integration_constants = sp.solve((
    heps_ynyp.rhs.limit(t, 0, '+-').subs(RLC) - 0,  # here initial condition y(0)=0
    heps_ynyp.rhs.diff(t).limit(t, 0, '+-').subs(RLC) - 0), # here initial condition y'(0)=0
    ['C1', 'C2'])

heps = heps_ynyp.subs(integration_constants)
sp.trigsimp(heps.rhs.subs(RLC)).expand()
```

This resolves to $h_\epsilon(t) = 1 - \mathrm{e}^{-\frac{3}{4} t} \cdot
\left(\frac{3}{4} \sin(t) + \cos(t)\right)$ for $t \geq 0$

```python
sp.plot(heps.rhs.subs(RLC), (t,0,10), ylabel=r'h$_\epsilon$(t)',
        title='step response', axis_center=(0,0));
```

### No Excitation and Non-Zero Initial Condition / Task c

```python
ynyp = sp.dsolve(
    ode.subs(x, 0).subs(y, sp.Function('y')(t)))

integration_constants = sp.solve((
    ynyp.rhs.limit(t, 0, '+-').subs(RLC) - 1,  # here initial condition y(0)=1
    ynyp.rhs.diff(t).limit(t, 0, '+-').subs(RLC) - 2), # here initial condition y'(0)=2
    ['C1', 'C2'])

y = ynyp.subs(integration_constants)
sp.trigsimp(y.rhs.subs(RLC)).expand()
```

This resolves to $y(t) = \mathrm{e}^{-\frac{3}{4} t} \cdot \left( \frac{11}{4} \sin(t) + \cos(t)\right)$ for $t\geq 0$

```python
sp.plot(y.rhs.subs(RLC), (t,0,10), ylabel=r'y(t)',
        title='no excitation with initial conditions', axis_center=(0,0));
```

### Step Excitation and Non-Zero Initial Condition / Task d

```python
ynyp = sp.dsolve(
    ode.subs(x, 1).subs(y, sp.Function('y')(t)))

integration_constants = sp.solve((
    ynyp.rhs.limit(t, 0, '+-').subs(RLC) - 1,  # here initial condition y(0)=1
    ynyp.rhs.diff(t).limit(t, 0, '+-').subs(RLC) - 2), # here initial condition y'(0)=2
    ['C1', 'C2'])

y = ynyp.subs(integration_constants)
sp.trigsimp(y.rhs.subs(RLC)).expand()
```

This resolves to $y(t) = 1+\mathrm{e}^{-\frac{3}{4} t} \, 2 \sin(t)$ for $t \geq 0$

```python
sp.plot(y.rhs.subs(RLC), (t,0,10), ylabel=r'y(t)',
        title='step excitation with initial conditions', axis_center=(0,0));
```

### Sine Excitation / Task e

```python
hsin_ynyp = sp.dsolve(
    ode.subs(x, sp.sin(t)).subs(y, sp.Function('hsin')(t)))

integration_constants = sp.solve((
    hsin_ynyp.rhs.limit(t, 0, '+-').subs(RLC) - 0,  # here initial condition y(0)=0
    hsin_ynyp.rhs.diff(t).limit(t, 0, '+-').subs(RLC) - 0),  # here initial condition y'(0)=0
    ['C1', 'C2'])

hsin = hsin_ynyp.subs(integration_constants)
sp.trigsimp(hsin.rhs.subs(RLC)).expand()
```

$y(t) = \frac{25}{73} \mathrm{e}^{-\frac{3}{4} t} \sin(t) +
\frac{200}{219} \mathrm{e}^{-\frac{3}{4} t} \cos(t) +
\frac{25}{73} \sin(t) -
\frac{200}{219} \cos(t)$ for $t\geq 0$

```python
sp.plot(hsin.rhs.subs(RLC), (t,0,10), ylabel=r'y(t)',
        title='sine excitation with zero initial conditions', axis_center=(0,0));
```

### Transfer Function

Transfer function is the Laplace transform of the impulse response $h(t)$

\begin{align}
H(s) = \mathcal{L}\{h(t)\}= \int\limits_{-\infty}^{\infty} h(t) \mathrm{e}^{-s t} \mathrm{d} t = \frac{1}{\frac{16}{25} s^2 + \frac{24}{25} s + 1}
\end{align}

Since $h(t)$ starts at 0 only, we only need to integrate from $0$ to $\infty$.

```python
s = sp.symbols('s')
H = sp.Function('H')(s)
H = sp.integrate(h.rhs.subs(RLC)*sp.exp(-s*t), (t, 0, sp.oo), conds='none').simplify()
H
```

### Frequency Response

For $s = \mathrm{j}\omega$ we evaluate the frequency response (i.e. the **steady state** with respect to amplitude and phase change between output and input of the system/ODE). We can do this for every desired angular frequency $\omega$.

So let us plot amplitude (magnitude) and phase over $\omega$.

```python
w = sp.symbols('omega', real=True)
Hjw = H.subs(s, sp.I * w)
```

```python
sp.plot(sp.Abs(H.subs(s, sp.I*w)), (w, -5, 5),
        ylabel=r'$|H(\mathrm{j} \omega)|$',
        xlabel=r'$\omega$', center=(0,0));
```

```python
sp.plot(sp.arg(H.subs(s, sp.I*w)), (w, -5, 5),
        ylabel=r'$\angle H(\mathrm{j} \omega)$ / rad',
        xlabel=r'$\omega$', center=(0,0));
```

Magnitude at $\omega=1$

```python
sp.Abs(Hjw.subs(w,1))
```

Phase in radian at $\omega=1$

```python
sp.arg(Hjw.subs(w,1))
```

```python
-np.arctan(8/3)
```

```python
w0 = 5/4
D = 3/5

Q = 1/(2*D)
print('D=',D,'Q=',Q)

w = np.linspace(-10,10,2**10)
s = 1j*w  # eval Fourier transform
H = 1 / (s**2/w0**2 + 2*D/w0*s + 1)

# for omega = 1
wdes = 1
Hdes = 1 / ((1j*wdes)**2/w0**2 + 2*D/w0*(1j*wdes) + 1)
np.abs(Hdes)
np.angle(Hdes)

plt.figure(figsize=(8,5))
plt.subplot(2,1,1)
plt.plot(w, np.abs(H), 'C0', lw=2, label=r'$|H(\,\mathrm{j}\,\omega)|$')
plt.plot(wdes, np.abs(Hdes), 'C3o', label=r'$|H(\,\mathrm{j}\,[\omega=1])|=$ % 4.3f' % np.abs(Hdes))
#plt.xlabel(r'$\omega$ / (rad/s)')
plt.ylabel(r'magnitude $|H(\mathrm{j}\omega)|$')
plt.xticks(np.arange(-10,11))
plt.yticks(np.arange(0,12)/10)
plt.xlim(-10,10)
plt.ylim(0,1.1)
plt.legend()
plt.grid(True)

plt.subplot(2,1,2)
plt.plot(w, np.angle(H)/np.pi, 'C0', lw=2, label=r'$\angle H(\,\mathrm{j}\,\omega) \, / \, \pi$')
plt.plot(wdes, np.angle(Hdes)/np.pi, 'C3o', label=r'$\angle H(\,\mathrm{j}\,[\omega=1])=$ % 4.3f $\pi$' % (np.angle(Hdes)/np.pi))
plt.xlabel(r'$\omega$ / (rad/s)')
plt.ylabel(r'normalized phase $\angle H(\mathrm{j}\omega) \, / \, \pi$')
plt.xticks(np.arange(-10,11))
plt.yticks(np.arange(-10,10)/5)
plt.xlim(-10,10)
plt.ylim(-1,1)
plt.legend()
plt.grid(True)
plt.savefig('frequency_response_mag_phase.pdf')
```

## Copyright

This tutorial is provided as Open Educational Resource (OER), to be found at
https://github.com/spatialaudio/signals-and-systems-exercises
accompanying the OER lecture
https://github.com/spatialaudio/signals-and-systems-lecture.
Both are licensed under a) the Creative Commons Attribution 4.0 International
License for text and graphics and b) the MIT License for source code.
Please attribute material from the tutorial as *Frank Schultz,
Continuous- and Discrete-Time Signals and Systems - A Tutorial Featuring
Computational Examples, University of Rostock* with
``main file, github URL, commit number and/or version tag, year``.