Skip to content

Commit

Permalink
Custom pulse-level simulator (#23)
Browse files Browse the repository at this point in the history
* wip: initial commit of pulsesim code

* refactor: quantum mode as abstract class

* fix: hamiltonian class uses mode instances for non-perturbed terms

* wip: qubit-qubit-cavity hamiltonian experiment

* feat: working qubit-qubit-cavity iswap simulation

* feat: quantum mode collapse operators and expected state fidelity calculations to mesolve

* fix: cavity mediated iswap experiment with exagerrated loss channels

* wip: biased qubit-cavity couplings

* fix: cavity dimension change back to N=10

* feat: add iswap fidelity measure over distribution of initial states

* chore: add tqdm to toml

* feat: new scqubits dir

* style: formatting docstrings
  • Loading branch information
evmckinney9 authored Feb 15, 2024
1 parent a76ac9e commit d01d16e
Show file tree
Hide file tree
Showing 24 changed files with 2,774 additions and 6 deletions.
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ repos:
- id: enforce-notebook-naming

- repo: https://github.com/qoomon/git-conventional-commits
rev: v2.6.5
rev: v2.6.7
hooks:
- id: conventional-commits

- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: "v0.1.8"
rev: "v0.1.15"
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
Expand Down Expand Up @@ -43,7 +43,7 @@ repos:
name: isort (python)

- repo: https://github.com/psf/black
rev: 23.12.0
rev: 24.1.1
hooks:
- id: black-jupyter
language_version: python3.9
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ init:
rm -rf .venv
$(PYTHON_VERSION) -m venv .venv
@$(PIP) install --upgrade pip

$(PIP) install -e .[dev]
@$(PRE_COMMIT) install
@$(PRE_COMMIT) autoupdate
Expand Down
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ version = "0.1.0"
authors = [{ name = "Evan McKinney" }]
requires-python = ">=3.9"
dependencies = [
"tqdm",
"numpy",
"qiskit",
"qutip",
"scqubits",
"weylchamber",
"matplotlib",
"LovelyPlots",
Expand Down
203 changes: 203 additions & 0 deletions src/notebooks/noisy_simulation/05_bloch_channels.ipynb

Large diffs are not rendered by default.

254 changes: 254 additions & 0 deletions src/notebooks/pulse_sim/01_snail_qubit.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# notebook to recreate Mingkang's simulation of qubit-SNAIL coupling gates\n",
"# using my refactored version of his code"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"from qutip import Options\n",
"import qutip as qt\n",
"from pathlib import Path\n",
"import matplotlib.pyplot as plt\n",
"from quantum_logical.pulsesim import QuantumSystem, Pulse\n",
"from quantum_logical.pulsesim.hamiltonian import QubitQubitSNAIL\n",
"\n",
"opts = Options(nsteps=1e6, atol=1e-8, rtol=1e-6)\n",
"p_bar = qt.ui.TextProgressBar() # None"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Better, load from YAML file\n",
"# Ensure the correct path relative to the project root\n",
"project_root = Path(\"/home/evm9/quantum_logical\") # Adjust as necessary\n",
"yaml_file = (\n",
" project_root / \"src/quantum_logical/pulsesim/system_params/system_params.yaml\"\n",
")\n",
"quantum_system = QuantumSystem.from_yaml(yaml_file)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"system_hamiltonian = QubitQubitSNAIL(quantum_system, use_TLS=True, use_RWA=False)\n",
"q1_mode = system_hamiltonian.q1_mode\n",
"q2_mode = system_hamiltonian.q2_mode\n",
"\n",
"# prepare an initial state\n",
"psi0 = quantum_system.prepare_tensor_fock_state([(q2_mode, 1)])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"system_hamiltonian.H"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Define experiment constants\n",
"# define frequency and amplitude ranges\n",
"# drive at qubit-qubit conversion with some detuning\n",
"width_d = 500\n",
"N = 30\n",
"\n",
"detuning_flist = 1000 * np.linspace(-0.01, 0.01, N) # MHz\n",
"flist = 2 * np.pi / 1000 * (detuning_flist) + abs(q1_mode.freq - q2_mode.freq)\n",
"alist = np.linspace(0, 30, N)\n",
"args = {\"shape\": Pulse.smoothbox, \"shape_params\": {\"t0\": 0, \"width\": width_d}}\n",
"t_list = np.linspace(0, width_d, 500)\n",
"\n",
"# plot an example pulse from the experiment to verify its shape\n",
"omega_p = flist[int(N / 2)]\n",
"amp_p = alist[int(N / 2)]\n",
"pulse = Pulse(omega=omega_p, amp=amp_p)\n",
"\n",
"# Plot the Gaussian pulse shape\n",
"Pulse.plot_pulse([(pulse, args)], t_list)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# collapse operators\n",
"c_ops = []\n",
"for mode in quantum_system.modes:\n",
" c_ops.append(mode.collapse_operators(quantum_system))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def simulation_task(freq_amp_tuple):\n",
" freq, amp = freq_amp_tuple\n",
" pulse = Pulse(omega=freq, amp=amp)\n",
" H = system_hamiltonian.driven(pulse)\n",
" solve_result = qt.mesolve(H, psi0, t_list, c_ops, args=args, options=opts)\n",
" final_state = solve_result.states[-1]\n",
" ground_state_populations = [\n",
" quantum_system.mode_population_expectation(final_state, mode, 0)\n",
" for mode in quantum_system.modes\n",
" ]\n",
" return ground_state_populations\n",
"\n",
"\n",
"# Prepare the parameters for parallel execution\n",
"freq_amp_pairs = [(f, a) for f in flist for a in alist]\n",
"\n",
"# Run the simulations in parallel\n",
"results = qt.parallel.parallel_map(simulation_task, freq_amp_pairs, progress_bar=True)\n",
"\n",
"# Process results\n",
"ground_state_populations = np.zeros((len(quantum_system.modes), len(alist), len(flist)))\n",
"for idx, (freq, amp) in enumerate(freq_amp_pairs):\n",
" freq_idx = np.where(flist == freq)[0][0]\n",
" amp_idx = np.where(alist == amp)[0][0]\n",
"\n",
" populations = results[idx]\n",
" for k, pop in enumerate(populations):\n",
" ground_state_populations[k, amp_idx, freq_idx] = pop"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Prepare the plot\n",
"fig, axes = plt.subplots(\n",
" 1, len(quantum_system.modes), figsize=(len(quantum_system.modes) * 4, 4)\n",
")\n",
"\n",
"# Conversion factor from radian frequency to GHz\n",
"rad_to_GHz = 1 / (2 * np.pi)\n",
"\n",
"# Define the number of ticks for the detuning x-axis\n",
"n_xticks = 5 # Adjust the number of ticks as needed\n",
"\n",
"# Plot data for each mode\n",
"for k, mode in enumerate(quantum_system.modes):\n",
" im = axes[k].imshow(\n",
" ground_state_populations[k],\n",
" # extent=[flist[0] * rad_to_GHz, flist[-1] * rad_to_GHz, alist[0], alist[-1]],\n",
" extent=[detuning_flist[0], detuning_flist[-1], alist[0], alist[-1]],\n",
" aspect=\"auto\",\n",
" origin=\"lower\",\n",
" vmin=0.0,\n",
" vmax=1.0, # Set color bar scale from 0.0 to 1.0\n",
" )\n",
" axes[k].set_title(f\"Mode: {mode.name}\")\n",
" # axes[k].set_xlabel(\"Frequency (GHz)\")\n",
" axes[k].set_xlabel(\"Detuning (MHz)\")\n",
" axes[k].set_ylabel(\"Amplitude (a.u.)\")\n",
"\n",
" # Customize x-axis ticks\n",
" # xticks = np.linspace(flist[0] * rad_to_GHz, flist[-1] * rad_to_GHz, n_xticks)\n",
" xticks = np.linspace(detuning_flist[0], detuning_flist[-1], n_xticks)\n",
" axes[k].set_xticks(xticks)\n",
" axes[k].set_xticklabels([f\"{x:.2f}\" for x in xticks]) # Format the tick labels\n",
"\n",
" # Add color bar\n",
" cbar = fig.colorbar(\n",
" im, ax=axes[k], orientation=\"vertical\", label=\"Ground State Population\"\n",
" )\n",
" cbar.set_ticks(np.linspace(0, 1, 5)) # Customize color bar ticks\n",
"\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# find the frequency and amplitude that maximized population in q1_mode\n",
"# this will be our calibrated iSWAP frequency and amplitude\n",
"max_pop = np.max(ground_state_populations[0])\n",
"max_pop_idx = np.where(ground_state_populations[0] == max_pop)\n",
"max_pop_freq = flist[max_pop_idx[1][0]]\n",
"max_pop_amp = alist[max_pop_idx[0][0]]\n",
"print(f\"Max population: {max_pop:.2f}\")\n",
"print(f\"Max population frequency: {max_pop_freq:.2f}\")\n",
"print(f\"Max population amplitude: {max_pop_amp:.2f}\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"pulse = Pulse(omega=max_pop_freq, amp=max_pop_amp)\n",
"H = system_hamiltonian.driven(pulse)\n",
"\n",
"e_ops = [quantum_system.modes_num[m] for m in quantum_system.modes]\n",
"solve_result = qt.mesolve(H, psi0, t_list, args=args, options=opts, e_ops=e_ops)\n",
"\n",
"# Plot the state evolution (<n> vs time) for each mode (one plot total)\n",
"fig, ax = plt.subplots(figsize=(6, 4))\n",
"for k, mode in enumerate(quantum_system.modes):\n",
" ax.plot(t_list, solve_result.expect[k], label=mode.name)\n",
"ax.set_xlabel(\"Time (dt)\")\n",
"ax.set_ylabel(\"Mode Occupation\")\n",
"ax.legend()\n",
"plt.show()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"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.9.17"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Loading

0 comments on commit d01d16e

Please sign in to comment.