{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# This cell is added by sphinx-gallery\n# It can be customized to whatever you like\n%matplotlib inline"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n\nVibrational dynamics\n====================\n\n*Technical details are available in the API documentation:*\n:doc:`code/api/api/strawberryfields.apps.qchem.dynamics`\n\nMolecules vibrate! In simple cases, like molecular oxygen, atoms\ncan only vibrate along a single axis: O=O --> O===O --> O=O --> O===O. For larger\nmolecules consisting of many atoms, vibrations can become much more complicated and fascinating.\nA useful tool for understanding vibrations is the concept of *normal* modes. These are patterns of\nvibration such that all components of a system move synchronously and with the same frequency,\neven if they do so in different directions. If a molecule is vibrating in a normal mode, its\nvibrational dynamics are straightforward: it continues to vibrate in the same pattern.\n\nMore interesting is the situation where a polyatomic molecule vibrates in a pattern that is\nnot a normal mode, e.g., when the vibration is localized on specific atomic positions or chemical\nbonds. These patterns are referred to as *local* modes, and their evolution in time is more\nchallenging to predict and analyze. As an illustration, consider the case of the water molecule\nshown in the figure below. Water has three vibrational normal modes: the symmetric and asymmetric\nstretching modes, and a bending mode. These normal modes can be transformed to three local modes:\ntwo stretching modes describing the vibrations of the single OH bonds, and a bending mode. Note that\nthe bending mode is already localized.\n\n![](../_static/water.png)\n\n :width: 400px\n :align: center\n\n|\n\nThe dynamics of the vibrational excitations in the normal and local modes of molecules are important\nto understand the mechanism of chemical reactions and energy transport [[#sparrow2018simulating]_],\n[[#jahangiri2020algorithm]_]. For instance, the time-dependent accumulation of vibrational energy in\na specific stretching mode can break chemical bonds or change the reactivity of a molecule.\n\nWithin the so-called harmonic approximation, normal vibrational modes are orthogonal to each\nother and excitations in one mode do not lead to excitations in the other modes. Local modes, on the\nother hand, are not orthogonal and the time evolution of vibrational excitations in local modes is\nnot trivial. Simulation of the dynamics of vibrations excitations in local modes requires solving\nthe time-dependent Schr\u00f6dinger equation, which is computationally expensive with classical methods.\n\nIn this tutorial, we explain how to use Gaussian Boson Sampling (GBS) for simulating the time\nevolution of vibrational excitations in local modes [[#sparrow2018simulating]_],\n[[#jahangiri2020algorithm]_]. Here's the main idea. First, we exploit a correspondence\nbetween vibrational modes in a molecule and optical modes in a photonic quantum computer.\nIn this case, photons in the device represent vibrational quanta. Second, given an\ninitial state of the molecule in the basis of local modes, we transform the system to the basis of\nnormal modes, where time evolution can be described more simply. This local-to-normal transformation\nis given by a unitary operation which can be implemented with an interferometer. Once\ntime evolution has been performed, we convert back to the local basis and probe the local modes\nto determine the number of vibrational quanta.\n\nHere's the algorithm in more detail:\n\n#. Assign each local mode in the molecule to a corresponding optical mode in the GBS device.\n#. Prepare an initial state in which some local modes are vibrationally excited.\n#. Apply the unitary $U^{\\dagger}$ to transform the local modes to the normal basis.\n#. Perform time evolution of the quantum state by applying the transformation\n $\\exp(-i \\hat{H} t / \\hbar)$. Here $\\hat{H} = \\sum_i \\hbar \\omega_i a_i^\\dagger\n a_i$ defines a Hamiltonian of independent quantum harmonic oscillators, $\\omega_i$ is the\n vibrational frequency of the $i$-th normal mode, $t$ is time, and $\\hbar$ is\n Planck's constant.\n#. Apply the unitary $U$ to transform the normal modes to the local modes.\n#. Measure the number of photons in each mode.\n\nThe distribution of the photons in the final modes determines the number of vibrational quanta in\nthe local modes. The GBS setup that corresponds to this algorithm is schematically illustrated\nbelow.\n\n![](../_static/dynamics_algo.png)\n\n :width: 300px\n :align: center\n\nVibrational dynamics of water\n-----------------------------\nWe are now ready to simulate vibrational quantum dynamics with GBS. In this tutorial,\nwe will focus on one of the most iconic molecules of all time: water \ud83c\udf0a. We\nfirst import the modules we need.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt\nimport numpy as np\nimport strawberryfields as sf\nfrom strawberryfields.apps import qchem"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We also need the molecular parameters that are used to program the GBS device. These\nparameters are (i) the normal-to-local unitary $U$, and (ii) the vibrational frequencies of\nthe normal modes [[#sparrow2018simulating]_]. Following common conventions in quantum chemistry,\nthese frequencies are quoted in units of $\\mbox{cm}^{-1}$. The vibrational normal\nmodes and frequencies can be obtained from electronic structure calculations. The procedure for\ncomputing the normal-to-local unitary is explained in [[#jacob2009localizing]_].\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"w = sf.apps.data.Water(0).w\nU = sf.apps.data.Water(0).U"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We now define an engine and initialize our quantum program. We also need to define the number of\nmodes and a cutoff dimension $D$ which determines the restricted set of number states\n$\\{|0\\rangle , ..., |D \u2212 1\\rangle\\}$ for each mode [[#killoran2019strawberry]_].\nWe use Fock states as the initial state in the GBS circuit, which represent states with a fixed\nnumber of vibrational quanta.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"modes = 3\neng = sf.Engine(\"fock\", backend_options={\"cutoff_dim\": 5})\nprog = sf.Program(modes)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We prepare an initial Fock state in which the second local OH stretching mode is populated with\none vibrational quantum, corresponding to a single photon in the GBS device.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"input_state = [0, 1, 0]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We define the time (in femtoseconds) and the number of samples to be generated. First we\ngenerate 10 samples at t = 70 femtoseconds.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"t = 70\nn_samples = 10"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We use the function :func:`~strawberryfields.apps.qchem.dynamics.TimeEvolution` to\nevolve the quantum state in time. Given a set of frequencies and a time of evolution\n$t$, this function applies a set of rotation gates on the quantum\nstate, which are parameterized according to the transformation $\\exp(-i \\hat{H} t / \\hbar)$.\nThe normal-to-local transformation unitary is mapped to an interferometer. Note that we apply\nthe transpose first, then convert back without transposing.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# to make samples reproducible\nnp.random.seed(seed=42)\n\nsamples = []\n\nwith prog.context as q:\n for i in range(modes):\n sf.ops.Fock(input_state[i]) | q[i]\n sf.ops.Interferometer(U.T) | q\n qchem.dynamics.TimeEvolution(w, t) | q\n sf.ops.Interferometer(U) | q\n sf.ops.MeasureFock() | q\n\nfor _ in range(n_samples):\n samples.append(eng.run(prog).samples[0].tolist())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's take a look at the samples.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"print(*samples, sep=\"\\n\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now, let's compute the mean photon numbers in each mode.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"print(np.mean(samples, axis=0))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"At time 70 femtoseconds, the excitations are also observed in the first local OH stretching mode.\nWe can create a sampling function based on the circuit implemented above and use it to generate\nsamples at any desired time.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def sample(input_state, t, w, U, n_samples):\n modes = len(U)\n samples = []\n eng = sf.Engine(\"fock\", backend_options={\"cutoff_dim\": 5})\n prog = sf.Program(modes)\n\n with prog.context as q:\n for i in range(modes):\n sf.ops.Fock(input_state[i]) | q[i]\n sf.ops.Interferometer(U.T) | q\n qchem.dynamics.TimeEvolution(w, t) | q\n sf.ops.Interferometer(U) | q\n sf.ops.MeasureFock() | q\n\n for _ in range(n_samples):\n samples.append(eng.run(prog).samples[0].tolist())\n return samples"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can repeat the sampling at different times and plot the probability of observing excitations\nin the local vibrational modes of water as a function of time. Since the sampling process is\ntime-consuming, we import pre-generated samples from the data module.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"samples = [sf.apps.data.Water(t=time)[:] for time in range(0, 270, 10)]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can now compute and plot the probability of observing one vibrational quantum in each local\nmode as a function of time.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"prob_1 = np.array([s.count([1, 0, 0]) / len(s) for s in samples])\nprob_2 = np.array([s.count([0, 1, 0]) / len(s) for s in samples])\nprob_3 = np.array([s.count([0, 0, 1]) / len(s) for s in samples])\n\nplt.ylabel(\"Probability\")\nplt.xlabel(\"Time (fs)\")\nplt.rc(\"font\", size=14)\nplt.plot(range(0, 270, 10), prob_1, \"o--\", color=\"#1f77b4\", label=\"1st OH stretching\")\nplt.plot(range(0, 270, 10), prob_2, \"o--\", color=\"#2ca02c\", label=\"2nd OH stretching\")\nplt.plot(range(0, 270, 10), prob_3, \"o--\", color=\"#bcbd22\", label=\"HOH bending\")\nplt.legend(frameon=False, prop={\"size\": 10})\nplt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The probability of observing one vibrational quantum in the local OH modes oscillates with time.\nExcitations are now observed in the first local mode although this mode was not excited initially.\nNote that the probability of excitation in the bending mode is always zero as this mode is\ndecoupled from the local stretching modes.\n\nYou can use the techniques outlined in this tutorial to simulate the vibrational dynamics for any\ninput state. For instance, you can try it for a state with two vibrational quanta. The techniques\ncan also be implemented in more sophisticated algorithms to engineer the vibrational state of a\nmolecule.\n\n\nReferences\n----------\n\n.. [#sparrow2018simulating]\n\n C. Sparrow, E. Mart\u00edn-L\u00f3pez, N. Maraviglia, A. Neville, C. Harrold,\n J. Carolan, Y. N. Joglekar, T. Hashimoto, N. Matsuda, J. L. O\u2019Brien,\n D. P. Tew, and A. Laing. Simulating the Vibrational Quantum Dynamics of Molecules\n using Photonics. Nature, 557:660, 2018.\n\n.. [#jahangiri2020algorithm]\n\n S. Jahangiri, J. M. Arrazola, N. Quesada, and A. Delgado. Quantum\n Algorithm for Simulating Molecular Vibrational Excitations. arXiv, 2020.\n\n.. [#jacob2009localizing]\n\n C. R. Jacob and M. Reiher. Localizing Normal Modes in Large Molecules. J. Chem. Phys.\n 130:084106, 2009.\n\n.. [#killoran2019strawberry]\n\n N. Killoran, J. Izaac, N. Quesada, V. Bergholm, M. Amy, and C.\n Weedbrook. Strawberry Fields: A Software Platform for Photonic Quantum Computing. Quantum,\n 3:129, 2019.\n\n"
]
}
],
"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.7.15"
}
},
"nbformat": 4,
"nbformat_minor": 0
}