diff --git a/docs/quantum_chess/concepts.ipynb b/docs/quantum_chess/concepts.ipynb index be15de2b..21e0067b 100644 --- a/docs/quantum_chess/concepts.ipynb +++ b/docs/quantum_chess/concepts.ipynb @@ -313,7 +313,7 @@ "outputs": [], "source": [ "def normal_move(s: cirq.Qid, t: cirq.Qid):\n", - " \"\"\" A normal move in quantum chess.\n", + " \"\"\"A normal move in quantum chess.\n", "\n", " This function takes two qubits and returns a generator\n", " that performs a normal move that moves a piece from the\n", @@ -323,10 +323,11 @@ " s: source qubit (square where piece starts)\n", " t: target qubit (square to move piece to)\n", " \"\"\"\n", - " yield cirq.ISWAP(s,t)\n", + " yield cirq.ISWAP(s, t)\n", + "\n", "\n", "def split_move(s: cirq.Qid, t1: cirq.Qid, t2: cirq.Qid):\n", - " \"\"\" A Split move in quantum chess.\n", + " \"\"\"A Split move in quantum chess.\n", "\n", " This function takes three qubits and returns a generator\n", " that performs a split move from the source qubit to the\n", @@ -337,8 +338,8 @@ " t1: target qubit (first square to move piece to)\n", " t2: target qubit (second square to move piece to)\n", " \"\"\"\n", - " yield cirq.ISWAP(s,t1)**0.5\n", - " yield cirq.ISWAP(s,t2)\n", + " yield cirq.ISWAP(s, t1) ** 0.5\n", + " yield cirq.ISWAP(s, t2)\n", "\n", "\n", "def slide_move(s: cirq.Qid, t: cirq.Qid, p: cirq.Qid):\n", @@ -355,7 +356,8 @@ " t: target qubit (square to move piece to)\n", " p: path qubit that determines whether move should occur\n", " \"\"\"\n", - " yield cirq.ISWAP(s,t).controlled_by(p)\n", + " yield cirq.ISWAP(s, t).controlled_by(p)\n", + "\n", "\n", "def place_piece(s: cirq.Qid):\n", " \"\"\"Place a piece on the board.\n", @@ -384,15 +386,15 @@ }, "outputs": [], "source": [ - "a1 = cirq.NamedQubit('a1')\n", - "a2 = cirq.NamedQubit('a2')\n", - "a3 = cirq.NamedQubit('a3')\n", - "b1 = cirq.NamedQubit('b1')\n", - "b2 = cirq.NamedQubit('b2')\n", - "b3 = cirq.NamedQubit('b3')\n", - "c1 = cirq.NamedQubit('c1')\n", - "c2 = cirq.NamedQubit('c2')\n", - "c3 = cirq.NamedQubit('c3')\n", + "a1 = cirq.NamedQubit(\"a1\")\n", + "a2 = cirq.NamedQubit(\"a2\")\n", + "a3 = cirq.NamedQubit(\"a3\")\n", + "b1 = cirq.NamedQubit(\"b1\")\n", + "b2 = cirq.NamedQubit(\"b2\")\n", + "b3 = cirq.NamedQubit(\"b3\")\n", + "c1 = cirq.NamedQubit(\"c1\")\n", + "c2 = cirq.NamedQubit(\"c2\")\n", + "c3 = cirq.NamedQubit(\"c3\")\n", "\n", "all_squares = [a1, a2, a3, b1, b2, b3, c1, c2, c3]" ] @@ -547,15 +549,15 @@ "\n", "\n", "# Let's print out the circuit to see what it does\n", - "print('Exclusion move circuit:')\n", + "print(\"Exclusion move circuit:\")\n", "print(exclusion_move_circuit)\n", "\n", "# This time, we have a measurement in the circuit.\n", "# Let's simulate it several times to see what happens.\n", "sim = cirq.Simulator()\n", - "print('Measurement Results:')\n", + "print(\"Measurement Results:\")\n", "for t in range(8):\n", - " print(f'--- Outcome #{t} ---')\n", + " print(f\"--- Outcome #{t} ---\")\n", " print(sim.simulate(exclusion_move_circuit))" ] }, @@ -622,20 +624,20 @@ ], "source": [ "# Define a measurement operation that measures all the squares\n", - "measure_all_squares = cirq.measure(*all_squares, key='all')\n", + "measure_all_squares = cirq.measure(*all_squares, key=\"all\")\n", "\n", "# Measure all squares at the end of the circuit\n", "king_moves_measured = king_moves + measure_all_squares\n", "exclusion_move_measured = exclusion_moves + measure_all_squares\n", "\n", - "print('Split moving the king:')\n", + "print(\"Split moving the king:\")\n", "print(king_moves_measured)\n", "results = sim.run(king_moves_measured, repetitions=1)\n", "print(results)\n", "\n", - "print('Attempting an exclusion move:')\n", + "print(\"Attempting an exclusion move:\")\n", "results = sim.run(exclusion_move_measured, repetitions=1)\n", - "print(results)\n" + "print(results)" ] }, { @@ -677,16 +679,17 @@ " \"\"\"\n", " sampling_frequency = {}\n", " for idx, sq in enumerate(all_squares):\n", - " sampling_frequency[str(sq)]=results.measurements['all'][:, idx].sum()\n", + " sampling_frequency[str(sq)] = results.measurements[\"all\"][:, idx].sum()\n", " return sampling_frequency\n", "\n", + "\n", "# Let's test out this histogram on the two circuits we've examined so far:\n", "\n", - "print('Split moving the king:')\n", + "print(\"Split moving the king:\")\n", "split_results = sim.run(king_moves_measured, repetitions=1000)\n", "print(histogram_of_squares(split_results))\n", "\n", - "print('Attempting an exclusion move:')\n", + "print(\"Attempting an exclusion move:\")\n", "exclusion_results = sim.run(exclusion_move_measured, repetitions=1000)\n", "print(histogram_of_squares(exclusion_results))" ] @@ -761,17 +764,20 @@ ], "source": [ "# Calculate the state of the board after moving the queen\n", - "after_exclusion_move = cirq.Circuit(\n", - " place_piece(a1),\n", - " place_piece(a3),\n", - " split_move(a1, b1, b2),\n", - " split_move(b1, c1, c2),\n", - " normal_move(a3, b2),\n", - ") + measure_all_squares\n", + "after_exclusion_move = (\n", + " cirq.Circuit(\n", + " place_piece(a1),\n", + " place_piece(a3),\n", + " split_move(a1, b1, b2),\n", + " split_move(b1, c1, c2),\n", + " normal_move(a3, b2),\n", + " )\n", + " + measure_all_squares\n", + ")\n", "\n", "# Compute statistics for the pieces.\n", "after_results = this_sim.run(after_exclusion_move, repetitions=1000)\n", - "print(histogram_of_squares(after_results))\n" + "print(histogram_of_squares(after_results))" ] }, { @@ -845,13 +851,16 @@ "source": [ "# Perform all the moves, including the exclusion move.\n", "# Afterwards, measure all qubits.\n", - "after_exclusion_move = cirq.Circuit(\n", - " place_piece(a1),\n", - " place_piece(a3),\n", - " split_move(a1, b1, b2),\n", - " split_move(b1, c1, c2),\n", - " normal_move(a3, b2),\n", - ") + measure_all_squares\n", + "after_exclusion_move = (\n", + " cirq.Circuit(\n", + " place_piece(a1),\n", + " place_piece(a3),\n", + " split_move(a1, b1, b2),\n", + " split_move(b1, c1, c2),\n", + " normal_move(a3, b2),\n", + " )\n", + " + measure_all_squares\n", + ")\n", "\n", "# Define a function to post select on the result.\n", "def histogram_post_select(results, square_idx, value):\n", @@ -868,17 +877,18 @@ " value: whether the qubit post-selected should be one or zero.\n", " \"\"\"\n", " sampling_frequency = {}\n", - " all_results = results.measurements['all']\n", - " post_selected_results = all_results[all_results[:,square_idx]==value]\n", + " all_results = results.measurements[\"all\"]\n", + " post_selected_results = all_results[all_results[:, square_idx] == value]\n", " for idx, sq in enumerate(all_squares):\n", - " sampling_frequency[str(sq)]=post_selected_results[:, idx].sum()\n", + " sampling_frequency[str(sq)] = post_selected_results[:, idx].sum()\n", " return sampling_frequency\n", "\n", + "\n", "# Compute statistics for the pieces.\n", "after_results = this_sim.run(after_exclusion_move, repetitions=1000)\n", "\n", "# Find the index of 'a3' (it should be at index 2)\n", - "post_select_idx = all_squares.index(cirq.NamedQubit('a3'))\n", + "post_select_idx = all_squares.index(cirq.NamedQubit(\"a3\"))\n", "\n", "# Print out the post-selected histogram\n", "print(histogram_post_select(after_results, post_select_idx, 0))" @@ -920,10 +930,12 @@ " normal_move(a3, b2),\n", " normal_move(c2, c3),\n", ")\n", - "after_exclusion_move = after_exclusion_without_measurement + measure_all_squares\n", + "after_exclusion_move = (\n", + " after_exclusion_without_measurement + measure_all_squares\n", + ")\n", "\n", "after_results = this_sim.run(after_exclusion_move, repetitions=1000)\n", - "post_select_idx = all_squares.index(cirq.NamedQubit('a3'))\n", + "post_select_idx = all_squares.index(cirq.NamedQubit(\"a3\"))\n", "print(histogram_post_select(after_results, post_select_idx, 0))" ] }, @@ -976,15 +988,19 @@ ], "source": [ "import cirq.contrib.noise_models as ccn\n", - "noise_model = ccn.DepolarizingNoiseModel(depol_prob=0.01)\n", - "noisy=cirq.DensityMatrixSimulator(noise=noise_model)\n", "\n", - "king_moves_measured = cirq.Circuit(\n", - " place_piece(a1),\n", - " split_move(a1, b1, b2),\n", - " split_move(b1, c1, c2),\n", - " split_move(b2, b3, c3),\n", - ") + measure_all_squares\n", + "noise_model = ccn.DepolarizingNoiseModel(depol_prob=0.01)\n", + "noisy = cirq.DensityMatrixSimulator(noise=noise_model)\n", + "\n", + "king_moves_measured = (\n", + " cirq.Circuit(\n", + " place_piece(a1),\n", + " split_move(a1, b1, b2),\n", + " split_move(b1, c1, c2),\n", + " split_move(b2, b3, c3),\n", + " )\n", + " + measure_all_squares\n", + ")\n", "\n", "print(histogram_of_squares(noisy.run(king_moves_measured, repetitions=1000)))" ] @@ -1031,13 +1047,14 @@ " discarded.\n", " \"\"\"\n", " sampling_frequency = {}\n", - " all_results = results.measurements['all']\n", + " all_results = results.measurements[\"all\"]\n", " # Select only rows where the row sums to one.\n", - " post_selected_results = all_results[all_results[:,:].sum(axis=1)==1]\n", + " post_selected_results = all_results[all_results[:, :].sum(axis=1) == 1]\n", " for idx, sq in enumerate(all_squares):\n", - " sampling_frequency[str(sq)]=post_selected_results[:, idx].sum()\n", + " sampling_frequency[str(sq)] = post_selected_results[:, idx].sum()\n", " return sampling_frequency\n", "\n", + "\n", "results = noisy.run(king_moves_measured, repetitions=1000)\n", "print(remove_multi_kings(results))" ] @@ -1093,18 +1110,23 @@ "except:\n", " _secret_lazy_value = (random.random() + 2.0) / 4.0\n", "\n", + "\n", "def lazy_move(source, target):\n", " return cirq.ISWAP(source, target) ** _secret_lazy_value\n", "\n", - "king_maybe_moves = cirq.Circuit(\n", - " place_piece(a1),\n", - " lazy_move(a1,a2),\n", - " lazy_move(a2,a3),\n", - " lazy_move(a3,b3),\n", - " lazy_move(b3,c3)\n", - ") + measure_all_squares\n", "\n", - "print(histogram_of_squares(sim.run(king_maybe_moves, repetitions=1000)))\n" + "king_maybe_moves = (\n", + " cirq.Circuit(\n", + " place_piece(a1),\n", + " lazy_move(a1, a2),\n", + " lazy_move(a2, a3),\n", + " lazy_move(a3, b3),\n", + " lazy_move(b3, c3),\n", + " )\n", + " + measure_all_squares\n", + ")\n", + "\n", + "print(histogram_of_squares(sim.run(king_maybe_moves, repetitions=1000)))" ] }, { @@ -1140,13 +1162,16 @@ "source": [ "over_rotation_amount = 1.46\n", "\n", - "king_probably_moves = cirq.Circuit(\n", - " place_piece(a1),\n", - " lazy_move(a1,a2) ** over_rotation_amount,\n", - " lazy_move(a2,a3) ** over_rotation_amount,\n", - " lazy_move(a3,b3) ** over_rotation_amount,\n", - " lazy_move(b3,c3) ** over_rotation_amount\n", - ") + measure_all_squares\n", + "king_probably_moves = (\n", + " cirq.Circuit(\n", + " place_piece(a1),\n", + " lazy_move(a1, a2) ** over_rotation_amount,\n", + " lazy_move(a2, a3) ** over_rotation_amount,\n", + " lazy_move(a3, b3) ** over_rotation_amount,\n", + " lazy_move(b3, c3) ** over_rotation_amount,\n", + " )\n", + " + measure_all_squares\n", + ")\n", "\n", "print(histogram_of_squares(sim.run(king_probably_moves, repetitions=1000)))" ] @@ -1190,27 +1215,28 @@ "# We will then measure how many times the king actually gets there.\n", "king_calibration = cirq.Circuit(\n", " place_piece(a1),\n", - " lazy_move(a1,a2) ** sympy.Symbol('r'),\n", - " cirq.measure(a1, a2, key='all') )\n", + " lazy_move(a1, a2) ** sympy.Symbol(\"r\"),\n", + " cirq.measure(a1, a2, key=\"all\"),\n", + ")\n", "\n", "# We will try all rotation values from 1.0 to 3.0 at intervals of 0.01\n", - "rotation_parameter = cirq.Linspace('r', 1.0, 3.0, 200)\n", - "results = sim.run_sweep(king_calibration,\n", - " params=rotation_parameter,\n", - " repetitions=1000)\n", + "rotation_parameter = cirq.Linspace(\"r\", 1.0, 3.0, 200)\n", + "results = sim.run_sweep(\n", + " king_calibration, params=rotation_parameter, repetitions=1000\n", + ")\n", "\n", "# Then we will keep track of the best value we found so far.\n", "best_over_rotation = 1.0\n", "most_correct_swaps = 0\n", "for result in results:\n", - " num_correct_swaps = result.measurements['all'][:,1].sum()\n", + " num_correct_swaps = result.measurements[\"all\"][:, 1].sum()\n", " if num_correct_swaps > most_correct_swaps:\n", " most_correct_swaps = num_correct_swaps\n", - " best_over_rotation = result.params['r']\n", + " best_over_rotation = result.params[\"r\"]\n", "\n", - "print(f'Best over rotation value found: {best_over_rotation}')\n", - "print(f'Implied secret swap value: {1/best_over_rotation}')\n", - "print(f'Actual secret swap value: {_secret_lazy_value}')" + "print(f\"Best over rotation value found: {best_over_rotation}\")\n", + "print(f\"Implied secret swap value: {1/best_over_rotation}\")\n", + "print(f\"Actual secret swap value: {_secret_lazy_value}\")" ] }, { @@ -1281,17 +1307,17 @@ } ], "source": [ - "print('Decomposing H gate')\n", + "print(\"Decomposing H gate\")\n", "decomposed_h = cirq.decompose_once(cirq.H(a1))\n", "print(decomposed_h)\n", "print(cirq.Circuit(decomposed_h))\n", "print()\n", "\n", - "print('Decomposing CNOT gate')\n", + "print(\"Decomposing CNOT gate\")\n", "decomposed_cnot = cirq.decompose_once(cirq.CNOT(a1, a2))\n", "print(decomposed_cnot)\n", "print(cirq.Circuit(decomposed_cnot))\n", - "print()\n" + "print()" ] }, { @@ -1333,7 +1359,7 @@ } ], "source": [ - "cirq.decompose_once(cirq.ISWAP(a1,a3).controlled_by(a2))" + "cirq.decompose_once(cirq.ISWAP(a1, a3).controlled_by(a2))" ] }, { @@ -1398,11 +1424,11 @@ } ], "source": [ - "c_iswap = cirq.Circuit(cirq.ISWAP(a1,a3).controlled_by(a2))\n", + "c_iswap = cirq.Circuit(cirq.ISWAP(a1, a3).controlled_by(a2))\n", "try:\n", - " cirq.google.optimized_for_sycamore(c_iswap, optimizer_type='sqrt_iswap')\n", + " cirq.google.optimized_for_sycamore(c_iswap, optimizer_type=\"sqrt_iswap\")\n", "except Exception as e:\n", - " print('An error occurred while attempting to optimize: ')\n", + " print(\"An error occurred while attempting to optimize: \")\n", " print(e)" ] }, @@ -1455,15 +1481,17 @@ "import numpy as np\n", "\n", "c_swap = cirq.Circuit(cirq.SWAP(a1, a3).controlled_by(a2))\n", - "c_swap_decomposed = cirq.Circuit(cirq.CNOT(a1, a3), cirq.TOFFOLI(a2, a3, a1), cirq.CNOT(a1, a3))\n", + "c_swap_decomposed = cirq.Circuit(\n", + " cirq.CNOT(a1, a3), cirq.TOFFOLI(a2, a3, a1), cirq.CNOT(a1, a3)\n", + ")\n", "c_swap_unitary = cirq.unitary(c_swap)\n", "c_swap_decomposed_unitary = cirq.unitary(c_swap_decomposed)\n", "\n", - "print('Unitary of controlled SWAP')\n", + "print(\"Unitary of controlled SWAP\")\n", "print(c_swap_unitary)\n", - "print('Unitary of decomposed circuit')\n", + "print(\"Unitary of decomposed circuit\")\n", "print(c_swap_decomposed_unitary)\n", - "print('Are they equal?')\n", + "print(\"Are they equal?\")\n", "print(np.isclose(c_swap_unitary, c_swap_decomposed_unitary).all())" ] }, @@ -1516,15 +1544,20 @@ "import numpy as np\n", "\n", "c_iswap = cirq.Circuit(cirq.ISWAP(a3, a2).controlled_by(a1))\n", - "c_iswap_decomposed = cirq.Circuit(cirq.CNOT(a3, a2), cirq.TOFFOLI(a1, a2, a3), cirq.CZ(a1, a2) ** 0.5, cirq.CNOT(a3, a2))\n", + "c_iswap_decomposed = cirq.Circuit(\n", + " cirq.CNOT(a3, a2),\n", + " cirq.TOFFOLI(a1, a2, a3),\n", + " cirq.CZ(a1, a2) ** 0.5,\n", + " cirq.CNOT(a3, a2),\n", + ")\n", "c_iswap_unitary = cirq.unitary(c_iswap)\n", "c_iswap_decomposed_unitary = cirq.unitary(c_iswap_decomposed)\n", "\n", - "print('Unitary of controlled iSWAP')\n", + "print(\"Unitary of controlled iSWAP\")\n", "print(c_iswap_unitary)\n", - "print('Unitary of decomposed circuit')\n", + "print(\"Unitary of decomposed circuit\")\n", "print(c_iswap_decomposed_unitary)\n", - "print('Are they equal?')\n", + "print(\"Are they equal?\")\n", "print(np.isclose(c_iswap_unitary, c_iswap_decomposed_unitary).all())" ] }, @@ -1558,9 +1591,10 @@ } ], "source": [ - "decomposed_circuit = cirq.google.optimized_for_sycamore(c_iswap_decomposed, \n", - " optimizer_type='sqrt_iswap')\n", - "print(f'Circuit: {len(decomposed_circuit)} moments')\n", + "decomposed_circuit = cirq.google.optimized_for_sycamore(\n", + " c_iswap_decomposed, optimizer_type=\"sqrt_iswap\"\n", + ")\n", + "print(f\"Circuit: {len(decomposed_circuit)} moments\")\n", "print(decomposed_circuit)" ] }, @@ -1714,25 +1748,28 @@ ], "source": [ "class IswapDecomposer(cirq.PointOptimizer):\n", - " \"\"\"Optimizer that decomposes iSWAPs into iSWAP ** 0.5 operations.\n", - " \"\"\"\n", - " \n", - " def optimization_at(self, circuit: cirq.Circuit, index: int,\n", - " op: cirq.Operation\n", - " ) -> Optional[cirq.PointOptimizationSummary]:\n", + " \"\"\"Optimizer that decomposes iSWAPs into iSWAP ** 0.5 operations.\"\"\"\n", + "\n", + " def optimization_at(\n", + " self, circuit: cirq.Circuit, index: int, op: cirq.Operation\n", + " ) -> Optional[cirq.PointOptimizationSummary]:\n", " if op.gate == cirq.ISWAP:\n", " # If this operation is an iSWAP, transform\n", - " new_ops = [cirq.ISWAP(*op.qubits) ** 0.5,\n", - " cirq.ISWAP(*op.qubits) ** 0.5]\n", - " \n", + " new_ops = [\n", + " cirq.ISWAP(*op.qubits) ** 0.5,\n", + " cirq.ISWAP(*op.qubits) ** 0.5,\n", + " ]\n", + "\n", " # Clear_span = 1 signifies that only this op should be replaced.\n", " # clear_qubits replaces only operations with these qubits.\n", - " # new_operations \n", - " return cirq.PointOptimizationSummary(clear_span=1,\n", - " clear_qubits=op.qubits,\n", - " new_operations=new_ops)\n", + " # new_operations\n", + " return cirq.PointOptimizationSummary(\n", + " clear_span=1, clear_qubits=op.qubits, new_operations=new_ops\n", + " )\n", " # Exercise to the reader:\n", " # Can you add an additional condition to this function to replace\n", + "\n", + "\n", " # controlled-iSWAP operations with the decomposition we found above?\n", "\n", "exclusion_with_sqrt_iswaps = after_exclusion_without_measurement.copy()\n", @@ -1807,16 +1844,16 @@ ], "source": [ "qubit_translation = {\n", - " cirq.NamedQubit('a3') : cirq.GridQubit(6, 5),\n", - " cirq.NamedQubit('b2') : cirq.GridQubit(5, 5),\n", - " cirq.NamedQubit('a1') : cirq.GridQubit(4, 5),\n", - " cirq.NamedQubit('b1') : cirq.GridQubit(3, 5),\n", - " cirq.NamedQubit('c2') : cirq.GridQubit(2, 5),\n", - " cirq.NamedQubit('c3') : cirq.GridQubit(1, 5),\n", - " cirq.NamedQubit('c1') : cirq.GridQubit(3, 6),\n", + " cirq.NamedQubit(\"a3\"): cirq.GridQubit(6, 5),\n", + " cirq.NamedQubit(\"b2\"): cirq.GridQubit(5, 5),\n", + " cirq.NamedQubit(\"a1\"): cirq.GridQubit(4, 5),\n", + " cirq.NamedQubit(\"b1\"): cirq.GridQubit(3, 5),\n", + " cirq.NamedQubit(\"c2\"): cirq.GridQubit(2, 5),\n", + " cirq.NamedQubit(\"c3\"): cirq.GridQubit(1, 5),\n", + " cirq.NamedQubit(\"c1\"): cirq.GridQubit(3, 6),\n", " # Not used except for measurement\n", - " cirq.NamedQubit('a2') : cirq.GridQubit(2, 4),\n", - " cirq.NamedQubit('b3') : cirq.GridQubit(3, 4),\n", + " cirq.NamedQubit(\"a2\"): cirq.GridQubit(2, 4),\n", + " cirq.NamedQubit(\"b3\"): cirq.GridQubit(3, 4),\n", "}\n", "\n", "\n", @@ -1827,8 +1864,8 @@ "\n", "# First, modify the circuit so that ISWAP's become two ISWAP ** 0.5\n", "exclusion_move_sycamore = exclusion_with_sqrt_iswaps.with_device(\n", - " new_device=cirq.google.Sycamore, \n", - " qubit_mapping=qubit_transformer)\n", + " new_device=cirq.google.Sycamore, qubit_mapping=qubit_transformer\n", + ")\n", "print(exclusion_move_sycamore)" ] }, @@ -1895,17 +1932,19 @@ } ], "source": [ - "def map_helper(cur_node: cirq.Qid,\n", - " mapping: Dict[cirq.Qid, cirq.GridQubit],\n", - " available_qubits: Set[cirq.GridQubit],\n", - " graph: Dict[cirq.Qid, Iterable[cirq.Qid]]) -> bool:\n", + "def map_helper(\n", + " cur_node: cirq.Qid,\n", + " mapping: Dict[cirq.Qid, cirq.GridQubit],\n", + " available_qubits: Set[cirq.GridQubit],\n", + " graph: Dict[cirq.Qid, Iterable[cirq.Qid]],\n", + ") -> bool:\n", " \"\"\"Helper function to construct mapping.\n", " Traverses a graph and performs recursive depth-first\n", " search to construct a mapping one node at a time.\n", " On failure, raises an error and back-tracks until a\n", " suitable mapping can be found. Assumes all qubits in\n", " the graph are connected.\n", - " \n", + "\n", " Args:\n", " cur_node: node to examine.\n", " mapping: current mapping of named qubits to `GridQubits`\n", @@ -1965,7 +2004,7 @@ " del mapping[node_to_map]\n", " available_qubits.add(node_to_try)\n", " continue\n", - " \n", + "\n", " if not map_helper(cur_node, mapping, available_qubits, graph):\n", " del mapping[node_to_map]\n", " available_qubits.add(node_to_try)\n", @@ -1976,58 +2015,63 @@ " # Fail upwards and back-track if possible.\n", " return False\n", "\n", - "def qubit_mapping(circuit: cirq.Circuit,\n", - " device: cirq.Device,\n", - " start_qubit: cirq.Qid,\n", - " mapped_qubit: cirq.Qid) -> Dict[cirq.Qid, cirq.GridQubit]:\n", - " \"\"\"Create a mapping from NamedQubits to Grid Qubits\n", - " This function analyzes the circuit to determine which\n", - " qubits need to be adjacent, then maps to the grid of the device\n", - " based on the generated mapping.\n", - " \"\"\"\n", - " # Build up an adjacency graph based on the circuits.\n", - " # Two qubit gates will turn into edges in the graph\n", - " g = {}\n", - " for m in circuit:\n", - " for op in m:\n", - " if len(op.qubits) == 2:\n", - " q1, q2 = op.qubits\n", - " if q1 not in g:\n", - " g[q1] = []\n", - " if q2 not in g:\n", - " g[q2] = []\n", - " if q2 not in g[q1]:\n", - " g[q1].append(q2)\n", - " if q1 not in g[q2]:\n", - " g[q2].append(q1)\n", - " for q in g:\n", - " if len(g[q]) > 4:\n", - " raise ValueError(\n", - " f'Qubit {q} needs more than 4 adjacent qubits!')\n", - "\n", - " # Initialize mappings and available qubits\n", - " start_list = set(device.qubits)\n", - " start_list.remove(mapped_qubit)\n", - "\n", - " mapping = {}\n", - " mapping[start_qubit] = mapped_qubit\n", - "\n", - " map_helper(start_qubit, mapping, start_list, g)\n", - "\n", - " if len(mapping) != len(g):\n", - " print('Warning: could not map all qubits!')\n", - "\n", - " return mapping\n", - "\n", - "dynamic_mapping = qubit_mapping(exclusion_with_sqrt_iswaps,\n", - " cirq.google.Sycamore,\n", - " cirq.NamedQubit('b1'),\n", - " cirq.GridQubit(3, 5))\n", + "\n", + "def qubit_mapping(\n", + " circuit: cirq.Circuit,\n", + " device: cirq.Device,\n", + " start_qubit: cirq.Qid,\n", + " mapped_qubit: cirq.Qid,\n", + ") -> Dict[cirq.Qid, cirq.GridQubit]:\n", + " \"\"\"Create a mapping from NamedQubits to Grid Qubits\n", + " This function analyzes the circuit to determine which\n", + " qubits need to be adjacent, then maps to the grid of the device\n", + " based on the generated mapping.\n", + " \"\"\"\n", + " # Build up an adjacency graph based on the circuits.\n", + " # Two qubit gates will turn into edges in the graph\n", + " g = {}\n", + " for m in circuit:\n", + " for op in m:\n", + " if len(op.qubits) == 2:\n", + " q1, q2 = op.qubits\n", + " if q1 not in g:\n", + " g[q1] = []\n", + " if q2 not in g:\n", + " g[q2] = []\n", + " if q2 not in g[q1]:\n", + " g[q1].append(q2)\n", + " if q1 not in g[q2]:\n", + " g[q2].append(q1)\n", + " for q in g:\n", + " if len(g[q]) > 4:\n", + " raise ValueError(f\"Qubit {q} needs more than 4 adjacent qubits!\")\n", + "\n", + " # Initialize mappings and available qubits\n", + " start_list = set(device.qubits)\n", + " start_list.remove(mapped_qubit)\n", + "\n", + " mapping = {}\n", + " mapping[start_qubit] = mapped_qubit\n", + "\n", + " map_helper(start_qubit, mapping, start_list, g)\n", + "\n", + " if len(mapping) != len(g):\n", + " print(\"Warning: could not map all qubits!\")\n", + "\n", + " return mapping\n", + "\n", + "\n", + "dynamic_mapping = qubit_mapping(\n", + " exclusion_with_sqrt_iswaps,\n", + " cirq.google.Sycamore,\n", + " cirq.NamedQubit(\"b1\"),\n", + " cirq.GridQubit(3, 5),\n", + ")\n", "for q in dynamic_mapping:\n", - " print(f'Qubit {q} maps to {dynamic_mapping[q]}')\n", + " print(f\"Qubit {q} maps to {dynamic_mapping[q]}\")\n", "dynamically_mapped_circuit = exclusion_with_sqrt_iswaps.with_device(\n", - " new_device=cirq.google.Sycamore, \n", - " qubit_mapping=lambda q: dynamic_mapping[q])\n", + " new_device=cirq.google.Sycamore, qubit_mapping=lambda q: dynamic_mapping[q]\n", + ")\n", "print(dynamically_mapped_circuit)" ] }, diff --git a/docs/quantum_chess/quantum_chess_client.ipynb b/docs/quantum_chess/quantum_chess_client.ipynb index e70dc650..237d43bb 100644 --- a/docs/quantum_chess/quantum_chess_client.ipynb +++ b/docs/quantum_chess/quantum_chess_client.ipynb @@ -88,8 +88,15 @@ }, "outputs": [], "source": [ - "!pip install git+https://github.com/quantumlib/ReCirq/ -q\n", - "!pip install requests -q" + "try:\n", + " import recirq\n", + "except ImportError:\n", + " !pip install git+https://github.com/quantumlib/ReCirq -q\n", + "\n", + "try:\n", + " import requests\n", + "except ImportError:\n", + " !pip install requests -q" ] }, { @@ -109,7 +116,7 @@ }, "outputs": [], "source": [ - "url = 'http://bd626d83c9ec.ngrok.io/' #@param {type:\"string\"}\n", + "url = \"http://bd626d83c9ec.ngrok.io/\" # @param {type:\"string\"}\n", "!curl -s $url" ] }, @@ -150,8 +157,8 @@ "source": [ "import requests\n", "\n", - "init_board_json = { 'init_basis_state' : 0xFFFF00000000FFFF }\n", - "response = requests.post(url + '/quantumboard/init', json=init_board_json)\n", + "init_board_json = {\"init_basis_state\": 0xFFFF00000000FFFF}\n", + "response = requests.post(url + \"/quantumboard/init\", json=init_board_json)\n", "\n", "print(response.content)" ] @@ -185,10 +192,15 @@ "from recirq.quantum_chess.enums import MoveType, MoveVariant\n", "from recirq.quantum_chess.bit_utils import square_to_bit\n", "\n", - "split_b1_a3_c3 = {'square1' : square_to_bit('b1'), 'square2' : square_to_bit('a3'), 'square3' : square_to_bit('c3'), \n", - " 'type' : int(MoveType.SPLIT_JUMP.value), 'variant': int(MoveVariant.BASIC.value)}\n", - "response = requests.post(url + '/quantumboard/do_move', json=split_b1_a3_c3)\n", - "print(response.content)\n" + "split_b1_a3_c3 = {\n", + " \"square1\": square_to_bit(\"b1\"),\n", + " \"square2\": square_to_bit(\"a3\"),\n", + " \"square3\": square_to_bit(\"c3\"),\n", + " \"type\": int(MoveType.SPLIT_JUMP.value),\n", + " \"variant\": int(MoveVariant.BASIC.value),\n", + "}\n", + "response = requests.post(url + \"/quantumboard/do_move\", json=split_b1_a3_c3)\n", + "print(response.content)" ] }, { @@ -217,8 +229,14 @@ }, "outputs": [], "source": [ - "move_c2_c4 = {'square1' : square_to_bit('c2'), 'square2' : square_to_bit('c4'), 'square3' : 0,'type' : int(MoveType.PAWN_TWO_STEP.value), 'variant': int(MoveVariant.BASIC.value)}\n", - "response = requests.post(url + '/quantumboard/do_move', json=move_c2_c4)\n", + "move_c2_c4 = {\n", + " \"square1\": square_to_bit(\"c2\"),\n", + " \"square2\": square_to_bit(\"c4\"),\n", + " \"square3\": 0,\n", + " \"type\": int(MoveType.PAWN_TWO_STEP.value),\n", + " \"variant\": int(MoveVariant.BASIC.value),\n", + "}\n", + "response = requests.post(url + \"/quantumboard/do_move\", json=move_c2_c4)\n", "print(response.content)" ] }, @@ -248,8 +266,14 @@ }, "outputs": [], "source": [ - "move_d1_c2 = {'square1' : square_to_bit('d1'), 'square2' : square_to_bit('c2'), 'square3' : 0, 'type' : int(MoveType.JUMP.value), 'variant': int(MoveVariant.EXCLUDED.value)}\n", - "response = requests.post(url + '/quantumboard/do_move', json=move_d1_c2)\n", + "move_d1_c2 = {\n", + " \"square1\": square_to_bit(\"d1\"),\n", + " \"square2\": square_to_bit(\"c2\"),\n", + " \"square3\": 0,\n", + " \"type\": int(MoveType.JUMP.value),\n", + " \"variant\": int(MoveVariant.EXCLUDED.value),\n", + "}\n", + "response = requests.post(url + \"/quantumboard/do_move\", json=move_d1_c2)\n", "print(response.content)" ] }, @@ -270,9 +294,9 @@ }, "outputs": [], "source": [ - "response = requests.post(url + '/quantumboard/undo_last_move')\n", + "response = requests.post(url + \"/quantumboard/undo_last_move\")\n", "print(response.content)\n", - "response = requests.post(url + '/quantumboard/do_move', json=move_d1_c2)\n", + "response = requests.post(url + \"/quantumboard/do_move\", json=move_d1_c2)\n", "print(response.content)" ] } diff --git a/docs/quantum_chess/quantum_chess_rest_api.ipynb b/docs/quantum_chess/quantum_chess_rest_api.ipynb index 4c5a3d9a..6578dd23 100644 --- a/docs/quantum_chess/quantum_chess_rest_api.ipynb +++ b/docs/quantum_chess/quantum_chess_rest_api.ipynb @@ -126,7 +126,13 @@ "from recirq.quantum_chess.move import Move\n", "from recirq.quantum_chess.enums import MoveType, MoveVariant\n", "\n", - "m = Move(source='b1', target='a3', target2='c3', move_type=MoveType.SPLIT_JUMP, move_variant=MoveVariant.BASIC)\n", + "m = Move(\n", + " source=\"b1\",\n", + " target=\"a3\",\n", + " target2=\"c3\",\n", + " move_type=MoveType.SPLIT_JUMP,\n", + " move_variant=MoveVariant.BASIC,\n", + ")\n", "b.reset()\n", "r = b.apply(m)\n", "print(b)" @@ -171,17 +177,19 @@ "outputs": [], "source": [ "from recirq.quantum_chess.quantum_board import CirqBoard\n", - "from recirq.quantum_chess.bit_utils import ( bit_to_square, xy_to_bit )\n", + "from recirq.quantum_chess.bit_utils import bit_to_square, xy_to_bit\n", "from recirq.quantum_chess.move import to_rank\n", "\n", "global_board = CirqBoard(1)\n", "\n", + "\n", "def print_game(board):\n", " board.print_debug_log()\n", - " print('\\n')\n", + " print(\"\\n\")\n", " print(board)\n", " print(\"\\n\\n\")\n", "\n", + "\n", "probs = global_board.get_probability_distribution()\n", "\n", "print_game(global_board)" @@ -242,15 +250,16 @@ "outputs": [], "source": [ "def init(board, init_basis_state):\n", - " board.with_state(init_basis_state)\n", - " probs = board.get_probability_distribution()\n", - " print_game(board)\n", + " board.with_state(init_basis_state)\n", + " probs = board.get_probability_distribution()\n", + " print_game(board)\n", + "\n", + " return {\n", + " \"probabilities\": probs,\n", + " \"empty\": board.get_empty_squares_bitboard(),\n", + " \"full\": board.get_full_squares_bitboard(),\n", + " }\n", "\n", - " return {\n", - " 'probabilities' : probs,\n", - " 'empty' : board.get_empty_squares_bitboard(),\n", - " 'full' : board.get_full_squares_bitboard()\n", - " }\n", "\n", "r = init(global_board, 0xFFFF00000000FFFF)" ] @@ -300,53 +309,61 @@ "\n", "# Helper function for creating a split move from json values\n", "def get_split_move(move_json):\n", - " return Move(\n", - " move_json['square1'],\n", - " move_json['square2'],\n", - " target2 = move_json['square3'],\n", - " move_type = MoveType(move_json['type']),\n", - " move_variant = MoveVariant(move_json['variant'])\n", + " return Move(\n", + " move_json[\"square1\"],\n", + " move_json[\"square2\"],\n", + " target2=move_json[\"square3\"],\n", + " move_type=MoveType(move_json[\"type\"]),\n", + " move_variant=MoveVariant(move_json[\"variant\"]),\n", " )\n", "\n", + "\n", "# Helper function for creating a merge move from json values\n", "def get_merge_move(move_json):\n", - " return Move(\n", - " move_json['square1'],\n", - " move_json['square3'],\n", - " source2 = move_json['square2'],\n", - " move_type = MoveType(move_json['type']),\n", - " move_variant = MoveVariant(move_json['variant'])\n", + " return Move(\n", + " move_json[\"square1\"],\n", + " move_json[\"square3\"],\n", + " source2=move_json[\"square2\"],\n", + " move_type=MoveType(move_json[\"type\"]),\n", + " move_variant=MoveVariant(move_json[\"variant\"]),\n", " )\n", "\n", + "\n", "# Helper function for creating a standard move from json values\n", "def get_standard_move(move_json):\n", - " return Move(\n", - " move_json['square1'],\n", - " move_json['square2'],\n", - " move_type = MoveType(move_json['type']),\n", - " move_variant = MoveVariant(move_json['variant'])\n", + " return Move(\n", + " move_json[\"square1\"],\n", + " move_json[\"square2\"],\n", + " move_type=MoveType(move_json[\"type\"]),\n", + " move_variant=MoveVariant(move_json[\"variant\"]),\n", " )\n", - " \n", + "\n", + "\n", "def do_move(board, move):\n", - " board.clear_debug_log()\n", - " r = board.do_move(move)\n", - " probs = board.get_probability_distribution()\n", - " print_game(board)\n", - "\n", - " return {\n", - " 'result' : r,\n", - " 'probabilities' : probs,\n", - " 'empty' : board.get_empty_squares_bitboard(),\n", - " 'full' : board.get_full_squares_bitboard()\n", - " }\n", - "\n", - "move_json = {'square1' : 'b1', 'square2' : 'a3', 'square3' : 'c3', 'type' : MoveType.SPLIT_JUMP, 'variant': MoveVariant.BASIC}\n", + " board.clear_debug_log()\n", + " r = board.do_move(move)\n", + " probs = board.get_probability_distribution()\n", + " print_game(board)\n", + "\n", + " return {\n", + " \"result\": r,\n", + " \"probabilities\": probs,\n", + " \"empty\": board.get_empty_squares_bitboard(),\n", + " \"full\": board.get_full_squares_bitboard(),\n", + " }\n", + "\n", + "\n", + "move_json = {\n", + " \"square1\": \"b1\",\n", + " \"square2\": \"a3\",\n", + " \"square3\": \"c3\",\n", + " \"type\": MoveType.SPLIT_JUMP,\n", + " \"variant\": MoveVariant.BASIC,\n", + "}\n", "split_b1_a3_c3 = get_split_move(move_json)\n", "\n", "r = init(global_board, 0xFFFF00000000FFFF)\n", - "r = do_move(global_board, split_b1_a3_c3)\n", - " \n", - " " + "r = do_move(global_board, split_b1_a3_c3)" ] }, { @@ -370,14 +387,17 @@ "from cirq import DensityMatrixSimulator, google\n", "from cirq.contrib.noise_models import DepolarizingNoiseModel\n", "\n", - "NOISY_SAMPLER = DensityMatrixSimulator(noise= DepolarizingNoiseModel(\n", - " depol_prob=0.004))\n", + "NOISY_SAMPLER = DensityMatrixSimulator(\n", + " noise=DepolarizingNoiseModel(depol_prob=0.004)\n", + ")\n", "\n", - "noisy_board = CirqBoard(0,\n", - " sampler=NOISY_SAMPLER,\n", - " device=google.Sycamore,\n", - " error_mitigation= ErrorMitigation.Correct,\n", - " noise_mitigation=0.05)\n", + "noisy_board = CirqBoard(\n", + " 0,\n", + " sampler=NOISY_SAMPLER,\n", + " device=google.Sycamore,\n", + " error_mitigation=ErrorMitigation.Correct,\n", + " noise_mitigation=0.05,\n", + ")\n", "\n", "r = init(noisy_board, 0xFFFF00000000FFFF)\n", "r = do_move(noisy_board, split_b1_a3_c3)" @@ -416,18 +436,19 @@ "outputs": [], "source": [ "def undo_last_move(board):\n", - " board.clear_debug_log()\n", + " board.clear_debug_log()\n", + "\n", + " r = board.undo_last_move()\n", + " probs = board.get_probability_distribution()\n", + " print_game(board)\n", "\n", - " r = board.undo_last_move()\n", - " probs = board.get_probability_distribution()\n", - " print_game(board)\n", + " return {\n", + " \"result\": r,\n", + " \"probabilities\": probs,\n", + " \"empty\": board.get_empty_squares_bitboard(),\n", + " \"full\": board.get_full_squares_bitboard(),\n", + " }\n", "\n", - " return {\n", - " 'result' : r,\n", - " 'probabilities' : probs,\n", - " 'empty' : board.get_empty_squares_bitboard(),\n", - " 'full' : board.get_full_squares_bitboard()\n", - " }\n", "\n", "r = init(global_board, 0xFFFF00000000FFFF)\n", "r = do_move(global_board, split_b1_a3_c3)\n", @@ -477,45 +498,49 @@ "from flask_restful import Resource, Api\n", "from flask_ngrok import run_with_ngrok\n", "\n", + "\n", "class Init(Resource):\n", - " def get(self):\n", - " return {'about': 'Init'}\n", + " def get(self):\n", + " return {\"about\": \"Init\"}\n", + "\n", + " def post(self):\n", + " print(request.get_json())\n", + " n = request.get_json()[\"init_basis_state\"]\n", + " global_board.clear_debug_log()\n", + " return init(global_board, int(n))\n", "\n", - " def post(self):\n", - " print(request.get_json())\n", - " n = request.get_json()['init_basis_state']\n", - " global_board.clear_debug_log()\n", - " return init(global_board,int(n))\n", "\n", - " \n", "class DoMove(Resource):\n", - " def post(self):\n", - " move_json = request.get_json()\n", - " t = MoveType(move_json['type'])\n", - " # We need to convert square indices to square names.\n", - " move_json['square1'] = bit_to_square(move_json['square1'])\n", - " move_json['square2'] = bit_to_square(move_json['square2'])\n", - " move_json['square3'] = bit_to_square(move_json['square3'])\n", - "\n", - " if t == MoveType.SPLIT_SLIDE or t == MoveType.SPLIT_JUMP:\n", - " return do_move(global_board, get_split_move(move_json))\n", - " elif t == MoveType.MERGE_JUMP or t == MoveType.MERGE_SLIDE:\n", - " return do_move(global_board, get_merge_move(move_json))\n", - " else:\n", - " return do_move(global_board, get_standard_move(move_json))\n", + " def post(self):\n", + " move_json = request.get_json()\n", + " t = MoveType(move_json[\"type\"])\n", + " # We need to convert square indices to square names.\n", + " move_json[\"square1\"] = bit_to_square(move_json[\"square1\"])\n", + " move_json[\"square2\"] = bit_to_square(move_json[\"square2\"])\n", + " move_json[\"square3\"] = bit_to_square(move_json[\"square3\"])\n", + "\n", + " if t == MoveType.SPLIT_SLIDE or t == MoveType.SPLIT_JUMP:\n", + " return do_move(global_board, get_split_move(move_json))\n", + " elif t == MoveType.MERGE_JUMP or t == MoveType.MERGE_SLIDE:\n", + " return do_move(global_board, get_merge_move(move_json))\n", + " else:\n", + " return do_move(global_board, get_standard_move(move_json))\n", + "\n", "\n", "class UndoLastMove(Resource):\n", " def post(self):\n", " return undo_last_move(global_board)\n", "\n", + "\n", "app = Flask(__name__)\n", "run_with_ngrok(app)\n", "\n", "api = Api(app)\n", "\n", - "api.add_resource(Init, '/quantumboard/init')\n", - "api.add_resource(DoMove, '/quantumboard/do_move')\n", - "api.add_resource(UndoLastMove, '/quantumboard/undo_last_move')\n", + "api.add_resource(Init, \"/quantumboard/init\")\n", + "api.add_resource(DoMove, \"/quantumboard/do_move\")\n", + "api.add_resource(UndoLastMove, \"/quantumboard/undo_last_move\")\n", + "\n", "\n", "@app.route(\"/\")\n", "def home():\n",