|
21 | 21 | construct, and simulate quantum circuits using a performant state-vector |
22 | 22 | simulator. |
23 | 23 |
|
24 | | -## Circuits and operations |
| 24 | +## Circuits and Operations |
25 | 25 | Begin with two necessary imports: The `Circuit` class, which will contain the |
26 | 26 | full quantum circuit with all the operations, measurements, qubits and bits, and |
27 | | -the operations module. The operations, or gates, contain information related to |
28 | | -a particular operation, including its matrix representation, potential |
29 | | -decompositions, and how to apply it to a circuit. |
| 27 | +the `operations` module. |
30 | 28 | """ |
31 | 29 |
|
32 | 30 | from dwave.gate.circuit import Circuit |
33 | 31 | import dwave.gate.operations as ops |
34 | 32 |
|
35 | 33 | ############################################################################### |
36 | | -# The `Circuit` keeps track of the operations and the logical flow of their |
37 | | -# excecutions. It also stores the qubits, bits and measurments. |
| 34 | +# The operations, or gates, contain information related to a particular operation, |
| 35 | +# including its matrix representation, potential decompositions, and how to apply |
| 36 | +# it to a circuit. |
| 37 | +# |
| 38 | +# The `Circuit` keeps track of the operations and the logical |
| 39 | +# flow of their executions. It also stores the qubits, bits and measurements. |
38 | 40 | # |
39 | | -# When initializing a circuit, the number of qubits and (optionally) the number of |
40 | | -# bits, i.e., classical measurement results containers, need to be declared. More |
41 | | -# qubits and bits can be added using the `Circuit.add_qubit` and `Circuit.add_bit` |
42 | | -# methods. |
| 41 | +# When initializing a circuit, you need to declare the number of qubits and, |
| 42 | +# optionally, the number of bits (i.e., classical measurement results containers). |
| 43 | +# You can add more qubits and bits using the `Circuit.add_qubit` and `Circuit.add_bit` |
| 44 | +# methods.. |
43 | 45 |
|
44 | 46 | circuit = Circuit(num_qubits=2, num_bits=2) |
45 | 47 |
|
|
50 | 52 | ops.X() |
51 | 53 |
|
52 | 54 | ############################################################################### |
53 | | -# Notice above that an operation can be instantiated without declaring which |
| 55 | +# Notice above that you can instantiate an operation without declaring which |
54 | 56 | # qubits it should be applied to. |
55 | 57 | # |
56 | | -# The matrix property can be accessed either via the operation class itself or an |
| 58 | +# You can access the matrix property via either the operation class itself or an |
57 | 59 | # instance of the operation, which additionally can contain parameters and qubit |
58 | 60 | # information. |
59 | 61 |
|
|
66 | 68 | ops.RZ(4.2).matrix |
67 | 69 |
|
68 | 70 | ############################################################################### |
69 | | -# ## The circuit context |
| 71 | +# ## The Circuit Context |
70 | 72 | # |
71 | 73 | # Operations are applied by calling either a class or an instance of a class |
72 | 74 | # within the context of the circuit. |
|
78 | 80 | # |
79 | 81 |
|
80 | 82 | ############################################################################### |
81 | | -# When activating the context, a named tuple containing reference registers to the |
82 | | -# circuit's qubits and classical bits is returned. You can also access the qubit |
83 | | -# registers directly via the `Circuit.qregisters` property, or the reference |
84 | | -# registers containing all the qubits via `Circuit.qubits`. |
| 83 | +# When you activate a context, a named tuple containing reference registers to |
| 84 | +# the circuit's qubits and classical bits is returned. You can also access the |
| 85 | +# qubit registers directly, via the `Circuit.qregisters` property, or the |
| 86 | +# reference registers containing all the qubits, via `Circuit.qubits`. |
85 | 87 | # |
86 | 88 | # In the example below, the circuit contains a single qubit register with two |
87 | 89 | # qubits; it could contain any number of qubit registers. You can |
88 | 90 | # |
89 | 91 | # * add another register with the `Circuit.add_qregister` method, where an argument `n` |
90 | | -# is the number of qubits in the new register |
| 92 | +# is the number of qubits in the new register. |
91 | 93 | # * add a qubit with `Circuit.add_qubit`, optionally passing a qubit object |
92 | 94 | # and/or a register to which to add it. |
93 | 95 |
|
|
104 | 106 | print(circuit) |
105 | 107 |
|
106 | 108 | ############################################################################### |
107 | | -# ## Applying gates to circuits |
| 109 | +# ## Applying Gates to Circuits |
108 | 110 | # |
109 | 111 | # You can apply operations to a circuit in several different ways, as demonstrated |
110 | 112 | # in the example below. You can pass both qubits and parameters as either single |
|
115 | 117 | # :::note |
116 | 118 | # Always apply any operations you instantiate within a circuit context to |
117 | 119 | # specific qubits in the circuit's qubit register. You can access the qubit |
118 | | -# register via the named tuple returned by the context manager as `q`, indexing |
| 120 | +# register via the named tuple, returned by the context manager as `q`, indexing |
119 | 121 | # into it to retrieve the corresponding qubit. |
120 | 122 | # ::: |
121 | 123 |
|
|
161 | 163 | # ::: |
162 | 164 |
|
163 | 165 | ############################################################################### |
164 | | -# ## Simulating a circuit |
| 166 | +# ## Simulating a Circuit |
165 | 167 | # |
166 | | -# `dwave-gate` comes with a performant state-vector simulator. It can be called by passing a circuit to the `simulate` method, which will update the quatum state stored in the circuit, accessible via `Circuit.state`. |
| 168 | +# `dwave-gate` comes with a performant state-vector simulator. You can call it by |
| 169 | +# passing a circuit to the `simulate` method, which will update the quantum state |
| 170 | +# stored in the circuit, accessible via `Circuit.state`. |
167 | 171 |
|
168 | 172 | from dwave.gate.simulator import simulate |
169 | 173 |
|
170 | 174 | ############################################################################### |
171 | | -# We create a circuit object with 2 qubits and 1 bit in a quantum and classical registers respectively --- the bit is required to store a single qubit measurement --- and then apply a Hadamard gate and a CNOT gate to the circuit. |
| 175 | +# This example creates a circuit object with 2 qubits and 1 bit in a quantum and |
| 176 | +# a classical register respectively---the bit is required to store a single qubit |
| 177 | +# measurement---and then applies a Hadamard gate and a CNOT gate to the circuit. |
172 | 178 |
|
173 | 179 | circuit = Circuit(2, 1) |
174 | 180 |
|
|
177 | 183 | ops.CNOT(q[0], q[1]) |
178 | 184 |
|
179 | 185 | ############################################################################### |
180 | | -# We can now simulate the circuit, which will update its stored quantum state. |
| 186 | +# You can now simulate the circuit, updating its stored quantum state. |
181 | 187 |
|
182 | 188 | simulate(circuit) |
183 | 189 |
|
|
192 | 198 | ############################################################################### |
193 | 199 | # ## Measurements |
194 | 200 | # |
195 | | -# Measurements work like any other operation in dwave-gate. The main difference is that the operation generates a measurement value when simulated which can be stored in the classical register by piping it into a classical bit. |
| 201 | +# Measurements work like any other operation in `dwave-gate`. The main difference |
| 202 | +# is that the operation generates a measurement value when simulated, which can be |
| 203 | +# stored in the classical register by piping it into a classical bit. |
196 | 204 | # |
197 | | -# We can reuse the circuit from above by simply unlocking it and appending a `Measurement` to it. |
| 205 | +# You can reuse the circuit above by simply unlocking it and appending a `Measurement` to it. |
198 | 206 |
|
199 | 207 | circuit.unlock() |
200 | 208 | with circuit.context as (q, c): |
201 | 209 | m = ops.Measurement(q[1]) | c[0] |
202 | 210 |
|
203 | 211 | ############################################################################### |
204 | 212 | # :::note |
205 | | -# We stored the measurement instance as `m`, which we can use for post-processing. It's also possible to do this with all other operations in the same way, allowing for multiple identical operation applications. |
| 213 | +# This example stored the measurement instance as `m`, which you can use for |
| 214 | +# post-processing. It's also possible to do this with all other operations in |
| 215 | +# the same way, allowing for multiple identical operation applications. |
| 216 | +# |
206 | 217 | # ```python |
207 | 218 | # with circuit.context as q, _: |
208 | 219 | # single_x_op = ops.X(q[0]) |
209 | 220 | # # apply the X-gate again to the second qubit |
210 | 221 | # # using the previously stored operation |
211 | 222 | # single_x_op(q[1]) |
212 | 223 | # ``` |
213 | | -# This procedure can also be shortened into a single line for further convience. |
| 224 | +# This procedure can also be shortened into a single line for further convenience. |
214 | 225 | # ```python |
215 | 226 | # ops.CNOT(q[0], q[1])(q[1], q[2])(q[2], q[3]) |
216 | 227 | # ``` |
217 | 228 | # ::: |
218 | 229 |
|
219 | 230 | ############################################################################### |
220 | | -# The circuit should now contain 3 operations: a Hadamard, a CNOT and a measurment. |
| 231 | +# The circuit should now contain 3 operations: a Hadamard, a CNOT and a measurement. |
221 | 232 |
|
222 | 233 | print(circuit) |
223 | 234 |
|
224 | 235 | ############################################################################### |
225 | | -# When simulating this circuit, the measurement will be applied and the measured value will be stored in the classical register. Since a measurement will affect the quantum state, the resulting state will have collapsed into the expected result dependent on the value which has been measured. |
| 236 | +# When you simulate this circuit, the measurement is applied and the measured |
| 237 | +# value is stored in the classical register. Since a measurement affects the |
| 238 | +# quantum state, the resulting state has collapsed into the expected result |
| 239 | +# dependent on the value which has been measured. |
226 | 240 |
|
227 | 241 | simulate(circuit) |
228 | 242 |
|
229 | 243 | ############################################################################### |
230 | | -# If the measurement result is 0 the state should collapse into $\vert00\rangle$, and if the measurement result is 1 the state should collapse into $\vert11\rangle$. Outputting the measurement value and the state reveals that this is indeed the case. |
| 244 | +# If the measurement result is 0 the state should collapse into $\vert00\rangle$, |
| 245 | +# and if the measurement result is 1 the state should collapse into $\vert11\rangle$. |
| 246 | +# Outputting the measurement value and the state reveals that this is indeed the case. |
231 | 247 |
|
232 | 248 | print(circuit.bits[0].value) |
233 | 249 | print(circuit.state) |
234 | 250 |
|
235 | 251 | ############################################################################### |
236 | | -# ## Measurement post-access |
237 | | -# Since we stored the measurement operation in `m`, we can use it to access the state as it was before the measurement. |
| 252 | +# ## Measurement Post-Access |
| 253 | +# Since you stored the measurement operation in `m`, you can use it to access the |
| 254 | +# state as it was before the measurement. |
238 | 255 | # |
239 | 256 | # :::note |
240 | 257 | # Accessing the state of the circuit along with any measurement post-sampling and state-access is only available for simulators. |
|
243 | 260 | m.state |
244 | 261 |
|
245 | 262 | ############################################################################### |
246 | | -# We can also sample that same state again using the `Measurement.sample` method, which by default only samples the state once. Here, we request 10 samples. |
| 263 | +# You can also sample that same state again using the `Measurement.sample` method, |
| 264 | +# which by default only samples the state once. Here, request 10 samples. |
247 | 265 |
|
248 | 266 | m.sample(num_samples=10) |
249 | 267 |
|
250 | 268 | ############################################################################### |
251 | | -# Finally, we can calculate the expected value of the measurment based on a specific number of samples. |
| 269 | +# Finally, you can calculate the expected value of the measurement based on a |
| 270 | +# specific number of samples. |
252 | 271 |
|
253 | 272 | m.expval(num_samples=10000) |
254 | 273 |
|
|
0 commit comments