diff --git a/docs/bibliography.bib b/docs/bibliography.bib index c425c145..cc9a5907 100644 --- a/docs/bibliography.bib +++ b/docs/bibliography.bib @@ -507,6 +507,17 @@ @book{simonsCoplanarWaveguideCircuits2001 isbn = {978-0-471-46393-1}, langid = {english} } +@article{somoroff_millisecond_2023, + title = {Millisecond {{Coherence}} in a {{Superconducting Qubit}}}, + author = {Somoroff, Aaron and Ficheux, Quentin and Mencia, Raymond A. and Xiong, Haonan and Kuzmin, Roman and Manucharyan, Vladimir E.}, + year = {2023}, + month = feb, + journal = {Physical Review Letters}, + volume = {130}, + number = {26}, + pages = {267001}, + doi = {10.1103/PhysRevLett.130.267001} +} @book{tinkhamIntroductionSuperconductivity2015, title = {Introduction to Superconductivity}, author = {Tinkham, Michael}, @@ -569,3 +580,34 @@ @article{yostSolidstateQubitsIntegrated2020 doi = {10.1038/s41534-020-00289-8}, langid = {english} } +@article{zhang_tunable_2024, + title = {Tunable inductive coupler for high fidelity gates between fluxonium qubits}, + author = {Zhang, Helin and Ding, Chunyang and Weiss, D. K. and Huang, Ziwen and Ma, Yuwei and Guinn, Charles and Sussman, Sara and Chitta, Sai Pavan and Chen, Danyang and Houck, Andrew A. and Koch, Jens and Schuster, David I.}, + journal = {Physical Review Letters}, + volume = {132}, + issue = {2}, + pages = {020601}, + year = {2024}, + doi = {10.1103/PhysRevLett.132.020601} +} +@article{zhang_universal_2021, + title = {Universal fast flux control of a coherent, low-frequency qubit}, + author = {Zhang, Helin and Chakram, Srivatsan and Roy, Tanay and Earnest, Nathan and Lu, Yao and Huang, Ziwen and Weiss, Daniel and Koch, Jens and Schuster, David I.}, + journal = {Physical Review X}, + volume = {11}, + issue = {1}, + pages = {011010}, + year = {2021}, + doi = {10.1103/PhysRevX.11.011010} +} +@article{zhu_circuit_2013, + title = {Circuit {{QED}} with Fluxonium Qubits: {{Theory}} of the Dispersive Regime}, + author = {Zhu, Guanyu and Koch, David G. and Braunstein, Samuel L. and Ferguson, David G. and Koch, Jens}, + year = {2013}, + month = jan, + journal = {Physical Review B}, + volume = {87}, + number = {2}, + pages = {024510}, + doi = {10.1103/PhysRevB.87.024510} +} diff --git a/docs/notebooks.rst b/docs/notebooks.rst index 22ac3083..6fc01ec7 100644 --- a/docs/notebooks.rst +++ b/docs/notebooks.rst @@ -164,16 +164,20 @@ and coupling strengths that feed back into the layout design - Computing transmon qubit frequency (:math:`\omega_{01}`) and anharmonicity (:math:`\alpha`) from Josephson energy :math:`E_J` and charging energy :math:`E_C`. -- Calculating the dispersive shift :math:`\chi` of a transmon–resonator system for - readout design. +- Analysing fluxonium qubit spectra from :math:`E_J`, :math:`E_C`, :math:`E_L`, and + external flux. +- Calculating the dispersive shift :math:`\chi` of a qubit–resonator system for readout + design. +- Comparing design trade-offs between transmon and fluxonium qubits. - Translating Hamiltonian-level parameters into physical layout dimensions. **Notebooks:** -- :doc:`notebooks/scqubits_parameter_calculation` — Full numerical diagonalization of - the transmon–resonator Hamiltonian with scQubits - :cite:`groszkowskiScqubitsPythonPackage2021`, compared against analytical perturbation - theory. +- :doc:`notebooks/scqubits_parameter_calculation` — Numerical diagonalization of + transmon– and fluxonium–resonator Hamiltonians with scQubits + :cite:`groszkowskiScqubitsPythonPackage2021`, including a side-by-side comparison of + anharmonicity, dispersive shift, and design trade-offs between the two qubit + modalities. - :doc:`notebooks/pymablock_dispersive_shift` — Perturbative block-diagonalization with Pymablock :cite:`arayaDayPymablockAlgorithmPackage2025` to compute the dispersive shift symbolically and map the result to layout parameters. diff --git a/notebooks/scqubits_parameter_calculation.ipynb b/notebooks/scqubits_parameter_calculation.ipynb index ad118d04..72c1c4d5 100644 --- a/notebooks/scqubits_parameter_calculation.ipynb +++ b/notebooks/scqubits_parameter_calculation.ipynb @@ -5,30 +5,26 @@ "id": "0", "metadata": {}, "source": [ - "# Dispersive Shift of a Transmon–Resonator System with scQubits\n", - "\n", - "This notebook demonstrates how to use\n", - "[scqubits](https://scqubits.readthedocs.io/en/latest/) {cite:p}`groszkowskiScqubitsPythonPackage2021`\n", - "to numerically compute the **dispersive shift** of a readout resonator coupled\n", - "to a transmon qubit, and how to translate the resulting Hamiltonian\n", - "parameters into physical layout parameters using **qpdk**.\n", - "\n", - "This notebook covers the same design workflow as the companion notebook on\n", - "**pymablock-based dispersive shift calculation**, but uses full numerical\n", - "diagonalization instead of closed-form perturbation theory—making it easy to\n", - "compare the two approaches.\n", - "\n", - "## Background\n", - "\n", - "In circuit quantum electrodynamics (cQED), the state of a transmon qubit is\n", - "typically measured via the *dispersive readout* technique\n", - "{cite:p}`blaisCircuitQuantumElectrodynamics2021`. The qubit is detuned from\n", - "a readout resonator, and the qubit-state-dependent frequency shift of the\n", - "resonator—the **dispersive shift** $\\chi$—allows non-destructive measurement\n", - "of the qubit state.\n", - "\n", - "The full transmon–resonator Hamiltonian (without the rotating-wave approximation)\n", - "reads:\n", + "# Transmon and Fluxonium Parameter Analysis with scQubits\n", + "\n", + "This notebook uses [scqubits](https://scqubits.readthedocs.io/) {cite:p}`groszkowskiScqubitsPythonPackage2021`\n", + "to numerically analyze **transmon** and **fluxonium** qubits coupled to a resonator,\n", + "translating Hamiltonian parameters into physical layout parameters via **qpdk**.\n", + "\n", + "The **transmon** {cite:p}`kochChargeinsensitiveQubitDesign2007a` achieves\n", + "charge-noise insensitivity in the $E_J \\gg E_C$ regime at the cost of weak\n", + "anharmonicity ($|\\alpha| \\approx E_C \\sim 200$ MHz). The **fluxonium**\n", + "{cite:p}`manucharyan_fluxonium_2009` adds a large superinductance, providing\n", + "strong anharmonicity and multi-millisecond coherence\n", + "{cite:p}`somoroff_millisecond_2023`.\n", + "\n", + "## Part I — Transmon\n", + "\n", + "### Background\n", + "\n", + "Transmons are typically read out via the **dispersive shift** $\\chi$ of a\n", + "coupled resonator {cite:p}`blaisCircuitQuantumElectrodynamics2021`.\n", + "The Hamiltonian is:\n", "```{math}\n", ":label: eq:transmon-resonator-hamiltonian-scq\n", "\\mathcal{H} = \\omega_t\\, a_t^\\dagger a_t\n", @@ -36,19 +32,12 @@ "+ \\omega_r\\, a_r^\\dagger a_r\n", "+ g\\,(a_t + a_t^\\dagger)(a_r + a_r^\\dagger),\n", "```\n", - "where $\\omega_t$ is the transmon frequency, $\\alpha$ its anharmonicity\n", - "($\\alpha < 0$ for a transmon),\n", - "$\\omega_r$ the resonator frequency, and $g$ the coupling strength.\n", - "\n", - "scQubits constructs and diagonalizes this Hamiltonian numerically in the\n", - "transmon charge basis and Fock basis {cite:p}`kochChargeinsensitiveQubitDesign2007a`.\n", - "The dispersive shift is then extracted directly from the dressed eigenvalues:\n", + "we extract $\\chi$ from the dressed eigenenergies $E_{ij}$ (where $i$ is the\n", + "qubit state and $j$ the photon number):\n", "```{math}\n", ":label: eq:dispersive-shift-definition-scq\n", - "\\chi = (E_{11} - E_{10}) - (E_{01} - E_{00}),\n", - "```\n", - "where $E_{ij}$ is the dressed eigenenergy with $i$ transmon excitations and\n", - "$j$ resonator photons." + "\\chi = (E_{11} - E_{10}) - (E_{01} - E_{00}).\n", + "```" ] }, { @@ -238,6 +227,12 @@ "source": [ "hilbert_space = scq.HilbertSpace([transmon, resonator])\n", "\n", + "# Extract the charge matrix element n_01 to match scQubits with analytical formulas\n", + "# scQubits interaction is g_val * n_t * (a + a†)\n", + "# Analytical formulas use g_01 = g_val * |<0|n|1>|\n", + "n_01 = np.abs(transmon.matrixelement_table(\"n_operator\")[0, 1])\n", + "g_01 = g_val * n_01\n", + "\n", "interaction = scq.InteractionTerm(\n", " g_strength=g_val,\n", " operator_list=[\n", @@ -276,8 +271,8 @@ "E_00, E_10, E_01, E_11 = evals[idx_00], evals[idx_10], evals[idx_01], evals[idx_11]\n", "chi_scqubits = (E_11 - E_10) - (E_01 - E_00)\n", "\n", - "# Compare to the analytical formula from qpdk.models.perturbation\n", - "chi_analytical = dispersive_shift(omega_t_val, omega_r_val, alpha_val, g_val)\n", + "# Compare to the analytical formula from qpdk.models.perturbation using g_01\n", + "chi_analytical = dispersive_shift(omega_t_val, omega_r_val, alpha_val, g_01)\n", "\n", "display(\n", " Math(rf\"\"\"\n", @@ -295,8 +290,9 @@ "metadata": {}, "source": [ "The scQubits result agrees well with the analytical perturbation-theory\n", - "formula; any residual difference reflects higher-order corrections beyond\n", - "the leading $g^2/\\Delta$ term." + "formula when using the effective coupling $g_{01} = g \\langle 0|\\hat{n}|1\\rangle$.\n", + "Residual differences reflect higher-order corrections and the contribution of\n", + "higher transmon levels beyond the leading $g^2/\\Delta$ terms." ] }, { @@ -331,8 +327,9 @@ "source": [ "_a_plus_adag = resonator.annihilation_operator() + resonator.creation_operator()\n", "g_sweep = np.linspace(0.01, 0.3, 200)\n", + "# Use effective coupling g_01 for analytical sweep\n", "chi_sweep_analytical = np.array([\n", - " dispersive_shift(omega_t_val, omega_r_val, alpha_val, gi) for gi in g_sweep\n", + " dispersive_shift(omega_t_val, omega_r_val, alpha_val, gi * n_01) for gi in g_sweep\n", "])\n", "\n", "\n", @@ -448,10 +445,407 @@ "id": "14", "metadata": {}, "source": [ - "## Design Workflow: From Hamiltonian to Layout Parameters\n", + "## Part II — Fluxonium\n", + "\n", + "### Background\n", + "\n", + "The **fluxonium** {cite:p}`manucharyan_fluxonium_2009` replaces the\n", + "transmon junction with a junction *shunted* by a large superinductance $L_s$:\n", + "```{math}\n", + ":label: eq:fluxonium-hamiltonian\n", + "\\mathcal{H}_\\text{flx}\n", + " = 4 E_C\\, \\hat{n}^2\n", + " - E_J\\, \\cos\\!\\bigl(\\hat{\\varphi} - 2\\pi\\Phi_\\text{ext}/\\Phi_0\\bigr)\n", + " + \\tfrac{1}{2} E_L\\, \\hat{\\varphi}^2,\n", + "```\n", + "where $E_L = (\\Phi_0/2\\pi)^2 / L_s$. Modern **\"heavy\" fluxoniums**\n", + "{cite:p}`zhang_universal_2021` add a large shunting capacitor ($E_J \\gtrsim 10 E_C$),\n", + "exponentially suppressing tunneling between potential wells and reaching multi-millisecond $T_1$.\n", + "\n", + "Key advantages:\n", + "1. **Massive anharmonicity** — $|\\alpha/\\omega_{01}| \\gg 1$ at the $\\Phi_0/2$\n", + " sweet spot, suppressing leakage {cite:p}`nguyen_blueprint_2019`.\n", + "2. **Protection** — Built-in protection against both charge and flux noise.\n", + "\n", + "Detuning to typical resonators ($\\sim 7$ GHz) is large, making dispersive readout\n", + "challenging {cite:p}`zhu_circuit_2013`." + ] + }, + { + "cell_type": "markdown", + "id": "15", + "metadata": {}, + "source": [ + "### Fluxonium Spectrum\n", + "\n", + "We construct a fluxonium qubit using parameters representative of a\n", + "**GHz-regime heavy fluxonium** ($E_J/E_C = 10$). The `cutoff`\n", + "parameter sets the size of the phase-basis truncation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16", + "metadata": {}, + "outputs": [], + "source": [ + "# Fluxonium Hamiltonian parameters (GHz regime)\n", + "EJ_flx = 5.0 # Josephson energy in GHz\n", + "EC_flx = 0.5 # Charging energy in GHz\n", + "EL_flx = 5.0 # Inductive energy in GHz\n", + "\n", + "fluxonium = scq.Fluxonium(\n", + " EJ=EJ_flx,\n", + " EC=EC_flx,\n", + " EL=EL_flx,\n", + " flux=0.5, # Half-flux-quantum sweet spot\n", + " cutoff=110,\n", + " truncated_dim=10,\n", + ")\n", + "\n", + "eigenvals_f = fluxonium.eigenvals(evals_count=6) - fluxonium.eigenvals(evals_count=1)[0]\n", + "f01_flx = eigenvals_f[1]\n", + "f12_flx = eigenvals_f[2] - eigenvals_f[1]\n", + "anharmonicity_flx = f12_flx - f01_flx\n", + "\n", + "display(\n", + " Math(rf\"\"\"\n", + "\\text{{Fluxonium Spectrum (scQubits, $\\Phi_{{\\mathrm{{ext}}}} = \\Phi_0/2$):}} \\\\\n", + "E_J = {EJ_flx:.3f}\\,\\mathrm{{GHz}}, \\quad\n", + "E_C = {EC_flx:.3f}\\,\\mathrm{{GHz}}, \\quad\n", + "E_L = {EL_flx:.3f}\\,\\mathrm{{GHz}} \\\\\n", + "0\\rightarrow 1\\ \\text{{frequency:}}\\ {f01_flx:.4f}\\,\\mathrm{{GHz}} \\\\\n", + "1\\rightarrow 2\\ \\text{{frequency:}}\\ {f12_flx:.3f}\\,\\mathrm{{GHz}} \\\\\n", + "\\text{{Anharmonicity,}}\\ \\alpha_\\text{{flx}} =\\ {anharmonicity_flx:.3f}\\,\\mathrm{{GHz}}\n", + "\"\"\")\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "17", + "metadata": {}, + "source": [ + "The fluxonium anharmonicity is **much larger** than a\n", + "transmon's ($\\sim E_C \\approx 200$ MHz). This is a direct consequence\n", + "of the double-well potential created by the competition between the\n", + "cosine and quadratic terms in {eq}`eq:fluxonium-hamiltonian`.\n", + "While many fluxoniums are designed for low frequencies (tens of MHz),\n", + "here we analyze a design operating in the GHz range for direct\n", + "comparison with the transmon." + ] + }, + { + "cell_type": "markdown", + "id": "18", + "metadata": {}, + "source": [ + "### Fluxonium Spectrum vs. External Flux\n", + "\n", + "The fluxonium energy levels depend strongly on external flux.\n", + "At half-integer flux quanta the lowest two levels form a\n", + "parity-protected sweet spot against flux noise\n", + "{cite:p}`manucharyan_fluxonium_2009,nguyen_blueprint_2019`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "19", + "metadata": {}, + "outputs": [], + "source": [ + "fluxonium.plot_evals_vs_paramvals(\n", + " \"flux\", np.linspace(0.0, 1.0, 201), subtract_ground=True, evals_count=6\n", + ")\n", + "plt.title(\"Fluxonium spectrum vs. external flux\")\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "20", + "metadata": {}, + "source": [ + "### Fluxonium–Resonator Dispersive Shift\n", + "\n", + "We couple the fluxonium to the same readout resonator used for the\n", + "transmon analysis and extract the dispersive shift via numerical\n", + "diagonalization. The coupling is again of the charge type\n", + "{cite:p}`zhu_circuit_2013`:\n", + "```{math}\n", + "\\mathcal{H}_\\text{int} = g\\, \\hat{n}_\\text{flx}\\,(a_r + a_r^\\dagger).\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "21", + "metadata": {}, + "outputs": [], + "source": [ + "omega_r_flx = 7.0 # Resonator frequency in GHz (same as transmon case)\n", + "g_flx = 0.1 # Coupling strength in GHz\n", + "\n", + "resonator_flx = scq.Oscillator(E_osc=omega_r_flx, truncated_dim=6)\n", + "\n", + "hilbert_space_flx = scq.HilbertSpace([fluxonium, resonator_flx])\n", + "_a_plus_adag_flx = (\n", + " resonator_flx.annihilation_operator() + resonator_flx.creation_operator()\n", + ")\n", + "\n", + "interaction_flx = scq.InteractionTerm(\n", + " g_strength=g_flx,\n", + " operator_list=[\n", + " (0, fluxonium.n_operator),\n", + " (1, _a_plus_adag_flx),\n", + " ],\n", + ")\n", + "hilbert_space_flx.interaction_list = [interaction_flx]\n", + "\n", + "evals_flx, evecs_flx = hilbert_space_flx.eigensys(evals_count=20)\n", + "evecs_flx = np.array([np.array(v.full()).flatten() for v in evecs_flx])\n", + "\n", + "dim_f = fluxonium.truncated_dim\n", + "dim_r_flx = resonator_flx.truncated_dim\n", + "\n", + "\n", + "def bare_state_vec_flx(q_idx: int, r_idx: int) -> np.ndarray:\n", + " \"\"\"Return the bare state |q_idx, r_idx⟩ in the fluxonium–resonator Hilbert space.\"\"\"\n", + " vec = np.zeros(dim_f * dim_r_flx)\n", + " vec[q_idx * dim_r_flx + r_idx] = 1.0\n", + " return vec\n", + "\n", + "\n", + "def find_dressed_index_flx(bare_vec: np.ndarray) -> int:\n", + " \"\"\"Return the dressed-state index with maximum overlap with bare_vec.\"\"\"\n", + " return int(np.argmax(np.abs(evecs_flx @ bare_vec) ** 2))\n", + "\n", + "\n", + "idx_00_f = find_dressed_index_flx(bare_state_vec_flx(0, 0))\n", + "idx_10_f = find_dressed_index_flx(bare_state_vec_flx(1, 0))\n", + "idx_01_f = find_dressed_index_flx(bare_state_vec_flx(0, 1))\n", + "idx_11_f = find_dressed_index_flx(bare_state_vec_flx(1, 1))\n", + "\n", + "E_00_f = evals_flx[idx_00_f]\n", + "E_10_f = evals_flx[idx_10_f]\n", + "E_01_f = evals_flx[idx_01_f]\n", + "E_11_f = evals_flx[idx_11_f]\n", + "chi_flx = (E_11_f - E_10_f) - (E_01_f - E_00_f)\n", + "\n", + "display(\n", + " Math(rf\"\"\"\n", + "\\textbf{{Fluxonium–Resonator Dispersive Shift:}} \\\\\n", + "\\omega_\\text{{flx}} = {f01_flx:.4f}\\,\\mathrm{{GHz}}, \\quad\n", + "\\omega_r = {omega_r_flx:.1f}\\,\\mathrm{{GHz}}, \\quad\n", + "g = {g_flx:.1f}\\,\\mathrm{{GHz}} \\\\\n", + "\\Delta = \\omega_\\text{{flx}} - \\omega_r = {f01_flx - omega_r_flx:.3f}\\,\\mathrm{{GHz}} \\\\\n", + "\\chi_{{\\mathrm{{fluxonium}}}} = {chi_flx * 1e3:.4f}\\,\\mathrm{{MHz}}\n", + "\"\"\")\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "22", + "metadata": {}, + "source": [ + "The fluxonium dispersive shift is typically **much smaller** than the\n", + "transmon's, because the qubit–resonator detuning $|\\Delta|$ is very large\n", + "($\\sim 7$ GHz). Achieving a useful $\\chi$ requires either stronger\n", + "coupling or a lower-frequency resonator\n", + "{cite:p}`zhu_circuit_2013`.\n", + "\n", + "Alternatively, to avoid qubit heating while ensuring high-fidelity readout,\n", + "modern heavy fluxoniums use a **plasmon-assisted readout** scheme\n", + "{cite:p}`zhang_universal_2021`. In this approach, a fast $\\pi$-pulse transfers\n", + "the computational $|e\\rangle$ state population to a higher-energy \"plasmon\" state\n", + "(e.g., $|f\\rangle$ or $|h\\rangle$) prior to measurement. Because these higher states\n", + "are much closer to the resonator frequency, their dispersive interaction is\n", + "significantly stronger, providing a large measurement signal while keeping the\n", + "fundamental qubit states protected from resonator-induced decoherence during normal operation." + ] + }, + { + "cell_type": "markdown", + "id": "23", + "metadata": {}, + "source": [ + "## Part III — Transmon vs. Fluxonium Comparison\n", + "\n", + "The table below highlights the key physical differences between the\n", + "two qubit modalities, computed with the parameters used above.\n", + "\n", + "**Two-Qubit Gating Advantage:** While transmons face speed limits due to weak\n", + "anharmonicity, heavy fluxoniums can achieve much faster entangling gates without\n", + "leaving the computational subspace. By coupling two fluxoniums via a tunable\n", + "inductive coupler, strong $XX$ interaction strengths (-35 to 75 MHz) can be\n", + "achieved while suppressing unwanted static $ZZ$ coupling to under 100 Hz,\n", + "maintaining high-fidelity single-qubit operations {cite:p}`zhang_tunable_2024`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "24", + "metadata": {}, + "outputs": [], + "source": [ + "comparison_data = [\n", + " (\"Qubit frequency $\\\\omega_{01}$\", f\"{f01:.3f} GHz\", f\"{f01_flx:.3f} GHz\"),\n", + " (\n", + " \"Anharmonicity $\\\\alpha$\",\n", + " f\"{anharmonicity:.3f} GHz\",\n", + " f\"{anharmonicity_flx:.3f} GHz\",\n", + " ),\n", + " (\n", + " \"$|\\\\alpha / \\\\omega_{01}|$\",\n", + " f\"{abs(anharmonicity / f01) * 100:.1f}%\",\n", + " f\"{abs(anharmonicity_flx / f01_flx) * 100:.1f}%\",\n", + " ),\n", + " (\"$E_J / E_C$\", f\"{EJ / EC:.0f}\", f\"{EJ_flx / EC_flx:.1f}\"),\n", + " (\n", + " \"Dispersive shift $\\\\chi$ ($g = 100$ MHz)\",\n", + " f\"{chi_scqubits * 1e3:.3f} MHz\",\n", + " f\"{chi_flx * 1e3:.3f} MHz\",\n", + " ),\n", + " (\n", + " \"Detuning $|\\\\Delta|$ from 7 GHz resonator\",\n", + " f\"{abs(omega_t_val - omega_r_val):.3f} GHz\",\n", + " f\"{abs(f01_flx - omega_r_flx):.3f} GHz\",\n", + " ),\n", + " (\"Flux sweet spot\", \"Any (fixed-frequency)\", \"$\\\\Phi_0/2$\"),\n", + " (\n", + " \"Dominant dephasing mechanism\",\n", + " \"Charge noise (mitigated by $E_J/E_C \\\\gg 1$)\",\n", + " \"Flux noise (mitigated at $\\\\Phi_0/2$)\",\n", + " ),\n", + "]\n", + "\n", + "df_compare = pl.DataFrame(\n", + " comparison_data,\n", + " schema=[\"Property\", \"Transmon\", \"Fluxonium\"],\n", + " orient=\"row\",\n", + ")\n", + "display_dataframe(df_compare)" + ] + }, + { + "cell_type": "markdown", + "id": "25", + "metadata": {}, + "source": [ + "### Anharmonicity Landscape\n", + "\n", + "The most striking difference is the anharmonicity-to-frequency ratio.\n", + "For the transmon, $|\\alpha/\\omega_{01}| \\sim E_C / \\sqrt{8 E_J E_C} \\sim 4\\%$,\n", + "meaning gate pulses must be carefully shaped to avoid leakage to the\n", + "$|2\\rangle$ state {cite:p}`kochChargeinsensitiveQubitDesign2007a`.\n", + "The fluxonium at half-flux-quantum has $|\\alpha/\\omega_{01}| \\gg 1$,\n", + "so leakage is naturally suppressed, at the cost of slower gates due to\n", + "the low transition frequency {cite:p}`nguyen_blueprint_2019`.\n", + "\n", + "Below we sweep $E_J/E_C$ for the transmon and $E_L$ for the fluxonium\n", + "to visualise how anharmonicity varies across the design space." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "26", + "metadata": {}, + "outputs": [], + "source": [ + "# Transmon: sweep EJ/EC\n", + "ej_ec_ratios = np.linspace(10, 120, 50)\n", + "alpha_transmon_sweep = np.array([\n", + " ej_ec_to_frequency_and_anharmonicity(r * EC, EC)[1] for r in ej_ec_ratios\n", + "])\n", + "freq_transmon_sweep = np.array([\n", + " ej_ec_to_frequency_and_anharmonicity(r * EC, EC)[0] for r in ej_ec_ratios\n", + "])\n", + "\n", + "# Fluxonium: sweep EL at half flux\n", + "el_sweep = np.linspace(0.05, 1.0, 30)\n", + "alpha_flx_sweep = []\n", + "freq_flx_sweep = []\n", + "for el_val in el_sweep:\n", + " fl_tmp = scq.Fluxonium(\n", + " EJ=EJ_flx, EC=EC_flx, EL=el_val, flux=0.5, cutoff=110, truncated_dim=4\n", + " )\n", + " evals_tmp = fl_tmp.eigenvals(evals_count=3)\n", + " evals_tmp -= evals_tmp[0]\n", + " freq_flx_sweep.append(evals_tmp[1])\n", + " alpha_flx_sweep.append((evals_tmp[2] - evals_tmp[1]) - evals_tmp[1])\n", + "alpha_flx_sweep = np.array(alpha_flx_sweep)\n", + "freq_flx_sweep = np.array(freq_flx_sweep)\n", + "\n", + "fig, axes = plt.subplots(1, 2, figsize=(12, 4))\n", + "\n", + "ax = axes[0]\n", + "ax.plot(ej_ec_ratios, freq_transmon_sweep, \"C0-\", linewidth=2, label=\"$\\\\omega_{01}$\")\n", + "ax.plot(\n", + " ej_ec_ratios,\n", + " alpha_transmon_sweep,\n", + " \"C1--\",\n", + " linewidth=2,\n", + " label=\"$|\\\\alpha|$\",\n", + ")\n", + "ax.set_xlabel(\"$E_J / E_C$\")\n", + "ax.set_ylabel(\"Frequency (GHz)\")\n", + "ax.set_title(\"Transmon\")\n", + "ax.legend()\n", + "ax.grid(True, alpha=0.3)\n", + "\n", + "ax = axes[1]\n", + "ax.plot(el_sweep, freq_flx_sweep, \"C0-\", linewidth=2, label=\"$\\\\omega_{01}$\")\n", + "ax.plot(\n", + " el_sweep,\n", + " np.abs(alpha_flx_sweep),\n", + " \"C1--\",\n", + " linewidth=2,\n", + " label=\"$|\\\\alpha|$\",\n", + ")\n", + "ax.set_xlabel(\"$E_L$ (GHz)\")\n", + "ax.set_ylabel(\"Frequency (GHz)\")\n", + "ax.set_title(\"Fluxonium ($\\\\Phi_\\\\mathrm{ext} = \\\\Phi_0/2$)\")\n", + "ax.legend()\n", + "ax.grid(True, alpha=0.3)\n", + "\n", + "fig.suptitle(\"Qubit frequency and anharmonicity across the design space\", fontsize=13)\n", + "fig.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "27", + "metadata": {}, + "source": [ + "The left panel shows the well-known transmon trade-off: increasing\n", + "$E_J/E_C$ exponentially suppresses charge dispersion but the\n", + "anharmonicity remains pinned at $\\alpha \\approx E_C$.\n", + "The right panel shows that the fluxonium frequency decreases with\n", + "smaller $E_L$ (heavier fluxonium, i.e. larger $L_s$), while the anharmonicity remains\n", + "large—a qualitatively different design knob." + ] + }, + { + "cell_type": "markdown", + "id": "28", + "metadata": {}, + "source": [ + "## Part IV — Design Workflow: From Hamiltonian to Layout Parameters\n", "\n", "The purpose of computing $\\chi$ is to **design** a qubit–resonator system\n", - "with a target dispersive shift. The workflow mirrors the pymablock notebook,\n", + "with a target dispersive shift. The sections below walk through the full\n", + "design flow for both a transmon and a fluxonium.\n", + "\n", + "### Transmon Design\n", + "\n", + "The transmon workflow mirrors the pymablock notebook,\n", "using qpdk analytical helpers for speed and scQubits for numerical verification:\n", "\n", "1. **Choose target $\\chi$** based on readout speed requirements\n", @@ -460,13 +854,13 @@ "4. **Convert to circuit parameters** ($C_\\Sigma$, $L_J$, $C_c$) using qpdk helpers\n", "5. **Convert to layout parameters** (resonator length, capacitor geometry)\n", "\n", - "### Step 1–3: From target $\\chi$ to coupling $g$" + "#### Step 1–3: From target $\\chi$ to coupling $g$" ] }, { "cell_type": "code", "execution_count": null, - "id": "15", + "id": "29", "metadata": {}, "outputs": [], "source": [ @@ -492,13 +886,14 @@ "chi_verify_analytical = dispersive_shift(\n", " omega_t_design, omega_r_design, alpha_design, float(g_design)\n", ")\n", - "chi_verify_scq = chi_scqubits_at_g(float(g_design))\n", + "# Note: scQubits interaction strength is scaled by n_01\n", + "chi_verify_scq = chi_scqubits_at_g(float(g_design) / n_01)\n", "\n", "display(\n", " Math(rf\"\"\"\n", "\\textbf{{Step 1–3: Hamiltonian Design}} \\\\\n", "\\text{{Target:}}\\quad \\chi = {chi_target_mhz:.1f}\\,\\mathrm{{MHz}} \\\\\n", - "\\text{{Required coupling:}}\\quad g = {float(g_design) * 1e3:.1f}\\,\\mathrm{{MHz}} \\\\\n", + "\\text{{Required coupling:}}\\quad g_{{01}} = {float(g_design) * 1e3:.1f}\\,\\mathrm{{MHz}} \\\\\n", "\\text{{Verification (analytical):}}\\quad \\chi = {chi_verify_analytical * 1e3:.3f}\\,\\mathrm{{MHz}} \\\\\n", "\\text{{Verification (scQubits):}}\\quad \\chi = {chi_verify_scq * 1e3:.3f}\\,\\mathrm{{MHz}}\n", "\"\"\")\n", @@ -507,10 +902,10 @@ }, { "cell_type": "markdown", - "id": "16", + "id": "30", "metadata": {}, "source": [ - "### Step 4: Convert to circuit parameters\n", + "#### Step 4: Convert to circuit parameters\n", "\n", "Using the qpdk helper functions, we convert the Hamiltonian parameters\n", "to circuit parameters:\n", @@ -522,7 +917,7 @@ { "cell_type": "code", "execution_count": null, - "id": "17", + "id": "31", "metadata": {}, "outputs": [], "source": [ @@ -582,10 +977,10 @@ }, { "cell_type": "markdown", - "id": "18", + "id": "32", "metadata": {}, "source": [ - "### Step 5: Layout parameters\n", + "#### Step 5: Layout parameters\n", "\n", "The circuit parameters map directly to layout dimensions:" ] @@ -593,7 +988,7 @@ { "cell_type": "code", "execution_count": null, - "id": "19", + "id": "33", "metadata": {}, "outputs": [], "source": [ @@ -617,7 +1012,7 @@ }, { "cell_type": "markdown", - "id": "20", + "id": "34", "metadata": {}, "source": [ "## Readout System Design Considerations\n", @@ -630,7 +1025,7 @@ { "cell_type": "code", "execution_count": null, - "id": "21", + "id": "35", "metadata": {}, "outputs": [], "source": [ @@ -671,25 +1066,78 @@ }, { "cell_type": "markdown", - "id": "22", + "id": "36", "metadata": {}, "source": [ - "## Summary: Complete Design Table\n", + "### Fluxonium Design\n", + "\n", + "Designing a fluxonium requires numerical diagonalization (via scQubits) since\n", + "transition frequencies depend complexly on $E_J$, $E_C$, $E_L$, and flux.\n", + "\n", + "1. **Numerical sweep**: Map $\\omega_{01}$ and $\\alpha$ vs. $E_L$ and $E_J$.\n", + "2. **Circuit mapping**: Convert energies to $L_s$, $L_J$, and $C_\\Sigma$.\n", + "3. **Layout layout**: Map $L_s$ to `inductor_n_turns` in the qpdk `fluxonium` cell.\n", "\n", - "The table below summarises the full design flow from Hamiltonian\n", - "parameters to layout parameters, with the dispersive shift as the\n", - "central design target." + "#### Fluxonium circuit parameters" ] }, { "cell_type": "code", "execution_count": null, - "id": "23", + "id": "37", + "metadata": {}, + "outputs": [], + "source": [ + "from qpdk.models.qubit import el_to_inductance\n", + "\n", + "# Fluxonium circuit parameters from the Hamiltonian energies\n", + "C_sigma_flx = float(ec_to_capacitance(EC_flx))\n", + "L_J_flx = float(ej_to_inductance(EJ_flx))\n", + "L_s_flx = float(el_to_inductance(EL_flx))\n", + "\n", + "display(\n", + " Math(rf\"\"\"\n", + "\\textbf{{Fluxonium Circuit Parameters:}} \\\\\n", + "E_J = {EJ_flx:.3f}\\,\\mathrm{{GHz}} \\;\\Rightarrow\\;\n", + " L_J = {L_J_flx * 1e9:.2f}\\,\\mathrm{{nH}} \\\\\n", + "E_C = {EC_flx:.3f}\\,\\mathrm{{GHz}} \\;\\Rightarrow\\;\n", + " C_\\Sigma = {C_sigma_flx * 1e15:.1f}\\,\\mathrm{{fF}} \\\\\n", + "E_L = {EL_flx:.3f}\\,\\mathrm{{GHz}} \\;\\Rightarrow\\;\n", + " L_s = {L_s_flx * 1e9:.1f}\\,\\mathrm{{nH}}\n", + "\"\"\")\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "38", + "metadata": {}, + "source": [ + "The superinductance $L_s \\sim 300\\,\\mathrm{nH}$ is realized by a\n", + "meander inductor made of a high-kinetic-inductance material (e.g. NbTiN\n", + "or granular aluminium) {cite:p}`manucharyan_fluxonium_2009,nguyen_blueprint_2019`.\n", + "The qpdk `fluxonium` cell parameterizes this as `inductor_n_turns`." + ] + }, + { + "cell_type": "markdown", + "id": "39", + "metadata": {}, + "source": [ + "## Summary: Transmon Design\n", + "\n", + "From Hamiltonian design targets to circuit and layout parameters." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "40", "metadata": {}, "outputs": [], "source": [ "data = [\n", - " (\"Target\", \"Target dispersive shift $\\\\chi$\", f\"{chi_target_mhz:.1f}\", \"MHz\"),\n", + " (\"Target\", \"Dispersive shift $\\\\chi$\", f\"{chi_target_mhz:.1f}\", \"MHz\"),\n", " (\"Hamiltonian\", \"$E_J$\", f\"{EJ_design:.1f}\", \"GHz\"),\n", " (\"Hamiltonian\", \"$E_C$\", f\"{EC_design:.1f}\", \"GHz\"),\n", " (\"Hamiltonian\", \"$\\\\omega_t$\", f\"{omega_t_design:.3f}\", \"GHz\"),\n", @@ -717,7 +1165,54 @@ }, { "cell_type": "markdown", - "id": "24", + "id": "41", + "metadata": {}, + "source": [ + "## Summary: Fluxonium Design\n", + "\n", + "Core parameters for the GHz-range fluxonium biased at $\\Phi_0/2$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "42", + "metadata": {}, + "outputs": [], + "source": [ + "data_flx = [\n", + " (\"Hamiltonian\", \"$E_J$\", f\"{EJ_flx:.3f}\", \"GHz\"),\n", + " (\"Hamiltonian\", \"$E_C$\", f\"{EC_flx:.3f}\", \"GHz\"),\n", + " (\"Hamiltonian\", \"$E_L$\", f\"{EL_flx:.3f}\", \"GHz\"),\n", + " (\"Hamiltonian\", \"$\\\\omega_\\\\text{flx}$\", f\"{f01_flx:.3f}\", \"GHz\"),\n", + " (\n", + " \"Hamiltonian\",\n", + " \"$\\\\alpha_\\\\text{flx}$\",\n", + " f\"{anharmonicity_flx:.3f}\",\n", + " \"GHz\",\n", + " ),\n", + " (\"Hamiltonian\", \"Flux bias\", \"$\\\\Phi_0/2$\", \"\"),\n", + " (\"Circuit\", \"$C_\\\\Sigma$\", f\"{C_sigma_flx * 1e15:.1f}\", \"fF\"),\n", + " (\"Circuit\", \"$L_J$\", f\"{L_J_flx * 1e9:.2f}\", \"nH\"),\n", + " (\"Circuit\", \"$L_s$ (superinductance)\", f\"{L_s_flx * 1e9:.1f}\", \"nH\"),\n", + " (\n", + " \"Dispersive shift\",\n", + " \"$\\\\chi$ ($g = 100$ MHz)\",\n", + " f\"{chi_flx * 1e3:.3f}\",\n", + " \"MHz\",\n", + " ),\n", + "]\n", + "\n", + "df_flx = pl.DataFrame(\n", + " data_flx, schema=[\"Category\", \"Parameter\", \"Value\", \"Unit\"], orient=\"row\"\n", + ")\n", + "\n", + "display_dataframe(df_flx)" + ] + }, + { + "cell_type": "markdown", + "id": "43", "metadata": {}, "source": [ "## References\n", diff --git a/notebooks/src/scqubits_parameter_calculation.py b/notebooks/src/scqubits_parameter_calculation.py index 307c700d..a03ba438 100644 --- a/notebooks/src/scqubits_parameter_calculation.py +++ b/notebooks/src/scqubits_parameter_calculation.py @@ -9,30 +9,26 @@ # --- # %% [markdown] -# # Dispersive Shift of a Transmon–Resonator System with scQubits -# -# This notebook demonstrates how to use -# [scqubits](https://scqubits.readthedocs.io/en/latest/) {cite:p}`groszkowskiScqubitsPythonPackage2021` -# to numerically compute the **dispersive shift** of a readout resonator coupled -# to a transmon qubit, and how to translate the resulting Hamiltonian -# parameters into physical layout parameters using **qpdk**. -# -# This notebook covers the same design workflow as the companion notebook on -# **pymablock-based dispersive shift calculation**, but uses full numerical -# diagonalization instead of closed-form perturbation theory—making it easy to -# compare the two approaches. -# -# ## Background -# -# In circuit quantum electrodynamics (cQED), the state of a transmon qubit is -# typically measured via the *dispersive readout* technique -# {cite:p}`blaisCircuitQuantumElectrodynamics2021`. The qubit is detuned from -# a readout resonator, and the qubit-state-dependent frequency shift of the -# resonator—the **dispersive shift** $\chi$—allows non-destructive measurement -# of the qubit state. -# -# The full transmon–resonator Hamiltonian (without the rotating-wave approximation) -# reads: +# # Transmon and Fluxonium Parameter Analysis with scQubits +# +# This notebook uses [scqubits](https://scqubits.readthedocs.io/) {cite:p}`groszkowskiScqubitsPythonPackage2021` +# to numerically analyze **transmon** and **fluxonium** qubits coupled to a resonator, +# translating Hamiltonian parameters into physical layout parameters via **qpdk**. +# +# The **transmon** {cite:p}`kochChargeinsensitiveQubitDesign2007a` achieves +# charge-noise insensitivity in the $E_J \gg E_C$ regime at the cost of weak +# anharmonicity ($|\alpha| \approx E_C \sim 200$ MHz). The **fluxonium** +# {cite:p}`manucharyan_fluxonium_2009` adds a large superinductance, providing +# strong anharmonicity and multi-millisecond coherence +# {cite:p}`somoroff_millisecond_2023`. +# +# ## Part I — Transmon +# +# ### Background +# +# Transmons are typically read out via the **dispersive shift** $\chi$ of a +# coupled resonator {cite:p}`blaisCircuitQuantumElectrodynamics2021`. +# The Hamiltonian is: # ```{math} # :label: eq:transmon-resonator-hamiltonian-scq # \mathcal{H} = \omega_t\, a_t^\dagger a_t @@ -40,19 +36,12 @@ # + \omega_r\, a_r^\dagger a_r # + g\,(a_t + a_t^\dagger)(a_r + a_r^\dagger), # ``` -# where $\omega_t$ is the transmon frequency, $\alpha$ its anharmonicity -# ($\alpha < 0$ for a transmon), -# $\omega_r$ the resonator frequency, and $g$ the coupling strength. -# -# scQubits constructs and diagonalizes this Hamiltonian numerically in the -# transmon charge basis and Fock basis {cite:p}`kochChargeinsensitiveQubitDesign2007a`. -# The dispersive shift is then extracted directly from the dressed eigenvalues: +# we extract $\chi$ from the dressed eigenenergies $E_{ij}$ (where $i$ is the +# qubit state and $j$ the photon number): # ```{math} # :label: eq:dispersive-shift-definition-scq -# \chi = (E_{11} - E_{10}) - (E_{01} - E_{00}), +# \chi = (E_{11} - E_{10}) - (E_{01} - E_{00}). # ``` -# where $E_{ij}$ is the dressed eigenenergy with $i$ transmon excitations and -# $j$ resonator photons. # %% tags=["hide-input", "hide-output"] import numpy as np @@ -182,6 +171,12 @@ # %% hilbert_space = scq.HilbertSpace([transmon, resonator]) +# Extract the charge matrix element n_01 to match scQubits with analytical formulas +# scQubits interaction is g_val * n_t * (a + a†) +# Analytical formulas use g_01 = g_val * |<0|n|1>| +n_01 = np.abs(transmon.matrixelement_table("n_operator")[0, 1]) +g_01 = g_val * n_01 + interaction = scq.InteractionTerm( g_strength=g_val, operator_list=[ @@ -220,8 +215,8 @@ def find_dressed_index(bare_vec: np.ndarray) -> int: E_00, E_10, E_01, E_11 = evals[idx_00], evals[idx_10], evals[idx_01], evals[idx_11] chi_scqubits = (E_11 - E_10) - (E_01 - E_00) -# Compare to the analytical formula from qpdk.models.perturbation -chi_analytical = dispersive_shift(omega_t_val, omega_r_val, alpha_val, g_val) +# Compare to the analytical formula from qpdk.models.perturbation using g_01 +chi_analytical = dispersive_shift(omega_t_val, omega_r_val, alpha_val, g_01) display( Math(rf""" @@ -234,8 +229,9 @@ def find_dressed_index(bare_vec: np.ndarray) -> int: # %% [markdown] # The scQubits result agrees well with the analytical perturbation-theory -# formula; any residual difference reflects higher-order corrections beyond -# the leading $g^2/\Delta$ term. +# formula when using the effective coupling $g_{01} = g \langle 0|\hat{n}|1\rangle$. +# Residual differences reflect higher-order corrections and the contribution of +# higher transmon levels beyond the leading $g^2/\Delta$ terms. # %% [markdown] # ## Dispersive Shift vs. Coupling Strength @@ -258,8 +254,9 @@ def find_dressed_index(bare_vec: np.ndarray) -> int: # %% _a_plus_adag = resonator.annihilation_operator() + resonator.creation_operator() g_sweep = np.linspace(0.01, 0.3, 200) +# Use effective coupling g_01 for analytical sweep chi_sweep_analytical = np.array([ - dispersive_shift(omega_t_val, omega_r_val, alpha_val, gi) for gi in g_sweep + dispersive_shift(omega_t_val, omega_r_val, alpha_val, gi * n_01) for gi in g_sweep ]) @@ -358,10 +355,327 @@ def di(qi: int, ri: int) -> int: plt.show() # %% [markdown] -# ## Design Workflow: From Hamiltonian to Layout Parameters +# ## Part II — Fluxonium +# +# ### Background +# +# The **fluxonium** {cite:p}`manucharyan_fluxonium_2009` replaces the +# transmon junction with a junction *shunted* by a large superinductance $L_s$: +# ```{math} +# :label: eq:fluxonium-hamiltonian +# \mathcal{H}_\text{flx} +# = 4 E_C\, \hat{n}^2 +# - E_J\, \cos\!\bigl(\hat{\varphi} - 2\pi\Phi_\text{ext}/\Phi_0\bigr) +# + \tfrac{1}{2} E_L\, \hat{\varphi}^2, +# ``` +# where $E_L = (\Phi_0/2\pi)^2 / L_s$. Modern **"heavy" fluxoniums** +# {cite:p}`zhang_universal_2021` add a large shunting capacitor ($E_J \gtrsim 10 E_C$), +# exponentially suppressing tunneling between potential wells and reaching multi-millisecond $T_1$. +# +# Key advantages: +# 1. **Massive anharmonicity** — $|\alpha/\omega_{01}| \gg 1$ at the $\Phi_0/2$ +# sweet spot, suppressing leakage {cite:p}`nguyen_blueprint_2019`. +# 2. **Protection** — Built-in protection against both charge and flux noise. +# +# Detuning to typical resonators ($\sim 7$ GHz) is large, making dispersive readout +# challenging {cite:p}`zhu_circuit_2013`. + +# %% [markdown] +# ### Fluxonium Spectrum +# +# We construct a fluxonium qubit using parameters representative of a +# **GHz-regime heavy fluxonium** ($E_J/E_C = 10$). The `cutoff` +# parameter sets the size of the phase-basis truncation. + +# %% +# Fluxonium Hamiltonian parameters (GHz regime) +EJ_flx = 5.0 # Josephson energy in GHz +EC_flx = 0.5 # Charging energy in GHz +EL_flx = 5.0 # Inductive energy in GHz + +fluxonium = scq.Fluxonium( + EJ=EJ_flx, + EC=EC_flx, + EL=EL_flx, + flux=0.5, # Half-flux-quantum sweet spot + cutoff=110, + truncated_dim=10, +) + +eigenvals_f = fluxonium.eigenvals(evals_count=6) - fluxonium.eigenvals(evals_count=1)[0] +f01_flx = eigenvals_f[1] +f12_flx = eigenvals_f[2] - eigenvals_f[1] +anharmonicity_flx = f12_flx - f01_flx + +display( + Math(rf""" +\text{{Fluxonium Spectrum (scQubits, $\Phi_{{\mathrm{{ext}}}} = \Phi_0/2$):}} \\ +E_J = {EJ_flx:.3f}\,\mathrm{{GHz}}, \quad +E_C = {EC_flx:.3f}\,\mathrm{{GHz}}, \quad +E_L = {EL_flx:.3f}\,\mathrm{{GHz}} \\ +0\rightarrow 1\ \text{{frequency:}}\ {f01_flx:.4f}\,\mathrm{{GHz}} \\ +1\rightarrow 2\ \text{{frequency:}}\ {f12_flx:.3f}\,\mathrm{{GHz}} \\ +\text{{Anharmonicity,}}\ \alpha_\text{{flx}} =\ {anharmonicity_flx:.3f}\,\mathrm{{GHz}} +""") +) + +# %% [markdown] +# The fluxonium anharmonicity is **much larger** than a +# transmon's ($\sim E_C \approx 200$ MHz). This is a direct consequence +# of the double-well potential created by the competition between the +# cosine and quadratic terms in {eq}`eq:fluxonium-hamiltonian`. +# While many fluxoniums are designed for low frequencies (tens of MHz), +# here we analyze a design operating in the GHz range for direct +# comparison with the transmon. + +# %% [markdown] +# ### Fluxonium Spectrum vs. External Flux +# +# The fluxonium energy levels depend strongly on external flux. +# At half-integer flux quanta the lowest two levels form a +# parity-protected sweet spot against flux noise +# {cite:p}`manucharyan_fluxonium_2009,nguyen_blueprint_2019`. + +# %% +fluxonium.plot_evals_vs_paramvals( + "flux", np.linspace(0.0, 1.0, 201), subtract_ground=True, evals_count=6 +) +plt.title("Fluxonium spectrum vs. external flux") +plt.show() + +# %% [markdown] +# ### Fluxonium–Resonator Dispersive Shift +# +# We couple the fluxonium to the same readout resonator used for the +# transmon analysis and extract the dispersive shift via numerical +# diagonalization. The coupling is again of the charge type +# {cite:p}`zhu_circuit_2013`: +# ```{math} +# \mathcal{H}_\text{int} = g\, \hat{n}_\text{flx}\,(a_r + a_r^\dagger). +# ``` + +# %% +omega_r_flx = 7.0 # Resonator frequency in GHz (same as transmon case) +g_flx = 0.1 # Coupling strength in GHz + +resonator_flx = scq.Oscillator(E_osc=omega_r_flx, truncated_dim=6) + +hilbert_space_flx = scq.HilbertSpace([fluxonium, resonator_flx]) +_a_plus_adag_flx = ( + resonator_flx.annihilation_operator() + resonator_flx.creation_operator() +) + +interaction_flx = scq.InteractionTerm( + g_strength=g_flx, + operator_list=[ + (0, fluxonium.n_operator), + (1, _a_plus_adag_flx), + ], +) +hilbert_space_flx.interaction_list = [interaction_flx] + +evals_flx, evecs_flx = hilbert_space_flx.eigensys(evals_count=20) +evecs_flx = np.array([np.array(v.full()).flatten() for v in evecs_flx]) + +dim_f = fluxonium.truncated_dim +dim_r_flx = resonator_flx.truncated_dim + + +def bare_state_vec_flx(q_idx: int, r_idx: int) -> np.ndarray: + """Return the bare state |q_idx, r_idx⟩ in the fluxonium–resonator Hilbert space.""" + vec = np.zeros(dim_f * dim_r_flx) + vec[q_idx * dim_r_flx + r_idx] = 1.0 + return vec + + +def find_dressed_index_flx(bare_vec: np.ndarray) -> int: + """Return the dressed-state index with maximum overlap with bare_vec.""" + return int(np.argmax(np.abs(evecs_flx @ bare_vec) ** 2)) + + +idx_00_f = find_dressed_index_flx(bare_state_vec_flx(0, 0)) +idx_10_f = find_dressed_index_flx(bare_state_vec_flx(1, 0)) +idx_01_f = find_dressed_index_flx(bare_state_vec_flx(0, 1)) +idx_11_f = find_dressed_index_flx(bare_state_vec_flx(1, 1)) + +E_00_f = evals_flx[idx_00_f] +E_10_f = evals_flx[idx_10_f] +E_01_f = evals_flx[idx_01_f] +E_11_f = evals_flx[idx_11_f] +chi_flx = (E_11_f - E_10_f) - (E_01_f - E_00_f) + +display( + Math(rf""" +\textbf{{Fluxonium–Resonator Dispersive Shift:}} \\ +\omega_\text{{flx}} = {f01_flx:.4f}\,\mathrm{{GHz}}, \quad +\omega_r = {omega_r_flx:.1f}\,\mathrm{{GHz}}, \quad +g = {g_flx:.1f}\,\mathrm{{GHz}} \\ +\Delta = \omega_\text{{flx}} - \omega_r = {f01_flx - omega_r_flx:.3f}\,\mathrm{{GHz}} \\ +\chi_{{\mathrm{{fluxonium}}}} = {chi_flx * 1e3:.4f}\,\mathrm{{MHz}} +""") +) + +# %% [markdown] +# The fluxonium dispersive shift is typically **much smaller** than the +# transmon's, because the qubit–resonator detuning $|\Delta|$ is very large +# ($\sim 7$ GHz). Achieving a useful $\chi$ requires either stronger +# coupling or a lower-frequency resonator +# {cite:p}`zhu_circuit_2013`. +# +# Alternatively, to avoid qubit heating while ensuring high-fidelity readout, +# modern heavy fluxoniums use a **plasmon-assisted readout** scheme +# {cite:p}`zhang_universal_2021`. In this approach, a fast $\pi$-pulse transfers +# the computational $|e\rangle$ state population to a higher-energy "plasmon" state +# (e.g., $|f\rangle$ or $|h\rangle$) prior to measurement. Because these higher states +# are much closer to the resonator frequency, their dispersive interaction is +# significantly stronger, providing a large measurement signal while keeping the +# fundamental qubit states protected from resonator-induced decoherence during normal operation. + +# %% [markdown] +# ## Part III — Transmon vs. Fluxonium Comparison +# +# The table below highlights the key physical differences between the +# two qubit modalities, computed with the parameters used above. +# +# **Two-Qubit Gating Advantage:** While transmons face speed limits due to weak +# anharmonicity, heavy fluxoniums can achieve much faster entangling gates without +# leaving the computational subspace. By coupling two fluxoniums via a tunable +# inductive coupler, strong $XX$ interaction strengths (-35 to 75 MHz) can be +# achieved while suppressing unwanted static $ZZ$ coupling to under 100 Hz, +# maintaining high-fidelity single-qubit operations {cite:p}`zhang_tunable_2024`. + +# %% +comparison_data = [ + ("Qubit frequency $\\omega_{01}$", f"{f01:.3f} GHz", f"{f01_flx:.3f} GHz"), + ( + "Anharmonicity $\\alpha$", + f"{anharmonicity:.3f} GHz", + f"{anharmonicity_flx:.3f} GHz", + ), + ( + "$|\\alpha / \\omega_{01}|$", + f"{abs(anharmonicity / f01) * 100:.1f}%", + f"{abs(anharmonicity_flx / f01_flx) * 100:.1f}%", + ), + ("$E_J / E_C$", f"{EJ / EC:.0f}", f"{EJ_flx / EC_flx:.1f}"), + ( + "Dispersive shift $\\chi$ ($g = 100$ MHz)", + f"{chi_scqubits * 1e3:.3f} MHz", + f"{chi_flx * 1e3:.3f} MHz", + ), + ( + "Detuning $|\\Delta|$ from 7 GHz resonator", + f"{abs(omega_t_val - omega_r_val):.3f} GHz", + f"{abs(f01_flx - omega_r_flx):.3f} GHz", + ), + ("Flux sweet spot", "Any (fixed-frequency)", "$\\Phi_0/2$"), + ( + "Dominant dephasing mechanism", + "Charge noise (mitigated by $E_J/E_C \\gg 1$)", + "Flux noise (mitigated at $\\Phi_0/2$)", + ), +] + +df_compare = pl.DataFrame( + comparison_data, + schema=["Property", "Transmon", "Fluxonium"], + orient="row", +) +display_dataframe(df_compare) + +# %% [markdown] +# ### Anharmonicity Landscape +# +# The most striking difference is the anharmonicity-to-frequency ratio. +# For the transmon, $|\alpha/\omega_{01}| \sim E_C / \sqrt{8 E_J E_C} \sim 4\%$, +# meaning gate pulses must be carefully shaped to avoid leakage to the +# $|2\rangle$ state {cite:p}`kochChargeinsensitiveQubitDesign2007a`. +# The fluxonium at half-flux-quantum has $|\alpha/\omega_{01}| \gg 1$, +# so leakage is naturally suppressed, at the cost of slower gates due to +# the low transition frequency {cite:p}`nguyen_blueprint_2019`. +# +# Below we sweep $E_J/E_C$ for the transmon and $E_L$ for the fluxonium +# to visualise how anharmonicity varies across the design space. + +# %% +# Transmon: sweep EJ/EC +ej_ec_ratios = np.linspace(10, 120, 50) +alpha_transmon_sweep = np.array([ + ej_ec_to_frequency_and_anharmonicity(r * EC, EC)[1] for r in ej_ec_ratios +]) +freq_transmon_sweep = np.array([ + ej_ec_to_frequency_and_anharmonicity(r * EC, EC)[0] for r in ej_ec_ratios +]) + +# Fluxonium: sweep EL at half flux +el_sweep = np.linspace(0.05, 1.0, 30) +alpha_flx_sweep = [] +freq_flx_sweep = [] +for el_val in el_sweep: + fl_tmp = scq.Fluxonium( + EJ=EJ_flx, EC=EC_flx, EL=el_val, flux=0.5, cutoff=110, truncated_dim=4 + ) + evals_tmp = fl_tmp.eigenvals(evals_count=3) + evals_tmp -= evals_tmp[0] + freq_flx_sweep.append(evals_tmp[1]) + alpha_flx_sweep.append((evals_tmp[2] - evals_tmp[1]) - evals_tmp[1]) +alpha_flx_sweep = np.array(alpha_flx_sweep) +freq_flx_sweep = np.array(freq_flx_sweep) + +fig, axes = plt.subplots(1, 2, figsize=(12, 4)) + +ax = axes[0] +ax.plot(ej_ec_ratios, freq_transmon_sweep, "C0-", linewidth=2, label="$\\omega_{01}$") +ax.plot( + ej_ec_ratios, + alpha_transmon_sweep, + "C1--", + linewidth=2, + label="$|\\alpha|$", +) +ax.set_xlabel("$E_J / E_C$") +ax.set_ylabel("Frequency (GHz)") +ax.set_title("Transmon") +ax.legend() +ax.grid(True, alpha=0.3) + +ax = axes[1] +ax.plot(el_sweep, freq_flx_sweep, "C0-", linewidth=2, label="$\\omega_{01}$") +ax.plot( + el_sweep, + np.abs(alpha_flx_sweep), + "C1--", + linewidth=2, + label="$|\\alpha|$", +) +ax.set_xlabel("$E_L$ (GHz)") +ax.set_ylabel("Frequency (GHz)") +ax.set_title("Fluxonium ($\\Phi_\\mathrm{ext} = \\Phi_0/2$)") +ax.legend() +ax.grid(True, alpha=0.3) + +fig.suptitle("Qubit frequency and anharmonicity across the design space", fontsize=13) +fig.tight_layout() +plt.show() + +# %% [markdown] +# The left panel shows the well-known transmon trade-off: increasing +# $E_J/E_C$ exponentially suppresses charge dispersion but the +# anharmonicity remains pinned at $\alpha \approx E_C$. +# The right panel shows that the fluxonium frequency decreases with +# smaller $E_L$ (heavier fluxonium, i.e. larger $L_s$), while the anharmonicity remains +# large—a qualitatively different design knob. + +# %% [markdown] +# ## Part IV — Design Workflow: From Hamiltonian to Layout Parameters # # The purpose of computing $\chi$ is to **design** a qubit–resonator system -# with a target dispersive shift. The workflow mirrors the pymablock notebook, +# with a target dispersive shift. The sections below walk through the full +# design flow for both a transmon and a fluxonium. +# +# ### Transmon Design +# +# The transmon workflow mirrors the pymablock notebook, # using qpdk analytical helpers for speed and scQubits for numerical verification: # # 1. **Choose target $\chi$** based on readout speed requirements @@ -370,7 +684,7 @@ def di(qi: int, ri: int) -> int: # 4. **Convert to circuit parameters** ($C_\Sigma$, $L_J$, $C_c$) using qpdk helpers # 5. **Convert to layout parameters** (resonator length, capacitor geometry) # -# ### Step 1–3: From target $\chi$ to coupling $g$ +# #### Step 1–3: From target $\chi$ to coupling $g$ # %% # Design targets @@ -395,20 +709,21 @@ def di(qi: int, ri: int) -> int: chi_verify_analytical = dispersive_shift( omega_t_design, omega_r_design, alpha_design, float(g_design) ) -chi_verify_scq = chi_scqubits_at_g(float(g_design)) +# Note: scQubits interaction strength is scaled by n_01 +chi_verify_scq = chi_scqubits_at_g(float(g_design) / n_01) display( Math(rf""" \textbf{{Step 1–3: Hamiltonian Design}} \\ \text{{Target:}}\quad \chi = {chi_target_mhz:.1f}\,\mathrm{{MHz}} \\ -\text{{Required coupling:}}\quad g = {float(g_design) * 1e3:.1f}\,\mathrm{{MHz}} \\ +\text{{Required coupling:}}\quad g_{{01}} = {float(g_design) * 1e3:.1f}\,\mathrm{{MHz}} \\ \text{{Verification (analytical):}}\quad \chi = {chi_verify_analytical * 1e3:.3f}\,\mathrm{{MHz}} \\ \text{{Verification (scQubits):}}\quad \chi = {chi_verify_scq * 1e3:.3f}\,\mathrm{{MHz}} """) ) # %% [markdown] -# ### Step 4: Convert to circuit parameters +# #### Step 4: Convert to circuit parameters # # Using the qpdk helper functions, we convert the Hamiltonian parameters # to circuit parameters: @@ -471,7 +786,7 @@ def _resonator_objective(length: float) -> float: ) # %% [markdown] -# ### Step 5: Layout parameters +# #### Step 5: Layout parameters # # The circuit parameters map directly to layout dimensions: @@ -536,15 +851,51 @@ def _resonator_objective(length: float) -> float: ) # %% [markdown] -# ## Summary: Complete Design Table +# ### Fluxonium Design # -# The table below summarises the full design flow from Hamiltonian -# parameters to layout parameters, with the dispersive shift as the -# central design target. +# Designing a fluxonium requires numerical diagonalization (via scQubits) since +# transition frequencies depend complexly on $E_J$, $E_C$, $E_L$, and flux. +# +# 1. **Numerical sweep**: Map $\omega_{01}$ and $\alpha$ vs. $E_L$ and $E_J$. +# 2. **Circuit mapping**: Convert energies to $L_s$, $L_J$, and $C_\Sigma$. +# 3. **Layout layout**: Map $L_s$ to `inductor_n_turns` in the qpdk `fluxonium` cell. +# +# #### Fluxonium circuit parameters + +# %% +from qpdk.models.qubit import el_to_inductance + +# Fluxonium circuit parameters from the Hamiltonian energies +C_sigma_flx = float(ec_to_capacitance(EC_flx)) +L_J_flx = float(ej_to_inductance(EJ_flx)) +L_s_flx = float(el_to_inductance(EL_flx)) + +display( + Math(rf""" +\textbf{{Fluxonium Circuit Parameters:}} \\ +E_J = {EJ_flx:.3f}\,\mathrm{{GHz}} \;\Rightarrow\; + L_J = {L_J_flx * 1e9:.2f}\,\mathrm{{nH}} \\ +E_C = {EC_flx:.3f}\,\mathrm{{GHz}} \;\Rightarrow\; + C_\Sigma = {C_sigma_flx * 1e15:.1f}\,\mathrm{{fF}} \\ +E_L = {EL_flx:.3f}\,\mathrm{{GHz}} \;\Rightarrow\; + L_s = {L_s_flx * 1e9:.1f}\,\mathrm{{nH}} +""") +) + +# %% [markdown] +# The superinductance $L_s \sim 300\,\mathrm{nH}$ is realized by a +# meander inductor made of a high-kinetic-inductance material (e.g. NbTiN +# or granular aluminium) {cite:p}`manucharyan_fluxonium_2009,nguyen_blueprint_2019`. +# The qpdk `fluxonium` cell parameterizes this as `inductor_n_turns`. + +# %% [markdown] +# ## Summary: Transmon Design +# +# From Hamiltonian design targets to circuit and layout parameters. # %% data = [ - ("Target", "Target dispersive shift $\\chi$", f"{chi_target_mhz:.1f}", "MHz"), + ("Target", "Dispersive shift $\\chi$", f"{chi_target_mhz:.1f}", "MHz"), ("Hamiltonian", "$E_J$", f"{EJ_design:.1f}", "GHz"), ("Hamiltonian", "$E_C$", f"{EC_design:.1f}", "GHz"), ("Hamiltonian", "$\\omega_t$", f"{omega_t_design:.3f}", "GHz"), @@ -569,6 +920,41 @@ def _resonator_objective(length: float) -> float: display_dataframe(df) +# %% [markdown] +# ## Summary: Fluxonium Design +# +# Core parameters for the GHz-range fluxonium biased at $\Phi_0/2$. + +# %% +data_flx = [ + ("Hamiltonian", "$E_J$", f"{EJ_flx:.3f}", "GHz"), + ("Hamiltonian", "$E_C$", f"{EC_flx:.3f}", "GHz"), + ("Hamiltonian", "$E_L$", f"{EL_flx:.3f}", "GHz"), + ("Hamiltonian", "$\\omega_\\text{flx}$", f"{f01_flx:.3f}", "GHz"), + ( + "Hamiltonian", + "$\\alpha_\\text{flx}$", + f"{anharmonicity_flx:.3f}", + "GHz", + ), + ("Hamiltonian", "Flux bias", "$\\Phi_0/2$", ""), + ("Circuit", "$C_\\Sigma$", f"{C_sigma_flx * 1e15:.1f}", "fF"), + ("Circuit", "$L_J$", f"{L_J_flx * 1e9:.2f}", "nH"), + ("Circuit", "$L_s$ (superinductance)", f"{L_s_flx * 1e9:.1f}", "nH"), + ( + "Dispersive shift", + "$\\chi$ ($g = 100$ MHz)", + f"{chi_flx * 1e3:.3f}", + "MHz", + ), +] + +df_flx = pl.DataFrame( + data_flx, schema=["Category", "Parameter", "Value", "Unit"], orient="row" +) + +display_dataframe(df_flx) + # %% [markdown] # ## References # diff --git a/qpdk/models/perturbation.py b/qpdk/models/perturbation.py index 7c87267e..fa112c1b 100644 --- a/qpdk/models/perturbation.py +++ b/qpdk/models/perturbation.py @@ -100,19 +100,20 @@ def dispersive_shift( .. math:: - \chi = \frac{2g^2}{\Delta - \alpha} - - \frac{2g^2}{\Delta} - - \frac{2g^2}{\omega_t + \omega_r + \alpha} - + \frac{2g^2}{\omega_t + \omega_r} + \chi = \frac{2g^2}{\Delta} + - \frac{2g^2}{\Delta - \alpha} + - \frac{2g^2}{\omega_t + \omega_r} + + \frac{2g^2}{\omega_t + \omega_r + \alpha} where :math:`\Delta = \omega_t - \omega_r`. The first two terms give the rotating-wave-approximation (RWA) contribution .. math:: - \chi_\text{RWA} = \frac{2 \alpha g^2}{\Delta(\Delta - \alpha)} + \chi_\text{RWA} = \frac{-2 \alpha g^2}{\Delta(\Delta - \alpha)} and the last two are corrections from the counter-rotating terms. + The sign follows the convention :math:`\chi = \omega_{r, |1\rangle} - \omega_{r, |0\rangle}`. All parameters are in GHz, and the returned value is also in GHz. @@ -132,11 +133,12 @@ def dispersive_shift( Δ = ω_t_ghz - ω_r_ghz # Full expression including counter-rotating terms + # Convention: chi = omega_r(1) - omega_r(0) return ( - 2 * g_ghz**2 / (Δ - α_ghz) - - 2 * g_ghz**2 / Δ - - 2 * g_ghz**2 / (ω_t_ghz + ω_r_ghz + α_ghz) - + 2 * g_ghz**2 / (ω_t_ghz + ω_r_ghz) + 2 * g_ghz**2 / Δ + - 2 * g_ghz**2 / (Δ - α_ghz) + - 2 * g_ghz**2 / (ω_t_ghz + ω_r_ghz) + + 2 * g_ghz**2 / (ω_t_ghz + ω_r_ghz + α_ghz) )