Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Running notebooks locally requires additional dependencies located in [notebooks
| Quantum Circuit Born Machine | [Quantum_Circuit_Born_Machine.ipynb](notebooks/textbook/Quantum_Circuit_Born_Machine.ipynb) | [Benedetti2019](https://www.nature.com/articles/s41534-019-0157-8), [Liu2018](https://journals.aps.org/pra/abstract/10.1103/PhysRevA.98.062324) |
| QFT | [Quantum_Fourier_Transform.ipynb](notebooks/textbook/Quantum_Fourier_Transform.ipynb) | [Coppersmith2002](https://arxiv.org/abs/quant-ph/0201067) |
| QPE | [Quantum_Phase_Estimation_Algorithm.ipynb](notebooks/textbook/Quantum_Phase_Estimation_Algorithm.ipynb) | [Kitaev1995](https://arxiv.org/abs/quant-ph/9511026) |
| Quantum Counting | [Quantum_Counting_Algorithm.ipynb](notebooks/textbook/Quantum_Counting_Algorithm.ipynb) | [Brassard1998](https://arxiv.org/abs/quant-ph/9805082) |
| Quantum Walk | [Quantum_Walk.ipynb](notebooks/textbook/Quantum_Walk.ipynb) | [Childs2002](https://arxiv.org/abs/quant-ph/0209131) |
|Shor's| [Shors_Algorithm.ipynb](notebooks/textbook/Shors_Algorithm.ipynb) | [Shor1998](https://arxiv.org/abs/quant-ph/9508027) |
| Simon's | [Simons_Algorithm.ipynb](notebooks/textbook/Simons_Algorithm.ipynb) | [Simon1997](https://epubs.siam.org/doi/10.1137/S0097539796298637) |
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,15 @@
"\n",
"estimator = AdaptiveShotAllocator(paulis, coeffs)\n",
"\n",
"print(\"Identified commuting groups:\", [ [paulis[p] for p in commuting_group] for commuting_group in estimator.cliq])\n",
"print(\n",
" \"Identified commuting groups:\",\n",
" [[paulis[p] for p in commuting_group] for commuting_group in estimator.cliq],\n",
")\n",
"\n",
"print(\"Proposed allocation (shots per group) w/o prior measurement knowledge: \", estimator.incremental_shot_allocation(1200))"
"print(\n",
" \"Proposed allocation (shots per group) w/o prior measurement knowledge: \",\n",
" estimator.incremental_shot_allocation(1200),\n",
")"
]
},
{
Expand Down Expand Up @@ -178,20 +184,21 @@
" # To that end, we keep track of the measurements in a 2-D array, recording the number of different outcomes.\n",
" # DETAILS: `measurements[i][j][(-1,1)]`, for example, records the number of times observables `i` and `j`\n",
" # were measured together and recorded values of `-1` adn `1` respectively.\n",
" measurements = [[{(1, 1): 0, (1, -1): 0, (-1, 1): 0, (-1, -1): 0}\n",
" for _ in range(hamiltonian_terms)]\n",
" for _ in range(hamiltonian_terms)]\n",
" measurements = [\n",
" [{(1, 1): 0, (1, -1): 0, (-1, 1): 0, (-1, -1): 0} for _ in range(hamiltonian_terms)]\n",
" for _ in range(hamiltonian_terms)\n",
" ]\n",
"\n",
" # STEP 2: Perform the measurements ()\n",
" for shot_id in range(shots[0]):\n",
" state = np.random.randint(4)\n",
" measurement_IZ = 1 - 2*(state%2)\n",
" measurement_ZI = 1 - 2*(state//2)\n",
" measurement_IZ = 1 - 2 * (state % 2)\n",
" measurement_ZI = 1 - 2 * (state // 2)\n",
" measurements[0][0][(measurement_IZ, measurement_IZ)] += 1\n",
" measurements[1][1][(measurement_ZI, measurement_ZI)] += 1\n",
" measurements[0][1][(measurement_IZ, measurement_ZI)] += 1\n",
" measurements[1][0][(measurement_ZI, measurement_IZ)] += 1 \n",
" \n",
" measurements[1][0][(measurement_ZI, measurement_IZ)] += 1\n",
"\n",
" for shot_id in range(shots[1]):\n",
" measurement_XX = 1\n",
" measurements[2][2][(measurement_XX, measurement_XX)] += 1\n",
Expand Down Expand Up @@ -225,7 +232,9 @@
}
],
"source": [
"print(f\"Estimated expectation value: {estimator.expectation_from_measurements():.6f} ± {estimator.error_estimate():.6f}\")"
"print(\n",
" f\"Estimated expectation value: {estimator.expectation_from_measurements():.6f} ± {estimator.error_estimate():.6f}\"\n",
")"
]
},
{
Expand Down Expand Up @@ -333,15 +342,64 @@
],
"source": [
"# Note that, as would be the case in practice, we have removed the IIII term and its cofficient from the calculations below\n",
"paulis = ['IIII', 'XXXI', 'XXXZ', 'XYYI', 'XZXI', 'XZXZ', 'YXYI', 'YXYZ', 'YYXI', 'YZYI', 'YZYZ', 'ZIII',\n",
" 'ZXZI', 'ZXZZ', 'ZXIZ', 'ZZII', 'ZZZI', 'ZZZZ', 'ZIZI', 'ZIZZ', 'IXII', 'IXZI', 'IXIZ', 'IZII',\n",
" 'IZZZ', 'IZIZ', 'IIZI'][1:]\n",
"coeffs = [-14.440090444958097, 0.01396784712709576, 0.0050449972385411684, 0.008922759379312662, 0.004572316311895031, \n",
" 0.004572316311895031, 0.01396784712709576, 0.0050449972385411684, -0.008922759379312662, 0.004572316311895031, \n",
" 0.004572316311895031, 0.37322478932293823, 0.01396784712709576, 0.0050449972385411684, -0.008922759379312663, \n",
" 0.37322478932293823, 0.06754531038829523, 0.06754531038829523, 0.0629729940764002, 0.0629729940764002, \n",
" -0.0050449972385411684, 0.008922759379312663, -0.01396784712709576, 0.1377331477309217, 0.18592768458263145, \n",
" 0.10062930161995226, 0.18592768458263148][1:]\n",
"paulis = [\n",
" \"IIII\",\n",
" \"XXXI\",\n",
" \"XXXZ\",\n",
" \"XYYI\",\n",
" \"XZXI\",\n",
" \"XZXZ\",\n",
" \"YXYI\",\n",
" \"YXYZ\",\n",
" \"YYXI\",\n",
" \"YZYI\",\n",
" \"YZYZ\",\n",
" \"ZIII\",\n",
" \"ZXZI\",\n",
" \"ZXZZ\",\n",
" \"ZXIZ\",\n",
" \"ZZII\",\n",
" \"ZZZI\",\n",
" \"ZZZZ\",\n",
" \"ZIZI\",\n",
" \"ZIZZ\",\n",
" \"IXII\",\n",
" \"IXZI\",\n",
" \"IXIZ\",\n",
" \"IZII\",\n",
" \"IZZZ\",\n",
" \"IZIZ\",\n",
" \"IIZI\",\n",
"][1:]\n",
"coeffs = [\n",
" -14.440090444958097,\n",
" 0.01396784712709576,\n",
" 0.0050449972385411684,\n",
" 0.008922759379312662,\n",
" 0.004572316311895031,\n",
" 0.004572316311895031,\n",
" 0.01396784712709576,\n",
" 0.0050449972385411684,\n",
" -0.008922759379312662,\n",
" 0.004572316311895031,\n",
" 0.004572316311895031,\n",
" 0.37322478932293823,\n",
" 0.01396784712709576,\n",
" 0.0050449972385411684,\n",
" -0.008922759379312663,\n",
" 0.37322478932293823,\n",
" 0.06754531038829523,\n",
" 0.06754531038829523,\n",
" 0.0629729940764002,\n",
" 0.0629729940764002,\n",
" -0.0050449972385411684,\n",
" 0.008922759379312663,\n",
" -0.01396784712709576,\n",
" 0.1377331477309217,\n",
" 0.18592768458263145,\n",
" 0.10062930161995226,\n",
" 0.18592768458263148,\n",
"][1:]\n",
"\n",
"print(\"4-qubit BeH Hamiltonian (electronic, Bravyi-Kitaev mapping).\")\n",
"print(f\"Number of qubits: {len(paulis[0])}\")\n",
Expand Down Expand Up @@ -500,7 +558,9 @@
"print(f\"Estimated expectation: {e_estimated:.6f}\")\n",
"print(f\"Estimated standard error: {error_estimate:.6f}\")\n",
"\n",
"print(f\"Actual difference: {abs(e_exact - e_estimated):.6f} ({100*abs(e_exact - e_estimated)/abs(e_exact):.2f}%)\")\n",
"print(\n",
" f\"Actual difference: {abs(e_exact - e_estimated):.6f} ({100 * abs(e_exact - e_estimated) / abs(e_exact):.2f}%)\"\n",
")\n",
"print(f\"Final shot allocation: {estimator.shots}\")\n",
"print(f\"Total shots used: {sum(estimator.shots)}\")"
]
Expand Down Expand Up @@ -592,34 +652,29 @@
"\n",
"# Run comparison\n",
"num_runs = 50\n",
"results = {\n",
" 'Random': [],\n",
" 'Uniform': [],\n",
" 'Weighted': [],\n",
" 'Adaptive': [] \n",
"}\n",
"results = {\"Random\": [], \"Uniform\": [], \"Weighted\": [], \"Adaptive\": []}\n",
"\n",
"print(f\"Running {num_runs} trials for each strategy...\")\n",
"for i in tqdm(range(num_runs)):\n",
" # Reset the allocator every time so that we don't take advantage of prior measurement knowledge\n",
" estimator.reset()\n",
" \n",
" results['Adaptive'].append(\n",
"\n",
" results[\"Adaptive\"].append(\n",
" estimator.expectation_from_measurements(\n",
" run_adaptive_allocation(device, circuit, estimator, shots_per_round, num_rounds)\n",
" )\n",
" )\n",
" results['Uniform'].append(\n",
" results[\"Uniform\"].append(\n",
" estimator.expectation_from_measurements(\n",
" run_fixed_allocation(device, circuit, estimator, uniform_shots)\n",
" )\n",
" )\n",
" results['Random'].append(\n",
" results[\"Random\"].append(\n",
" estimator.expectation_from_measurements(\n",
" run_fixed_allocation(device, circuit, estimator, random_shots)\n",
" )\n",
" )\n",
" results['Weighted'].append(\n",
" results[\"Weighted\"].append(\n",
" estimator.expectation_from_measurements(\n",
" run_fixed_allocation(device, circuit, estimator, weighted_shots)\n",
" )\n",
Expand Down Expand Up @@ -693,14 +748,9 @@
"# Plot results with separate subplots (squashed aspect ratio)\n",
"fig, axes = plt.subplots(4, 1, figsize=(10, 6), sharex=True)\n",
"\n",
"colors = {\n",
" 'Random': 'red', \n",
" 'Uniform': 'orange',\n",
" 'Weighted': 'blue',\n",
" 'Adaptive': 'green' \n",
"}\n",
"colors = {\"Random\": \"red\", \"Uniform\": \"orange\", \"Weighted\": \"blue\", \"Adaptive\": \"green\"}\n",
"\n",
"strategies = ['Random', 'Uniform', 'Weighted', 'Adaptive']\n",
"strategies = [\"Random\", \"Uniform\", \"Weighted\", \"Adaptive\"]\n",
"\n",
"# First pass: calculate all histograms to find the maximum bar height\n",
"bins = np.arange(0.0, 0.05, 0.001)\n",
Expand All @@ -716,35 +766,44 @@
"for i, strategy in enumerate(strategies):\n",
" values = results[strategy]\n",
" errors = np.abs(np.array(values) - e_exact)\n",
" \n",
"\n",
" # Plot histogram in the corresponding subplot\n",
" axes[i].hist(errors, bins=bins, \n",
" color=colors[strategy], alpha=0.7, edgecolor='black', linewidth=0.5,\n",
" label=strategy)\n",
" \n",
" axes[i].hist(\n",
" errors,\n",
" bins=bins,\n",
" color=colors[strategy],\n",
" alpha=0.7,\n",
" edgecolor=\"black\",\n",
" linewidth=0.5,\n",
" label=strategy,\n",
" )\n",
"\n",
" # Add statistics as legend\n",
" mean_error = np.mean(errors)\n",
" std_error = np.std(errors)\n",
" \n",
" axes[i].set_ylabel('Frequency')\n",
"\n",
" axes[i].set_ylabel(\"Frequency\")\n",
" axes[i].grid(True, alpha=0.3)\n",
" \n",
"\n",
" # Set aspect ratio and y-axis limits\n",
" axes[i].set_aspect(aspect='auto')\n",
" axes[i].set_aspect(aspect=\"auto\")\n",
" axes[i].set_ylim(0, max_height * 1.05) # Add 5% padding at top\n",
" \n",
"\n",
" # Set integer y-ticks\n",
" axes[i].yaxis.set_major_locator(MaxNLocator(integer=True))\n",
" \n",
"\n",
" # Add legend with strategy name and statistics\n",
" axes[i].legend([f'{strategy} (Mean: {mean_error:.6f}, Std: {std_error:.6f})'], \n",
" loc='upper right', framealpha=0.9)\n",
" axes[i].legend(\n",
" [f\"{strategy} (Mean: {mean_error:.6f}, Std: {std_error:.6f})\"],\n",
" loc=\"upper right\",\n",
" framealpha=0.9,\n",
" )\n",
"\n",
"# Set common x-label only on the bottom subplot\n",
"axes[-1].set_xlabel('Absolute Error')\n",
"axes[-1].set_xlabel(\"Absolute Error\")\n",
"\n",
"# Add overall title with more space\n",
"fig.suptitle('Distribution of Estimation Errors by Strategy', fontsize=16, y=0.98)\n",
"fig.suptitle(\"Distribution of Estimation Errors by Strategy\", fontsize=16, y=0.98)\n",
"\n",
"plt.tight_layout()\n",
"plt.subplots_adjust(top=0.93) # Add space between suptitle and subplots\n",
Expand All @@ -767,35 +826,46 @@
"def visualize_shot_allocation_comparison(strategies, allocations, total_shots):\n",
" \"\"\"\n",
" Visualize different shot allocation strategies for comparison.\n",
" \n",
"\n",
" Args:\n",
" strategies (list): Names of the strategies to compare\n",
" allocations (list): List of shot allocations for each strategy\n",
" total_shots (int): Total number of shots used\n",
" \"\"\"\n",
" plt.figure(figsize=(12, 6))\n",
" \n",
"\n",
" # Create a bar chart for each strategy\n",
" x = np.arange(len(allocations[0]))\n",
" width = 0.8 / len(strategies)\n",
" \n",
"\n",
" for i, (strategy, allocation) in enumerate(zip(strategies, allocations)):\n",
" plt.bar(x + i*width - 0.4 + width/2, allocation, width, \n",
" label=strategy, alpha=0.7, color = colors[strategy])\n",
" \n",
" plt.xlabel('Measurement Group')\n",
" plt.ylabel('Number of Shots')\n",
" plt.title(f'Comparison of Shot Allocation Strategies (Total: {total_shots} shots)')\n",
" plt.xticks(x, [f'Group {i+1}' for i in x])\n",
" plt.bar(\n",
" x + i * width - 0.4 + width / 2,\n",
" allocation,\n",
" width,\n",
" label=strategy,\n",
" alpha=0.7,\n",
" color=colors[strategy],\n",
" )\n",
"\n",
" plt.xlabel(\"Measurement Group\")\n",
" plt.ylabel(\"Number of Shots\")\n",
" plt.title(f\"Comparison of Shot Allocation Strategies (Total: {total_shots} shots)\")\n",
" plt.xticks(x, [f\"Group {i + 1}\" for i in x])\n",
" plt.legend()\n",
" plt.grid(True, alpha=0.3)\n",
" \n",
"\n",
" # Add percentages on top of each bar\n",
" for i, (strategy, allocation) in enumerate(zip(strategies, allocations)):\n",
" for j, shots in enumerate(allocation):\n",
" percentage = 100 * shots / total_shots\n",
" plt.text(j + i*width - 0.4 + width/2, shots + 5, \n",
" f'{percentage:.1f}%', ha='center', fontsize=8)"
" plt.text(\n",
" j + i * width - 0.4 + width / 2,\n",
" shots + 5,\n",
" f\"{percentage:.1f}%\",\n",
" ha=\"center\",\n",
" fontsize=8,\n",
" )"
]
},
{
Expand All @@ -815,7 +885,11 @@
}
],
"source": [
"visualize_shot_allocation_comparison([strategy for strategy in results.keys()], [random_shots, uniform_shots, weighted_shots, estimator.shots], sum(uniform_shots))"
"visualize_shot_allocation_comparison(\n",
" [strategy for strategy in results.keys()],\n",
" [random_shots, uniform_shots, weighted_shots, estimator.shots],\n",
" sum(uniform_shots),\n",
")"
]
},
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

from typing import List

import numpy as np
Expand All @@ -15,6 +14,7 @@

_localSim = LocalSimulator()


def create_random_state(num_qubits: int = 4) -> Circuit:
"""
Generate a quantum circuit with random rotations and entanglement.
Expand All @@ -33,7 +33,7 @@ def create_random_state(num_qubits: int = 4) -> Circuit:

# Entangling layer
for i in range(num_qubits - 1):
circ.cnot(control=i, target=i+1)
circ.cnot(control=i, target=i + 1)

# Second layer of rotations
for i in range(num_qubits):
Expand Down Expand Up @@ -73,10 +73,12 @@ def get_exact_expectation(circuit: Circuit, paulis: List[str], coeffs: List[floa
e_exact += c * result.values[0]
return e_exact


"""
Utilities for allocating measurement shots across different measurement groups.
"""


def get_uniform_shots(num_groups: int, total_shots: int) -> List[int]:
"""
Generate uniform shot allocation across measurement groups.
Expand Down Expand Up @@ -132,4 +134,3 @@ def get_weighted_shots(cliq: List[List[int]], coeffs: List[float], total_shots:
for i in range(remainder):
shots[i] += 1
return shots.tolist()

2 changes: 1 addition & 1 deletion notebooks/textbook/CHSH_Inequality.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@
],
"source": [
"print(\n",
" f\"Estimated cost to run this example: {tracker.qpu_tasks_cost() + tracker.simulator_tasks_cost() :.2f} USD\"\n",
" f\"Estimated cost to run this example: {tracker.qpu_tasks_cost() + tracker.simulator_tasks_cost():.2f} USD\"\n",
")"
]
},
Expand Down
Loading