Skip to content

Commit

Permalink
added codes
Browse files Browse the repository at this point in the history
  • Loading branch information
mhjensen committed Dec 5, 2023
1 parent a665656 commit 207ac0e
Show file tree
Hide file tree
Showing 6 changed files with 2,386 additions and 0 deletions.
320 changes: 320 additions & 0 deletions doc/Programs/HamiltonianSimulation.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,320 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"$$ \\newcommand{\\ket}[1]{\\left|{#1}\\right\\rangle} $$\n",
"$$ \\newcommand{\\bra}[1]{\\left\\langle{#1}\\right|} $$"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Hamiltonian Simulation\n",
"The dynamics of many simple quantum systems, with time-independent Hamiltonian H, can be found in the Schrödinger equation\n",
"\n",
"$$\n",
"i\\hbar \\frac{d}{dt}\\ket{\\psi} = H\\ket{\\psi}\n",
"$$\n",
"\n",
"with the general solution\n",
"\n",
"$$\n",
"\\ket{\\psi(t)} = e^{-\\frac{i}{\\hbar}Ht}\\ket{\\psi(0)}\n",
"$$\n",
"\n",
"We can write this in terms of a unitary operator\n",
"\n",
"$$\n",
" U = e^{-\\frac{i}{\\hbar}Ht}\n",
"$$\n",
"\n",
"Since $\\ket{\\psi}$ will be an eigenvector of $H$ with eigenvalue $E$, we have \n",
"\n",
"$$\n",
" U\\ket{\\psi_k} = e^{-\\frac{i}{\\hbar}E_kt}\\ket{\\psi_k}\n",
"$$\n",
"\n",
"Clearly there should be a way to implement this on a quantum computer, as the eigenvalue is just a phase factor. However we encounter some problems quite early on, usually the Hamiltonian can be written in terms of individual sums (e.g. onebody and twobody part)\n",
"\n",
"$$\n",
"H = \\sum_k H_K\n",
"$$\n",
"\n",
"Which gives\n",
"\n",
"$$\n",
" U = e^{-\\frac{i}{\\hbar}Ht} = e^{-\\frac{i}{\\hbar}\\sum_k H_kt}\n",
"$$\n",
"\n",
"We would like to express this in terms of products, rather than sums. This way the operator can be written as the product of some number of other operators and thus the quantum computation could be done instead of the infinite sum that is the exponent. The Baker-Campbell-Hausdorff expansion gives such an expression, but comes with an infite sum of commutators, and in most cases $[H_k,H_{k'}]\\neq 0$. Luckily we can truncate the expression, hopefully without loosing too much information.\n",
"\n",
"$$\n",
" U = e^{-\\frac{i}{\\hbar}Ht} \\approx \\left(\\prod_k e^{-\\frac{i}{\\hbar}\\frac{H_kt}{\\rho}}\\right)^\\rho + O\\left(\\frac{t^2}{\\rho^2}\\right) \\approx \\prod_k U_k\n",
"$$ \n",
"\n",
"where $\\rho$ is the trotter number. By letting $\\Delta t = \\frac{t}{\\rho}$ we can make a good approximation, that gets better the longer it acts. Next we want to implement this as a quantum algorithm. Assume the Hamiltonian to be on second quantized form we have\n",
"\n",
"$$\n",
"H = \\sum_{pq} h_{pq} a_p^\\dagger a_q + \\sum_{pqrs} v_{pqrs} a_p^\\dagger a_q^\\dagger a_s a_r\n",
"$$\n",
"\n",
"This can be written in terms of Pauli operators using the Jordan-Wigner transformation or the Braviy-Kitaev transformation. The Jordan-Wigner transformation yields\n",
"\n",
"$$\n",
" a_i^\\dagger = \\left( \\prod_{k=1}^{i-1} \\sigma_z^k \\right)\\sigma_+^i, \\quad a_i = \\left( \\prod_{k=1}^{i-1} \\sigma_z^k \\right)\\sigma_-^i\n",
"$$\n",
"\n",
"without having to change basis. The Braviy-Kitaev transformation is dependent on changing basis, but in turns it can be implemented using less gates than Jordan-Wigner. Lastly we need a way to implement the exponent\n",
"\n",
"$$\n",
"e^{-\\frac{i}{\\hbar}Ht}\n",
"$$\n",
"\n",
"Firstly we take notice of the relation\n",
"\n",
"$$\n",
"e^{-\\frac{i}{\\hbar}Ot}\\ket{\\Phi} = \\left(\\cos(t)I - i \\sin(t)O\\right)\\ket{\\Phi} = \\left(\\cos(t)I - i \\sin(t)\\lambda_O \\right)\\ket{\\Phi} = e^{-\\frac{i}{\\hbar}\\lambda_Ot}\\ket{\\Phi}\n",
"$$\n",
"\n",
"given some operator $O$ with eigenvalue $\\lambda_O$. Next we see the how a transformation has an affect on this state\n",
"\n",
"$$\n",
"U^\\dagger e^{-\\frac{i}{\\hbar}Ot}U = U^\\dagger \\left(\\cos(t)I - i\\sin(t)O \\right) U = \\left(\\cos(t)U^\\dagger I U - i\\sin(t)U^\\dagger O U \\right) = \\left(\\cos(t)I - i\\sin(t)U^\\dagger O U \\right) = e^{-iU^\\dagger O U t}\n",
"$$\n",
"\n",
"Decomposing our Hamiltonian so that $H = U^\\dagger O U$ in a complex exponent thus have a simple way of being implemented given above. Since this will be composed of the pauli operators and ladder operators given above, where\n",
"\n",
"$$\n",
"\\sigma_+ = \\frac{1}{2}(\\sigma_x + i\\sigma_y), \\quad \\sigma_- = \\frac{1}{2}(\\sigma_x - i\\sigma_y)\n",
"$$\n",
"\n",
"and introduce the rotation operator\n",
"\n",
"$$\n",
"R_n(\\theta) = cos\\left(\\frac{\\theta}{2}\\right)I - i\\ sin\\left(\\frac{\\theta}{2}\\right)(n_x\\sigma_x + n_y\\sigma_y + n_z\\sigma_z)\n",
"$$\n",
"\n",
"with the following relations\n",
"\n",
"$$\n",
"\\sigma_x = R_y(\\frac{\\pi}{2})\\sigma_zR_y(-\\frac{\\pi}{2}), \\quad \\sigma_x = -R_z(\\frac{\\pi}{2})\\sigma_yR_z(-\\frac{\\pi}{2})\n",
"\\\\\n",
"\\sigma_y = R_z(\\frac{\\pi}{2})\\sigma_xR_z(-\\frac{\\pi}{2}), \\quad \\sigma_y = -R_x(\\frac{\\pi}{2})\\sigma_zR_x(-\\frac{\\pi}{2})\n",
"\\\\\n",
" \\sigma_x = H\\sigma_zH, \\quad \\sigma_y = R_z(\\frac{\\pi}{2})H\\sigma_z H R_z(-\\frac{\\pi}{2})\n",
"$$\n",
"\n",
"where $H$ is the hadamard gate. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Next to implement, e.g. the two qubit case, $e^{-i\\sigma_z \\otimes \\sigma_z t}$ we can use the circuit below with an aditional ancilla qubit:"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<pre style=\"word-wrap: normal;white-space: pre;background: #fff0;line-height: 1.1;font-family: &quot;Courier New&quot;,Courier,monospace\"> \n",
"q0_0: |0>──■───────────────────────■──\n",
" │ │ \n",
"q0_1: |0>──┼────■─────────────■────┼──\n",
" ┌─┴─┐┌─┴─┐┌───────┐┌─┴─┐┌─┴─┐\n",
"q0_2: |0>┤ X ├┤ X ├┤ Rz(1) ├┤ X ├┤ X ├\n",
" └───┘└───┘└───────┘└───┘└───┘</pre>"
],
"text/plain": [
"<qiskit.visualization.text.TextDrawing at 0x7f778e536630>"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import qiskit as qk\n",
"import numpy as np\n",
"\n",
"n = 2\n",
"t = 1\n",
"\n",
"qr = qk.QuantumRegister(n+1)\n",
"qc = qk.QuantumCircuit(qr)\n",
"qc.cx(qr[0],qr[-1])\n",
"qc.cx(qr[1],qr[-1])\n",
"qc.rz(t,qr[-1])\n",
"qc.cx(qr[1],qr[-1])\n",
"qc.cx(qr[0],qr[-1])\n",
"qc.draw()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Where we have utilized two simple tricks. First we know that $\\sigma_z$ have eigenvalues $1$ and $-1$, so acting with multiple $\\sigma_z$ gates only changes the unit sign of the eigenvalue. Next we have that the $R_z$ gate in matrix form look like\n",
"\n",
"$$\n",
"\\begin{equation}\n",
" R_z(\\theta) = \n",
" \\begin{bmatrix}\n",
" e^{-i\\theta} & 0 \\\\\n",
" 0 & e^{i\\theta} \\\\\n",
" \\end{bmatrix}\n",
"\\end{equation}\n",
"$$\n",
"\n",
"Since this only gives a phase, we can \"store\" the parity of the qubits in the ancilla qubit and then do the rotation, as this will have the same effect as initial problem.\n",
"\n",
"However, as we should aim for more efficient implementations of all circuit elements, we see that there can be done some adjustments to this. First we recognizing that we do not actually need the ancilla qubit. By storing the parity in one of the qubits and doing the rotation on this, gives the equiavalent action.\n",
"Next we see that in the case of the two qubits being acted on by $\\sigma_x$ gates we need to act with hadamard gates on each side of the $\\sigma_z$. this can be shortened by recognizing that the CNOT gate is equivalent to a swap gate and a CNOT (that is, reversed order CNOT) with hadamards on each side. Implementing this in the first circuit gets rid of the initial hadamard gates and, and we are only left with hadamard gates on each side of the $R_z$ gate which is equal to $HR_xH=R_z$. So instead of acting with $2n$ hadamard gates, we have to act with $2$ hadamard gates.\n",
"For the case with $\\sigma_y$ gates, we still get the same reduction of hadamard gates, but still have to act with the other rotation gates."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Example:\n",
"# Heisenberg model\n",
"\n",
"The Heiseinberg model is a one-dimensional chain of spin $\\frac{1}{2}$ particles, where there are only one degree of freedom being the spin. The direction of the spins and the relationship between neighbouring spins determine the energy of the system. The Hamiltonian is given by\n",
"\n",
"$$\n",
" H = h \\sum_k \\sigma_k^z \\pm J\\sum_k \\vec{\\sigma_k} \\cdot \\vec{\\sigma_{k+1}}\n",
"$$\n",
"\n",
"As we want negative eigenvalues we must alter the Hamiltonian so that $H' = H -E_{max}$. We write this in terms of dimensionless variables, by dividing with $\\pm J$\n",
"\n",
"$$\n",
" \\frac{H'}{\\pm J} = h' \\sum_k \\sigma_k^z + \\sum_k \\vec{\\sigma_k} \\cdot \\vec{\\sigma_{k+1}} - E_{max}'\n",
"$$\n",
"\n",
"with $h'=\\frac{h}{\\pm J}$ and $E_{max}'=\\frac{E_{max}}{\\pm J}$.\n",
"\n",
"Next we write out $\\sigma$ vector dot products as\n",
"\n",
"$$\n",
"\\vec{\\sigma_k} \\cdot \\vec{\\sigma_{k+1}} = \\sigma_k^x\\sigma_{k+1}^x + \\sigma_k^y\\sigma_{k+1}^y + \\sigma_k^z\\sigma_{k+1}^z\n",
"$$\n",
"\n",
"Clearly our evolution operator will have four sums."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"##### First sum: $h'\\sum_k \\sigma_k^z$\n",
"We see that \n",
"\n",
"$$\n",
"e^{-ih'\\sum_k \\sigma_k^zt} = \\prod_k e^{-ih'\\sigma_k^zt} = \\prod_k R_z(h't)\n",
"$$"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"##### Second sum: $\\sum_k \\sigma_k^x\\sigma_{k+1}^x$\n",
"Next we take advantage of transformation in the exponent mentioned above so that\n",
"\n",
"$$\n",
"e^{-i\\sum_k \\sigma_k^x\\sigma_{k+1}^x t} = \\prod_k U_k^\\dagger e^{-i\\sigma_k^z\\sigma_{k+1}^z t} U_k\n",
"$$\n",
"\n",
"where $e^{-i\\sum_k \\sigma_k^z\\sigma_{k+1}^z t}$ can be implemented using an ancilla qubit as a target for CNOT-gates with the simulation qubits as controls, thus affecting/storing the parity, then apply the $R_z(t)$ rotation on the ancilla, and reverse the CNOT action. From the table above we can choose $U$ as both\n",
"\n",
"$$\n",
"U = H \\otimes H \\quad \\text{or} \\quad U = R_y(-\\frac{\\pi}{2})\\otimes R_y(-\\frac{\\pi}{2})\n",
"$$\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"##### Third sum: $\\sum_k \\sigma_k^y\\sigma_{k+1}^y$\n",
"Repeat the process with $U$\n",
"\n",
"$$\n",
"U = R_x(-\\frac{\\pi}{2}) \\otimes R_x(-\\frac{\\pi}{2})\n",
"$$\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"##### Fourth sum: $\\sum_k \\sigma_k^z\\sigma_{k+1}^z$\n",
"Repeat the process with $U$\n",
"\n",
"$$\n",
"U = I \\otimes I\n",
"$$\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"##### $E_{max}$ term\n",
"Need only to apply the phase $E_{max}t$ to one of the qubits in the circuit."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.8"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Loading

0 comments on commit 207ac0e

Please sign in to comment.