diff --git a/docs/params.ipynb b/docs/params.ipynb index 89b735fb883b..cb4c44732bc6 100644 --- a/docs/params.ipynb +++ b/docs/params.ipynb @@ -18,7 +18,7 @@ }, "outputs": [], "source": [ - "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# @title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", "# You may obtain a copy of the License at\n", "#\n", @@ -87,9 +87,9 @@ "source": [ "## Concept of Circuit Parameterization and Sweeps\n", "\n", - "Suppose one has a quantum circuit and in this circuit there is a gate with some parameter. One might wish to run this circuit for different values of this parameter. An example of this type of setup is a Rabi flop experiment. In this experiment, one runs a set of quantum computations where one 1) starts in $|0\\rangle$ state, 2) rotates the state by $\\theta$ about the $x$ axis, i.e. applies the gate $\\exp(i \\theta X)$, and 3) measures the state in the computational basis. Running this experiment for multiple values of $\\theta$, and plotting the probability of observing a $|1\\rangle$ outcome yields the quintessential $\\cos^2$ probability distribution as a function of the different parameters $\\theta$. To support this type of experiment, Cirq provides the concept of parameterized circuits and parameter sweeps. \n", + "Suppose you have a quantum circuit and in this circuit there is a gate with some parameter. You might wish to run this circuit for different values of this parameter. An example of this type of circuit is a Rabi flop experiment. This experiment runs a set of quantum computations which 1) starts in $|0\\rangle$ state, 2) rotates the state by $\\theta$ about the $x$ axis, i.e. applies the gate $\\exp(i \\theta X)$, and 3) measures the state in the computational basis. Running this experiment for multiple values of $\\theta$, and plotting the probability of observing a $|1\\rangle$ outcome yields the quintessential $\\cos^2$ probability distribution as a function of the parameter $\\theta$. To support this type of experiment, Cirq provides the concept of parameterized circuits and parameter sweeps. \n", "\n", - "Let's illustrate parameter sweeps by a simple example. Suppose that we want to compare two quantum circuits that are very similar except for a single gate." + "The next cell illustrates parameter sweeps with a simple example. Suppose you want to compare two quantum circuits that are identical except for a single exponentiated `cirq.Z` gate." ] }, { @@ -115,9 +115,9 @@ "id": "0bbbafcbd46b" }, "source": [ - "One could run (either on hardware or in simulation) these circuits separately, for example, and collect statistics on the results of these circuits. However we can use parameter sweeps to do this in a cleaner and more perfomant manner. \n", + "You could run these circuits separately (either on hardware or in simulation), and collect statistics on the results of these circuits. However parameter sweeps can do this in a cleaner and more perfomant manner. \n", "\n", - "First one defines a parameter, and constructs a circuit that depends on this parameter. We use [SymPy](https://www.sympy.org/en/index.html){:external}, a symbolic mathematics package, to define our parameters. For example, here we define a symbol, theta, and use it to construct a paremeterized circuit." + "First define a parameter, and construct a circuit that depends on this parameter. Cirq uses [SymPy](https://www.sympy.org/en/index.html){:external}, a symbolic mathematics package, to define parameters. In this example the Sympy parameter is `theta`, which is used to construct a parameterized circuit." ] }, { @@ -142,7 +142,7 @@ "id": "39411f440f90" }, "source": [ - "Notice now that our circuit contains a `cirq.Z` gate that is raised to a power, but this power is our parameter `theta`. This is a \"parameterized circuit\". An alternative way to construct this, where we see that the parameter is actually a parameter on the gate's constructor arguments, is" + "Notice now that the circuit contains a `cirq.Z` gate that is raised to a power, but this power is the parameter `theta`. This is a \"parameterized circuit\". An equivalent way to construct this circuit, where the parameter is actually a parameter in the gate constructor's arguments, is:" ] }, { @@ -153,7 +153,9 @@ }, "outputs": [], "source": [ - "circuit = cirq.Circuit([cirq.H(q0), cirq.ZPowGate(exponent=theta)(q0), cirq.H(q0), cirq.measure(q0)])\n", + "circuit = cirq.Circuit(\n", + " cirq.H(q0), cirq.ZPowGate(exponent=theta)(q0), cirq.H(q0), cirq.measure(q0)\n", + ")\n", "print(f\"circuit:\\n{circuit}\")" ] }, @@ -163,7 +165,7 @@ "id": "5ee7e4d0795f" }, "source": [ - "We can check whether an object in Cirq is parameterized using `cirq.is_parameterized`:" + "Note: You can check whether an object in Cirq is parameterized using `cirq.is_parameterized`:" ] }, { @@ -183,7 +185,7 @@ "id": "83d26b614ffe" }, "source": [ - "Parameterized circuits are just like normal circuits, they just aren't defined in terms of actually gates you can run on a quantum computer without the additional information about the values of the parameters. Following along with our example above, we can generate the two circuits (`circuit1` and `circuit2`) by using `cirq.resolve_parameter` and supplying the parameters:" + "Parameterized circuits are just like normal circuits; they just aren't defined in terms of gates that you can actually run on a quantum computer without the additional information about the values of the parameters. Following the example above, you can generate the two circuits (`circuit1` and `circuit2`) by using `cirq.resolve_parameter` and supplying the values that you want the parameter(s) to take:" ] }, { @@ -195,7 +197,9 @@ "outputs": [], "source": [ "# circuit1 has theta = 0.5\n", - "cirq.resolve_parameters(circuit, {\"theta\": 0.5})" + "cirq.resolve_parameters(circuit, {\"theta\": 0.5})\n", + "# circuit2 has theta = 0.25\n", + "cirq.resolve_parameters(circuit, {\"theta\": 0.25})" ] }, { @@ -204,7 +208,7 @@ "id": "6463c8d810fa" }, "source": [ - "More interestingly, can combine parameterized circuits with a list of parameter assignments when doing things like running circuits or simulating them. These lists of parameter assignements are called \"sweeps\". For example we can use a simulators `run_sweep` method to run simulations for the parameters corresonding to the two circuits defined above." + "More interestingly, you can combine parameterized circuits with a list of parameter assignments when doing things like running circuits or simulating them. These lists of parameter assignements are called \"sweeps\". For example you can use a simulator's `run_sweep` method to run simulations for the parameters corresponding to the two circuits defined above. " ] }, { @@ -227,7 +231,7 @@ "id": "75e583a33046" }, "source": [ - "To recap, we can construct parameterized circuits which depend on parameters that have not yet been assigned a value. These parameterized circuits can then be resolved to circuits with actual values via a dictionary that maps the parameter name to the value. We can also construct lists of dictionaries of parameter assignments, called sweeps, and pass this to many objects in Cirq that use circuits to do an action (such as simulate or run on hardware). For each of the elements in the sweep, the object will do the action using the parameters as described by the element." + "To recap, you can construct parameterized circuits that depend on parameters that have not yet been assigned a value. These parameterized circuits can then be resolved to circuits with actual values via a dictionary that maps the sympy variable name to the value that parameter should take. You can also construct lists of dictionaries of parameter assignments, called sweeps, and pass this to many functions in Cirq that use circuits to do an action (such as `simulate` or `run`). For each of the elements in the sweep, the function will execute using the parameters as described by the element." ] }, { @@ -238,7 +242,7 @@ "source": [ "## Constructing Sweeps\n", "\n", - "Above we constructed a sweep by simply constructing a list of parameter assignments, `[{\"theta\": 0.5}, {\"theta\": 0.25}]`. Cirq also provides other ways to construct sweeps. \n", + "The previous example constructed a sweep by simply constructing a list of parameter assignments, `[{\"theta\": 0.5}, {\"theta\": 0.25}]`. Cirq also provides other ways to construct sweeps. \n", "\n", "One useful method for constructing parameter sweeps is `cirq.Linspace` which creates a sweep over a list of equally spaced elements. " ] @@ -263,7 +267,9 @@ "id": "e0d86edee975" }, "source": [ - "Many methods that take a sweepable will take a list, but if one want to construct an explicit sweepable from a list, `cirq.Points` does this." + "Note: The `Linspace` sweep is composed of `cirq.ParamResolver` instances instead of simple dictionaries. However, you can think of them as effectively the same for most use cases. \n", + "\n", + "If you need to explicitly and individually specify each parameter resolution, you can do it by constructing a list of dictionaries as before. However, you can also use `cirq.Points` to do this more succinctly." ] }, { @@ -285,7 +291,11 @@ "id": "cd97c725e966" }, "source": [ - "Often one wants to sweep over multiple parameters. Two common cases are that one wants to combined two sweeps over parameters to take all combinations of these parameters (the cartesian product), or taking combinations that match up elementwise (zipping). Here are two examples that show how to do this" + "If you're working with parameterized circuits, it is very likely you'll need to keep track of multiple parameters. Two common use cases necessitate building a sweep from two constituent sweeps, where the new sweep includes: \n", + "- Every possible combination of the elements of each sweep: A cartesian product. \n", + "- A element-wise pairing of the two sweeps: A zip.\n", + "\n", + "The following are examples of using the `*` and `+` operators to combine sweeps by cartesian product and zipping, respectively. " ] }, { @@ -298,7 +308,7 @@ "source": [ "sweep1 = cirq.Linspace(\"theta\", 0, 1, 5)\n", "sweep2 = cirq.Points(\"gamma\", [0, 3])\n", - "# By taking the product of these two sweeps, we can sweep over all possible\n", + "# By taking the product of these two sweeps, you can sweep over all possible\n", "# combinations of the parameters.\n", "for param in sweep1 * sweep2:\n", " print(param)" @@ -314,7 +324,7 @@ "source": [ "sweep1 = cirq.Points(\"theta\", [1, 2, 3])\n", "sweep2 = cirq.Points(\"gamma\", [0, 3, 4])\n", - "# By taking the sum of these two sweeps, we can combine the sweeps\n", + "# By taking the sum of these two sweeps, you can combine the sweeps\n", "# elementwise (similar to python's zip function):\n", "for param in sweep1 + sweep2:\n", " print(param)" @@ -326,7 +336,7 @@ "id": "b9d5e67f80e5" }, "source": [ - "`cirq.Linspace` and `cirq.Points` are instances of the `cirq.Sweep` class, which explicitly supports cartesian product with the `*` operation, and zipping with the `+` operation. Other mathematical operations will not work in general *between sweeps*." + "`cirq.Linspace` and `cirq.Points` are instances of the `cirq.Sweep` class, which explicitly supports cartesian product with the `*` operation, and zipping with the `+` operation. The `*` operation produces a `cirq.Product` object, and `+` produces a `cirq.Zip` object, both of which are also `Sweep`s. Other mathematical operations will not work in general *between sweeps*." ] }, { @@ -344,7 +354,7 @@ "id": "802e8fabd18c" }, "source": [ - "Cirq uses Sympy to define its parameters. Sympy is a general symbolic mathematics toolset, and we can leverage this in Cirq. For example, in Sympy, we can define an expression and use it to construct circuits that depend on this expression:" + "[SymPy](https://www.sympy.org/en/index.html){:external} is a general symbolic mathematics toolset, and you can leverage this in Cirq to define more complex parameters than have been shown so far. For example, you can define an expression in Sympy and use it to construct circuits that depend on this expression:" ] }, { @@ -355,7 +365,7 @@ }, "outputs": [], "source": [ - "# We construct an expression for 0.5 * a + 0.25:\n", + "# Construct an expression for 0.5 * a + 0.25:\n", "expr = 0.5 * sympy.Symbol(\"a\") + 0.25\n", "print(expr)" ] @@ -368,7 +378,7 @@ }, "outputs": [], "source": [ - "# We can use this in the circuit:\n", + "# Use the expression in the circuit:\n", "circuit = cirq.Circuit(cirq.X(q0)**expr, cirq.measure(q0))\n", "print(f\"circuit:\\n{circuit}\")" ] @@ -379,7 +389,7 @@ "id": "d6501bf32491" }, "source": [ - "When we resolve parameters for this circuit, the expression will be evaluated" + "Both the exponents and parameter arguments of circuit operations can in fact be any general Sympy expression: The previous examples just used single-variable expressions. When you resolve parameters for this circuit, the expressions are evaluated under the given assignments to the variables in the expression. " ] }, { @@ -399,7 +409,7 @@ "id": "3853e96f6abd" }, "source": [ - "Similarly when we run a simulation, we can pass in a sweep, and Cirq will evaluate this expression for each of the possible values in the sweep:" + "Just as before, you can pass a sweep over variable values to `run` or `simulate`, and Cirq will evaluate the expression for each possible value. " ] }, { @@ -410,7 +420,10 @@ }, "outputs": [], "source": [ - "sim.run_sweep(circuit, repetitions=20, params=[{\"a\": 0}, {\"a\": 1}])" + "sim = cirq.Simulator()\n", + "results = sim.run_sweep(circuit, repetitions=25, params=cirq.Points('a', [0, 1]))\n", + "for result in results:\n", + " print(f\"param: {result.params}, result: {result}\")" ] }, { @@ -419,7 +432,7 @@ "id": "dae5c1c38113" }, "source": [ - "Sympy supports a large number of numeric functions and methods, and we can create fairly sophisticated expressions:" + "Sympy supports a large number of numeric functions and methods, which can be used to create fairly sophisticated expressions, like cosine, exponentiation, and more:" ] }, { @@ -439,7 +452,9 @@ "id": "93ddeb7cee7d" }, "source": [ - "Cirq can evaluate numerically all of the expressions Sympy can evalute. One should note however, that if one is running a parameterized circuit on a service (such as on a hardware backed quantum computing service) these services may not suport evaluating all expressions. See documentation for the particular service for details. However, as a general workaround, one can instead use Cirq's flattening ability to evaluate the parameters server side." + "Cirq can numerically evaluate all of the expressions Sympy can evalute. However, if you are running a parameterized circuit on a service (such as on a hardware backed quantum computing service) that service may not support evaluating all expressions. See documentation for the particular service you're using for details. \n", + "\n", + "As a general workaround, you can instead use Cirq's flattening ability to evaluate the parameters before sending them off to the service." ] }, { @@ -450,7 +465,7 @@ "source": [ "### Flattening Expressions\n", "\n", - "Suppose we build a circuit with multiple expressions in the circuit:" + "Suppose you build a circuit that includes multiple different expressions:" ] }, { @@ -462,11 +477,7 @@ "outputs": [], "source": [ "a = sympy.Symbol('a')\n", - "circuit = cirq.Circuit(\n", - " cirq.X(q0) ** (a/4),\n", - " cirq.Y(q0) ** (1-a/2),\n", - " cirq.measure(q0)\n", - ")\n", + "circuit = cirq.Circuit(cirq.X(q0)**(a / 4), cirq.Y(q0)**(1 - a / 2), cirq.measure(q0))\n", "print(circuit)" ] }, @@ -476,7 +487,7 @@ "id": "a7592df0d861" }, "source": [ - "The idea behind flattening is that for each of the expressions used in the circuit, we create a new symbol for this expression, and then construct and object, a `cirq.ExpressionMap`, that has knowledge about how to map from the bare symbols to the value of the expression. " + "Flattening replaces every expression in the circuit with a new symbol that is representative of the value of that expression. Additionally, it keeps track of the new symbols and provices a `cirq.ExpressionMap` object to map the old sympy expression objects to the new symbols that replaced them. " ] }, { @@ -499,7 +510,7 @@ "id": "756ad9a92137" }, "source": [ - "Notice that the new circuit has new symbols, `` and `<1-a/2`. These are not expressions. We can see this by looking at the value of the exponent in the first gate:" + "Notice that the new circuit has new symbols, `` and `<1-a/2>`, which are explicitly not expressions. You can see this by looking at the value of the exponent in the first gate:" ] }, { @@ -522,7 +533,7 @@ "id": "3b5a767a93bc" }, "source": [ - "The second object returned by `cirq.flatten` is an object that can map sweeps with particular values to the new symbols that corresond to the expressions, with the value being that of the evaluated expression." + "The second object returned by `cirq.flatten` is an object that can be used to map sweeps over the previous symbols to new sweeps over the new expression-symbols. The values assigned to the new expression symbols in the resulting sweep are the old expressions kept track of in the `ExpressionMap`, but resolved with the values provided by the original input sweep." ] }, { @@ -546,7 +557,9 @@ "id": "c560b632e84d" }, "source": [ - "One can then use these new sweep elements with the flattened circuit" + "To reinforce: The new sweep is over two new symbols, which each represent the values of the expressions in the original circuit. The values assigned to these new expression symbols is acquired by evaluating the expressions with `a` resolved to a value in `[0, 4]`, according to the old sweep. \n", + "\n", + "You can use these new sweep elements to resolve the parameters of the flattened circuit:" ] }, { @@ -568,7 +581,7 @@ "id": "beff46419af0" }, "source": [ - "Using `cirq.flatten` one can always take a paramterized circuit with complicated expressions plus a sweep, and produce an equivalent circuit with no expressions, only symbols, and a sweep for these symbols. Because this is a common flow, cirq provides `cirq.flatten_sweep` to do this in one step:" + "Using `cirq.flatten`, you can always take a parameterized circuit with any complicated expressions, plus a sweep, and produce an equivalent circuit with no expressions, only symbols, and a sweep for these new symbols. Because this is a common flow, Cirq provides `cirq.flatten_sweep` to do this in one step:" ] }, { @@ -590,7 +603,7 @@ "id": "9b3f42c586a4" }, "source": [ - "We can then directly use these objects to run the sweeps. For example, here we use them to perform a simulation:" + "You can then directly use these objects to run the sweeps. For example, you can use them to perform a simulation:" ] }, { @@ -613,7 +626,21 @@ "id": "de31ae91808b" }, "source": [ - "Where we see that the different flatten parameters have corresponding different results of the simulation." + "You can see that the different flattened parameters have corresponding different results for their simulation." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "48f8502171e3" + }, + "source": [ + "# Summary\n", + "\n", + "- Cirq circuits can handle arbitrary Sympy expressions in place of exponents and parameter arguments in operations.\n", + "- By providing one or a sequence of `ParamResolver`s or dictionaries that resolve the Sympy variables to values, `run`, `simulate`, and other functions can iterate efficiently over different parameter assignments for otherwise identical circuits. \n", + "- Sweeps can be created succinctly with `cirq.Points` and `cirq.Linspace`, and composed with each other with `*` and `+`, to create `cirq.Product` and `cirq.Zip` sweeps. \n", + "- When the service you're using does not support arbitrary expressions, you can flatten a circuit and sweep into a new circuit that doesn't have complex expressions, and a corresponding new sweep. " ] } ], diff --git a/docs/simulation.ipynb b/docs/simulation.ipynb index 843d8ee5fad3..da46576dd34d 100644 --- a/docs/simulation.ipynb +++ b/docs/simulation.ipynb @@ -11,14 +11,14 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": { "cellView": "form", "id": "z2RJVa8qgXou" }, "outputs": [], "source": [ - "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# @title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", "# You may obtain a copy of the License at\n", "#\n", @@ -64,7 +64,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": { "id": "bd9529db1c0b" }, @@ -119,25 +119,16 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": { "id": "f3c82c1c12a6" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(0, 0): ───X^0.5───@───X^0.5───M('q0')───\n", - " │\n", - "(1, 0): ───X^0.5───@───X^0.5───M('q1')───\n" - ] - } - ], + "outputs": [], "source": [ "q0 = cirq.GridQubit(0, 0)\n", "q1 = cirq.GridQubit(1, 0)\n", "\n", + "\n", "def basic_circuit(meas=True):\n", " sqrt_x = cirq.X**0.5\n", " yield sqrt_x(q0), sqrt_x(q1)\n", @@ -146,6 +137,7 @@ " if meas:\n", " yield cirq.measure(q0, key='q0'), cirq.measure(q1, key='q1')\n", "\n", + "\n", "circuit = cirq.Circuit()\n", "circuit.append(basic_circuit())\n", "\n", @@ -158,26 +150,17 @@ "id": "b4e74a859e3a" }, "source": [ - "We can simulate this by creating a ``cirq.Simulator`` and\n", + "You can simulate this by creating a ``cirq.Simulator`` and\n", "passing the circuit into its ``run`` method:" ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": { "id": "5422e0c06102" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "q0=0\n", - "q1=1\n" - ] - } - ], + "outputs": [], "source": [ "simulator = cirq.Simulator()\n", "result = simulator.run(circuit)\n", @@ -205,20 +188,11 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": { "id": "e83b165ebf06" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "q0=1\n", - "q1=0\n" - ] - } - ], + "outputs": [], "source": [ "result = simulator.run(circuit)\n", "\n", @@ -245,23 +219,16 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": { "id": "e085289e0002" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[0.5+0.j 0. +0.5j 0. +0.5j 0.5+0.j ]\n" - ] - } - ], + "outputs": [], "source": [ "import numpy as np\n", + "\n", "circuit = cirq.Circuit()\n", - "circuit.append(basic_circuit(False)) \n", + "circuit.append(basic_circuit(False))\n", "result = simulator.simulate(circuit, qubit_order=[q0, q1])\n", "\n", "print(np.around(result.final_state_vector, 3))" @@ -304,25 +271,16 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": { "id": "mjUGQ78IiQAG" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[(1+0j), 0j]\n" - ] - } - ], + "outputs": [], "source": [ "XX_obs = cirq.X(q0) * cirq.X(q1)\n", "ZZ_obs = cirq.Z(q0) * cirq.Z(q1)\n", "ev_list = simulator.simulate_expectation_values(\n", - " cirq.Circuit(basic_circuit(False)),\n", - " observables=[XX_obs, ZZ_obs],\n", + " cirq.Circuit(basic_circuit(False)), observables=[XX_obs, ZZ_obs]\n", ")\n", "print(ev_list)" ] @@ -364,19 +322,11 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": { "id": "982a827446d3" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[ 1 2 10 20]\n" - ] - } - ], + "outputs": [], "source": [ "outside = [1, 10]\n", "inside = [1, 2]\n", @@ -400,22 +350,11 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": { "id": "8141e8461313" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "amps[0] is for first=0, second=0\n", - "amps[1] is for first=0, second=1\n", - "amps[2] is for first=1, second=0\n", - "amps[3] is for first=1, second=1\n" - ] - } - ], + "outputs": [], "source": [ "i = 0\n", "for first in [0, 1]:\n", @@ -430,25 +369,17 @@ "id": "48c4d1acd296" }, "source": [ - "We can check that this is in fact the ordering with a\n", + "You can check that this is in fact the ordering with a\n", "circuit that flips one qubit out of two:" ] }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": { "id": "befc299bfd2a" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[0. 0. 1. 0.]\n" - ] - } - ], + "outputs": [], "source": [ "q_stay = cirq.NamedQubit('q_stay')\n", "q_flip = cirq.NamedQubit('q_flip')\n", @@ -461,19 +392,11 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": { "id": "ca70c50a782f" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[0. 1. 0. 0.]\n" - ] - } - ], + "outputs": [], "source": [ "# second qubit in order flipped\n", "result = simulator.simulate(c, qubit_order=[q_stay, q_flip])\n", @@ -498,25 +421,14 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "metadata": { "id": "68bc0a762450" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "state at step 0: [0. +0.5j 0.5+0.j 0.5+0.j 0. -0.5j]\n", - "state at step 1: [0. +0.5j 0.5+0.j 0.5+0.j 0. +0.5j]\n", - "state at step 2: [0.5+0.j 0. +0.5j 0. +0.5j 0.5+0.j ]\n", - "state at step 3: [1.+0.j 0.+0.j 0.+0.j 0.+0.j]\n" - ] - } - ], + "outputs": [], "source": [ "circuit = cirq.Circuit()\n", - "circuit.append(basic_circuit()) \n", + "circuit.append(basic_circuit())\n", "for i, step in enumerate(simulator.simulate_moment_steps(circuit)):\n", " print('state at step %d: %s' % (i, np.around(step.state_vector(copy=True), 3)))" ] @@ -548,22 +460,11 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "metadata": { "id": "8c8c037355eb" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "state at step 0: [0. +0.5j 0.5+0.j 0.5+0.j 0. -0.5j]\n", - "state at step 1: [0. +0.5j 0.5+0.j 0.5+0.j 0. +0.5j]\n", - "state at step 2: [0.5+0.j 0. +0.5j 0. +0.5j 0.5+0.j ]\n", - "state at step 3: [1.+0.j 0.+0.j 0.+0.j 0.+0.j]\n" - ] - } - ], + "outputs": [], "source": [ "chunks = [cirq.Circuit(moment) for moment in basic_circuit()]\n", "next_state = 0 # represents the all-zero state\n", @@ -594,7 +495,7 @@ "## Parameterized values and studies\n", "\n", "In addition to circuit gates with fixed values, Cirq also\n", - "supports gates which can have `Symbol` value (see\n", + "supports gates which can have `Symbol` values (see\n", "[Gates](gates.ipynb)). These are values that can be resolved\n", "at runtime. \n", "\n", @@ -605,32 +506,22 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "metadata": { "id": "1b5c6f4438ef" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[1.+0.j 0.+0.j 0.+0.j 0.+0.j]\n", - "[ 0.6 +0.6j 0.25-0.25j 0.25-0.25j -0.1 -0.1j ]\n", - "[0. +0.5j 0.5+0.j 0.5+0.j 0. -0.5j]\n", - "[-0.1 +0.1j 0.25+0.25j 0.25+0.25j 0.6 -0.6j ]\n", - "[0.+0.j 0.+0.j 0.+0.j 1.+0.j]\n" - ] - } - ], + "outputs": [], "source": [ "import sympy\n", + "\n", "rot_w_gate = cirq.X**sympy.Symbol('x')\n", "circuit = cirq.Circuit()\n", "circuit.append([rot_w_gate(q0), rot_w_gate(q1)])\n", + "print(circuit)\n", "for y in range(5):\n", " resolver = cirq.ParamResolver({'x': y / 4.0})\n", " result = simulator.simulate(circuit, resolver)\n", - " print(np.round(result.final_state_vector, 2))" + " print(f\"params:{result.params}, state vector:{np.round(result.final_state_vector, 2)}\")" ] }, { @@ -639,14 +530,14 @@ "id": "10617793bfd2" }, "source": [ - "Here we see that the `Symbol` is used in two gates, and then the resolver\n", + "In the previous example, the symbol `x` is used in two gates, and then the resolver\n", "provides this value at run time.\n", "\n", - "Parameterized values are most useful in defining what we call a\n", - "`sweep`. A `sweep` is a sequence of trials, where each\n", + "Parameterized values are most useful in defining what is called a\n", + "\"sweep\", which is a sequence of trials, where each\n", "trial is a run with a particular set of parameter values.\n", "\n", - "Running a `sweep` returns a `Result` for each set of fixed parameter\n", + "Running a sweep returns a `Result` for each set of fixed parameter\n", "values and repetitions. \n", "\n", "For instance:" @@ -654,33 +545,20 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "metadata": { "id": "ccc88952ba49" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "q0=00\n", - "q1=00\n", - "q0=10\n", - "q1=10\n", - "q0=11\n", - "q1=11\n" - ] - } - ], + "outputs": [], "source": [ "resolvers = [cirq.ParamResolver({'x': y / 2.0}) for y in range(3)]\n", "circuit = cirq.Circuit()\n", "circuit.append([rot_w_gate(q0), rot_w_gate(q1)])\n", "circuit.append([cirq.measure(q0, key='q0'), cirq.measure(q1, key='q1')])\n", - "results = simulator.run_sweep(program=circuit,\n", - " params=resolvers,\n", - " repetitions=2)\n", + "results = simulator.run_sweep(program=circuit, params=resolvers, repetitions=2)\n", "for result in results:\n", + " print(f\"params:{result.params}\")\n", + " print(f\"measurements:\")\n", " print(result)" ] }, @@ -690,7 +568,7 @@ "id": "5ca5f417ca71" }, "source": [ - "Above we see that assigning different values to gate parameters yields\n", + "The previous example demonstrates that assigning different values to gate parameters yields\n", "different results for each trial in the sweep, and that each trial is repeated\n", "`repetitions` times. See [Parameter Sweeps](params.ipynb) for more information on sweeping and parameters." ] @@ -722,19 +600,11 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "metadata": { "id": "9bc8775b8ef9" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Counter({0: 59, 1: 41})\n" - ] - } - ], + "outputs": [], "source": [ "q = cirq.NamedQubit('a')\n", "circuit = cirq.Circuit(cirq.H(q), cirq.amplitude_damp(0.2)(q), cirq.measure(q))\n", @@ -749,42 +619,22 @@ "id": "164ccf2b7d71" }, "source": [ - "We create a state in an equal superposition of 0 and 1,\n", - "then apply amplitude damping which takes 1 to 0 with\n", - "something like a probability of 0.2. \n", + "The previous example creates a state in an equal superposition of 0 and 1, then applies amplitude damping which takes 1 to 0 with something like a probability of 0.2. \n", "\n", - "We see that instead of about 50 percent of the timing being in 0, about 20 percent of the 1 has been converted into 0, so we end up with total\n", - "around 60 percent in the 0 state.\n", + "You can see that, instead of about 50 percent of the timing being in 0, about 20 percent of the 1 has been converted into 0, so you end up with total around 60 percent in the 0 state.\n", "\n", - "Like the pure state simulators, the mixed state simulator\n", - "supports `run()` and `run_sweeps()` methods. \n", + "Like the pure state simulators, the mixed state simulator supports `run()` and `run_sweeps()` methods. \n", "\n", - "The `cirq.DensityMatrixSimulator` also supports getting access\n", - "to the density matrix of the circuit at the end of simulating\n", - "the circuit, or when stepping through the circuit. These are\n", - "done by the `simulate()` and `simulate_sweep()` methods, or,\n", - "for stepping through the circuit, via the `simulate_moment_steps`\n", - "method. For example, we can simulate creating an equal\n", - "superposition followed by an amplitude damping channel with a\n", - "gamma of 0.2 by:" + "The `cirq.DensityMatrixSimulator` also supports getting access to the density matrix of the circuit at the end of simulating the circuit, or when stepping through the circuit. These are done by the `simulate()` and `simulate_sweep()` methods, or, for stepping through the circuit, via the `simulate_moment_steps` method. For example, you can simulate creating an equal superposition followed by an amplitude damping channel with a gamma of 0.2 by:" ] }, { "cell_type": "code", - "execution_count": 17, + "execution_count": null, "metadata": { "id": "c66bc5094882" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[[0.6 +0.j 0.447+0.j]\n", - " [0.447+0.j 0.4 +0.j]]\n" - ] - } - ], + "outputs": [], "source": [ "q = cirq.NamedQubit('a')\n", "circuit = cirq.Circuit(cirq.H(q), cirq.amplitude_damp(0.2)(q))\n", @@ -799,8 +649,7 @@ "id": "ce9b181d8c72" }, "source": [ - "We see that we have access to the density matrix at the\n", - "end of the simulation via `final_density_matrix`." + "Note: The density matrix at the end of the simulation is accessible via `final_density_matrix`." ] }, {