-
Notifications
You must be signed in to change notification settings - Fork 116
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add 3 notebooks outlining how to use the QCQMC code and interpret zenodo data.
- Loading branch information
Showing
9 changed files
with
1,128 additions
and
135 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,221 @@ | ||
{ | ||
"cells": [ | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"# Analyzing the Experimentally Reconstructed Wavefunctions\n", | ||
"\n", | ||
"The experimentally reconstructe wavefunctions from the \n", | ||
"[QCQMC](https://www.nature.com/articles/s41586-021-04351-z) paper are available\n", | ||
"for download from [zenodo](https://zenodo.org/records/10141262)." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"import urllib.request\n", | ||
"import tarfile\n", | ||
"\n", | ||
"stream = urllib.request.urlopen(\"https://zenodo.org/records/10141262/files/qcqmc_data.tar.gz\")\n", | ||
"\n", | ||
"with tarfile.open(fileobj=stream, mode='r|gz') as tf:\n", | ||
" tf.extractall()" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"# Look at the README from the downloaded data\n", | ||
"from IPython.display import Markdown, display\n", | ||
"display(Markdown('qcqmc_data/README.md'))" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"# Loading the wavefunctions\n", | ||
"\n", | ||
"Here we will reproduce some of the results from Section E of the SI from [QCQMC](https://www.nature.com/articles/s41586-021-04351-z).\n", | ||
"\n", | ||
"The variational energy of the trial wavefunction as a function of the number of cliffords used for shadow tomography is reported in Table S1, which we have reproduced here:\n", | ||
"\n", | ||
"| NCliffords | repeat 1 | repeat 2 | repeat 3 | repeat 4 |\n", | ||
"|---|---|---|---|---|\n", | ||
"| 10 | -1.800644 | -1.764747 | -1.813274 | -1.658202 |\n", | ||
"| 16 | -1.823041 | -1.802192 | -1.840494 | -1.730591 |\n", | ||
"| 28 | -1.906644 | -1.839835 | -1.843326 | -1.746749 |\n", | ||
"| 47 | -1.925654 | -1.888527 | -1.860863 | -1.809656 |\n", | ||
"| 80 | -1.909567 | -1.869456 | -1.887139 | -1.846339 |\n", | ||
"| 136 | -1.930880 | -1.902309 | -1.889992 | -1.879164 |\n", | ||
"| 229 | -1.944249 | -1.921523 | -1.903710 | -1.890947 |\n", | ||
"| 387 | -1.947362 | -1.934682 | -1.910477 | -1.901883 |\n", | ||
"| 652 | -1.952416 | -1.939853 | -1.912790 | -1.905250 |\n", | ||
"| 1100 | -1.955544 | -1.944651 | -1.915073 | -1.909122 |\n", | ||
"| 1856 | -1.955028 | -1.945966 | -1.909558 | -1.908038 |\n", | ||
"| 3129 | -1.953877 | -1.947763 | -1.913386 | -1.908835 |\n", | ||
"| 5276 | -1.954697 | -1.947323 | -1.912284 | -1.909315 |\n", | ||
"| 8896 | -1.954930 | -1.947458 | -1.913889 | -1.913068 |\n", | ||
"| 15000 | -1.954356 | -1.948894 | -1.913894 | -1.913082 |\n", | ||
"\n", | ||
"Each column represents an independented partitioned shadow tomography experiment.\n" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"We can reproduce this table from the data by using [FQE](https://quantumai.google/openfermion/fqe) to read the wavefunctions and Hamiltonian and recompute the variational energy of the shadow trial wavefunction.\n", | ||
"\n", | ||
"First we need to parse the wavefunction and Hamiltonian before computing the energy using FQE:" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"import fqe\n", | ||
"import h5py\n", | ||
"import numpy as np\n", | ||
"\n", | ||
"def compute_energy(wfn_file: str, ham_file: str) -> float:\n", | ||
" \"\"\"Compute the variational energy of the experimentally reconstructed wavefunction.\n", | ||
"\n", | ||
" Args:\n", | ||
" wfn_file: The path to the FQE wavefunction. \n", | ||
" ham_file: The path to the hamiltonian.\n", | ||
"\n", | ||
" Returns:\n", | ||
" The variational energy\n", | ||
" \"\"\"\n", | ||
" fqe_wfn = fqe.wavefunction.Wavefunction()\n", | ||
" fqe_wfn.read(filename=wfn_file)\n", | ||
" with h5py.File(ham_file, 'r') as fh5:\n", | ||
" ecore = fh5[\"e0\"][()]\n", | ||
" h1e_act = fh5[\"h1\"][:]\n", | ||
" eri_act = fh5[\"h2\"][:]\n", | ||
" # get integrals into openfermion order\n", | ||
" of_eris = np.transpose(eri_act, (0, 2, 3, 1))\n", | ||
" # ... and then into FQE format\n", | ||
" fqe_ham = fqe.hamiltonians.restricted_hamiltonian.RestrictedHamiltonian((h1e_act, np.einsum('ijlk', -0.5 * of_eris)), e_0=ecore)\n", | ||
" return fqe_wfn.expectationValue(fqe_ham)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Now we can glob all of the wavefunctions from the zenodo repo and recompute the variational energy:" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"import glob\n", | ||
"import pandas as pd\n", | ||
"for column in [1, 2, 3, 4]:\n", | ||
" wavefunctions = glob.glob(f'qcqmc_data/h4_sto3g/fqe_wfns/column{column}/wfn*')\n", | ||
" n_cliffords = [int(x.split('/')[-1].split('_')[-1]) for x in wavefunctions]\n", | ||
" energies = [compute_energy(wfn_file, f'qcqmc_data/h4_sto3g/fqe_hams/column{column}/chem_ham.h5').real for wfn_file in wavefunctions]\n", | ||
" if column == 1:\n", | ||
" df = pd.DataFrame({'n_clifford': n_cliffords, f'repeat {column}': energies})\n", | ||
" else:\n", | ||
" new_df = pd.DataFrame({'n_clifford': n_cliffords, f'repeat {column}': energies})\n", | ||
" df = pd.merge(df, new_df, on='n_clifford', how='outer')\n", | ||
"\n", | ||
"reproduced_table = df.sort_values(by='n_clifford')\n", | ||
"print(reproduced_table)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Given these inputs we can also re-run AFQMC using the shadow wavefunctions as a trial wavefuncktion. To do so, we first need to parse the wavefunction and hamiltonian which is provided in ipie format in the zenodo repo: " | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"from ipie.qmc.afqmc import AFQMC\n", | ||
"\n", | ||
"num_elec = (2, 2) # H4 molecule, 4 electrons, ms = 0 \n", | ||
"n_clifford = 15_000\n", | ||
"ham_file = 'qcqmc_data/h4_sto3g/ipie_ham/column3/ham.h5'\n", | ||
"wfn_file = f'qcqmc_data/h4_sto3g/ipie_wfns/column3/wfn_{n_clifford}.h5' \n", | ||
"afqmc = AFQMC.build_from_hdf5(num_elec, ham_file, wfn_file, num_blocks=1_000, num_walkers=100)\n", | ||
"afqmc.trial.calculate_energy(afqmc.system, afqmc.hamiltonian)\n", | ||
"afqmc.run(estimator_filename=f'h4_sto3g_n_clifford_{n_clifford}.h5')" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Finally we can analyze the result and compare it to the literature value which we agree with within error bars." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"from ipie.analysis.extraction import extract_observable\n", | ||
"import matplotlib.pyplot as plt\n", | ||
"from ipie.analysis.blocking import reblock_minimal \n", | ||
"\n", | ||
"paper_result = -1.96922\n", | ||
"analyzed_result = reblock_minimal(afqmc.estimators.filename, start_block=100)\n", | ||
"notebook_energy = analyzed_result.ETotal_ac.values[0]\n", | ||
"notebook_error = analyzed_result.ETotal_error_ac.values[0]\n", | ||
"\n", | ||
"data = extract_observable(afqmc.estimators.filename)\n", | ||
"plt.plot(data.ETotal, marker='o', label=\"AFQMC\", color=\"C0\")\n", | ||
"plt.axhline(paper_result, label=\"Exact Result\", color=\"C1\")\n", | ||
"plt.axhline(notebook_energy, label=\"Notebook result\", color=\"C2\")\n", | ||
"plt.legend()\n", | ||
"plt.xlabel(\"Block number\")\n", | ||
"plt.ylabel(\"Total Energy (Ha)\")\n", | ||
"print(f\"paper result = {paper_result}\")\n", | ||
"print(f\"notebook result = {notebook_energy} +/ {notebook_error}\")" | ||
] | ||
} | ||
], | ||
"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.12.3" | ||
} | ||
}, | ||
"nbformat": 4, | ||
"nbformat_minor": 2 | ||
} |
Oops, something went wrong.