-
Notifications
You must be signed in to change notification settings - Fork 9
Demos page #35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Demos page #35
Changes from 5 commits
5e181a6
693f3c2
c3fb20f
d90829f
0718763
2d81f0e
9f50c55
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -47,6 +47,7 @@ cov.xml | |
|
|
||
| # Sphinx documentation | ||
| docs/_build/ | ||
| docs/demos/out | ||
|
|
||
| # Jupyter Notebook | ||
| .ipynb_checkpoints | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,10 +8,54 @@ SPHINXBUILD ?= sphinx-build | |
| SOURCEDIR = . | ||
| BUILDDIR = _build | ||
|
|
||
| JUPYTEXT ?= jupytext | ||
| NBCONVERT ?= jupyter nbconvert | ||
| DEMOFOLDER = demos/demos | ||
| OUTFOLDER = demos/out | ||
|
|
||
| # Script to add download buttons to the bottom of the rst files | ||
| ADD_DOWNLOAD_BUTTONS ="$\ | ||
| \$$a$\ | ||
| :download:\`Download Python source code \<$$(basename $$1 .rst).py\>\`\n\n$\ | ||
| :download:\`Download as Jupyter Notebook \<$$(basename $$1 .rst).ipynb\>\`\n" | ||
|
|
||
| # Script to add file names as labels to the top of the rst files | ||
| ADD_FILE_NAME_LABEL = "1s/^/.. _$$(basename $$1 .rst):\n\n/" | ||
|
|
||
| # Put it first so that "make" without argument is like "make help". | ||
| help: | ||
| @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) | ||
|
|
||
| .PHONY: demos | ||
| demos: | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This build rule is sufficiently complex to warrant a stand-alone shell script. Or, given how shell scripts are generally fragile, unmaintainable and unscalable, perhaps switch to something more portable and extensible, like Python? 🙂
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thought about it, and it's a good idea. I don't necessarily mind the simplicity of having it like this though. Perhaps leaving it like this for the time being and potentially reevaluate later. |
||
| # 0. create the output folder and copy all Python source files over to it | ||
| mkdir -p $(OUTFOLDER) | ||
| cp -a $(DEMOFOLDER)/. $(OUTFOLDER) | ||
|
|
||
| # 1. find all Python demos and convert them to Jupyter notebooks | ||
| find $(DEMOFOLDER) -name '*.py' -exec sh -c '$(JUPYTEXT) --to ipynb $$1 --output "$(OUTFOLDER)/$$(basename $$1 .py).ipynb"' sh {} \; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can use shell's built-in parameter expansion to avoid calling (external) |
||
|
|
||
| # 2. find all Jupyter notebooks and convert them into Sphinx rst files | ||
| find $(OUTFOLDER) -name '*.ipynb' -exec $(NBCONVERT) {} --to rst --output-dir=$(OUTFOLDER) --execute --RegexRemovePreprocessor.patterns="^%" \; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe you'll want to skip processing notebooks under |
||
|
|
||
| # 3. find all rst files and, add file name labels, replace major classes/methods with Sphinx hyperlinks, and add download links | ||
| find $(OUTFOLDER) -name '*.rst' -exec sh -c 'sed --in-place \ | ||
| -e $(ADD_FILE_NAME_LABEL) \ | ||
| -e "s/\`\`Circuit\`\`/:class:\`~dwave.gate.circuit.Circuit\`/g" \ | ||
| -e "s/\`\`Circuit\.\(\w*\)\`\`/:meth:\`~dwave.gate.circuit.Circuit.\1\`/g" \ | ||
| -e "s/\`\`ParametricCircuit\`\`/:class:\`~dwave.gate.circuit.ParametricCircuit\`/g" \ | ||
| -e "s/\`\`Operation\`\`/:class:\`~dwave.gate.operations.base.Operation\`/g" \ | ||
| -e "s/\`\`operations\`\`/:mod:\`~dwave.gate.operations\`/g" \ | ||
| -e "s/\`\`ops\.\(\w*\)\`\`/:class:\`~dwave.gate.operations.operations.\1\`/g" \ | ||
| -e "s/\`\`Measurement\`\`/:mod:\`~dwave.gate.operations.base.Measurement\`/g" \ | ||
| -e "s/\`\`ParametricOperation\`\`/:mod:\`~dwave.gate.operations.base.ParametricOperation\`/g" \ | ||
| -e "s/\`\`ControlledOperation\`\`/:mod:\`~dwave.gate.operations.base.ControlledOperation\`/g" \ | ||
| -e "s/\`\`ParametricControlledOperation\`\`/:mod:\`~dwave.gate.operations.base.ParametricControlledOperation\`/g" \ | ||
| -e "s/\`\`simulate\`\`/:mod:\`~dwave.gate.simulator.simulate\`/g" \ | ||
| -e "s/\`\`simulator\.\(\w*\)\`\`/:class:\`~dwave.gate.simulator.\1\`/g" \ | ||
| -e $(ADD_DOWNLOAD_BUTTONS) \ | ||
| $$1' sh {} \; \ | ||
|
Comment on lines
+42
to
+57
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you prefer |
||
|
|
||
| .PHONY: help Makefile | ||
|
|
||
| # Catch-all target: route all unknown targets to Sphinx using the new | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,256 @@ | ||
| # --- | ||
| # jupyter: | ||
| # jupytext: | ||
| # text_representation: | ||
| # extension: .py | ||
| # format_name: sphinx | ||
| # format_version: '1.1' | ||
| # jupytext_version: 1.14.5 | ||
| # kernelspec: | ||
| # display_name: dwave-gate | ||
| # language: python | ||
| # name: python3 | ||
| # --- | ||
|
|
||
| """ | ||
| # Beginner's Guide to `dwave-gate` | ||
| `dwave-gate` lets you easily construct and simulate quantum circuits. | ||
thisac marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| This tutorial guides you through using the `dwave-gate` library to inspect, | ||
| construct, and simulate quantum circuits using a performant state-vector | ||
| simulator. | ||
| ## Circuits and operations | ||
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| Begin with two necessary imports: The `Circuit` class, which will contain the | ||
| full quantum circuit with all the operations, measurements, qubits and bits, and | ||
| the operations module. The operations, or gates, contain information related to | ||
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| a particular operation, including its matrix representation, potential | ||
| decompositions, and how to apply it to a circuit. | ||
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| """ | ||
|
|
||
| from dwave.gate.circuit import Circuit | ||
| import dwave.gate.operations as ops | ||
|
|
||
| ############################################################################### | ||
| # The `Circuit` keeps track of the operations and the logical flow of their | ||
| # excecutions. It also stores the qubits, bits and measurments. | ||
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| # | ||
| # When initializing a circuit, the number of qubits and (optionally) the number of | ||
| # bits, i.e., classical measurement results containers, need to be declared. More | ||
| # qubits and bits can be added using the `Circuit.add_qubit` and `Circuit.add_bit` | ||
| # methods. | ||
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| circuit = Circuit(num_qubits=2, num_bits=2) | ||
|
|
||
| ############################################################################### | ||
| # You can use the `operations` module (shortened above to `ops`) to access a | ||
| # variety of quantum gates; for example, a Pauli X operator. | ||
|
|
||
| ops.X() | ||
|
|
||
| ############################################################################### | ||
| # Notice above that an operation can be instantiated without declaring which | ||
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| # qubits it should be applied to. | ||
| # | ||
| # The matrix property can be accessed either via the operation class itself or an | ||
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| # instance of the operation, which additionally can contain parameters and qubit | ||
| # information. | ||
|
|
||
| ops.X.matrix | ||
|
|
||
| ############################################################################### | ||
| # If the matrix representation is dependent on parameters (e.g., the rotation operation `ops.RX`) | ||
| # it can only be retrieved from an instance. | ||
|
|
||
| ops.RZ(4.2).matrix | ||
|
|
||
| ############################################################################### | ||
| # ## The circuit context | ||
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| # | ||
| # Operations are applied by calling either a class or an instance of a class | ||
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| # within the context of the circuit. | ||
| # | ||
| # ```python | ||
| # with circuit.context: | ||
| # # apply operations here | ||
| # ``` | ||
| # | ||
|
|
||
| ############################################################################### | ||
| # When activating the context, a named tuple containing reference registers to the | ||
| # circuit's qubits and classical bits is returned. You can also access the qubit | ||
| # registers directly via the `Circuit.qregisters` property, or the reference | ||
| # registers containing all the qubits via `Circuit.qubits`. | ||
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| # | ||
| # In the example below, the circuit contains a single qubit register with two | ||
| # qubits; it could contain any number of qubit registers. You can | ||
| # | ||
thisac marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| # * add another register with the `Circuit.add_qregister` method, where an argument `n` | ||
| # is the number of qubits in the new register | ||
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| # * add a qubit with `Circuit.add_qubit`, optionally passing a qubit object | ||
| # and/or a register to which to add it. | ||
|
|
||
| circuit = Circuit(2) | ||
|
|
||
| with circuit.context as reg: | ||
| ops.X(reg.q[0]) | ||
|
|
||
| ############################################################################### | ||
| # This example created a circuit object with two qubits in its register, applying | ||
| # a single X gate to the first qubit. Print the circuit to see general information | ||
| # about it: type of circuit, number of qubits/bits, and number of operations. | ||
|
|
||
| print(circuit) | ||
|
|
||
| ############################################################################### | ||
| # ## Applying gates to circuits | ||
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| # | ||
| # You can apply operations to a circuit in several different ways, as demonstrated | ||
| # in the example below. You can pass both qubits and parameters as either single | ||
| # values (when supported by the gate) or sequences. Note that different types of | ||
| # gates accept slightly different arguments, although you can _always_ pass the | ||
| # qubits as sequences via the keyword argument `qubits`. | ||
| # | ||
| # :::note | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you looking at the rendered docs (i.e., the rst file) or the jupyter notebook? The latter will not render the notebox, but the former should be displayed as above, rendering the docs nicely.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not working for me as well (in the jupyter notebook).
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Strange. @JoelPasvolsky seemed to get it to work when building everything in Codespaces and suspected it had to do with his Ubuntu version. Since it seems to be causing issues I'll look into it, but as long as the demos are built correctly in the live docs I'd think it's fine.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I recently updated my Ubuntu so if it's needed to help debug I can run locally again and see if it now works |
||
| # Always apply any operations you instantiate within a circuit context to | ||
| # specific qubits in the circuit's qubit register. You can access the qubit | ||
| # register via the named tuple returned by the context manager as `q`, indexing | ||
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| # into it to retrieve the corresponding qubit. | ||
| # ::: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| circuit = Circuit(3) | ||
|
|
||
| with circuit.context as (q, c): | ||
| # apply single-qubit gate | ||
| ops.Z(q[0]) | ||
| # apply single-qubit gate using kwarg | ||
| ops.Hadamard(qubits=q[0]) | ||
| # apply a parametric gate | ||
| ops.RY(4.2, q[1]) | ||
| # apply a parametric gate using kwargs | ||
| ops.Rotation(parameters=[4.2, 3.1, 2.3], qubits=q[1]) | ||
| # apply controlled gate | ||
| ops.CNOT(q[0], q[1]) | ||
| # apply controlled gate using kwargs | ||
| ops.CX(control=q[0], target=q[1]) | ||
| # apply controlled qubit gates using slicing (must unpack) | ||
| ops.CZ(*q[:2]) | ||
| # apply multi-qubit (non-controlled) gates (note tuple) | ||
| ops.SWAP((q[0], q[1])) | ||
| # apply multi-qubit (non-controlled) gates using kwargs | ||
| ops.CSWAP(qubits=(q[0], q[1], q[2])) | ||
| # apply multi-qubit (non-controlled) gates using slicing | ||
| ops.SWAP(q[:2]) | ||
| # apply gate on all qubits in the circuit | ||
| ops.Toffoli(q) | ||
|
|
||
| ############################################################################### | ||
| # You can access all the operations in a circuit using the `Circuit.circuit` | ||
| # property. The code below iterates over the returned list of all operations that | ||
| # have been applied to the circuit. | ||
|
|
||
| for op in circuit.circuit: | ||
| print(op) | ||
|
|
||
| ############################################################################### | ||
| # :::note | ||
thisac marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| # The CNOT alias for the controlled NOT gate is labelled CX in the circuit. You | ||
| # can find all operation aliases in the source code and documentation for the | ||
| # operations module. | ||
| # ::: | ||
|
|
||
| ############################################################################### | ||
| # ## Simulating a circuit | ||
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| # | ||
| # `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`. | ||
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| from dwave.gate.simulator import simulate | ||
|
|
||
| ############################################################################### | ||
| # 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. | ||
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| circuit = Circuit(2, 1) | ||
|
|
||
| with circuit.context as (q, c): | ||
| ops.Hadamard(q[0]) | ||
| ops.CNOT(q[0], q[1]) | ||
|
|
||
| ############################################################################### | ||
| # We can now simulate the circuit, which will update its stored quantum state. | ||
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| simulate(circuit) | ||
|
|
||
| ############################################################################### | ||
| # Printing the state reveals the expected state-vector $\frac{1}{\sqrt{2}}\left[1, | ||
| # 0, 0, 1\right]$ corresponding to the state: | ||
| # | ||
| # $$\vert\psi\rangle = \frac{1}{\sqrt{2}}\left(\vert00\rangle + \vert11\rangle\right)$$ | ||
|
|
||
| circuit.state | ||
|
|
||
| ############################################################################### | ||
| # ## Measurements | ||
| # | ||
| # 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. | ||
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| # | ||
| # We can reuse the circuit from above by simply unlocking it and appending a `Measurement` to it. | ||
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| circuit.unlock() | ||
| with circuit.context as (q, c): | ||
| m = ops.Measurement(q[1]) | c[0] | ||
|
|
||
| ############################################################################### | ||
| # :::note | ||
thisac marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| # 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. | ||
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| # ```python | ||
| # with circuit.context as q, _: | ||
| # single_x_op = ops.X(q[0]) | ||
| # # apply the X-gate again to the second qubit | ||
| # # using the previously stored operation | ||
| # single_x_op(q[1]) | ||
| # ``` | ||
| # This procedure can also be shortened into a single line for further convience. | ||
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| # ```python | ||
| # ops.CNOT(q[0], q[1])(q[1], q[2])(q[2], q[3]) | ||
| # ``` | ||
| # ::: | ||
thisac marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| ############################################################################### | ||
| # The circuit should now contain 3 operations: a Hadamard, a CNOT and a measurment. | ||
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| print(circuit) | ||
|
|
||
| ############################################################################### | ||
| # 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. | ||
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| simulate(circuit) | ||
|
|
||
| ############################################################################### | ||
| # 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. | ||
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| print(circuit.bits[0].value) | ||
| print(circuit.state) | ||
|
|
||
| ############################################################################### | ||
| # ## Measurement post-access | ||
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| # Since we stored the measurement operation in `m`, we can use it to access the state as it was before the measurement. | ||
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| # | ||
| # :::note | ||
thisac marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| # Accessing the state of the circuit along with any measurement post-sampling and state-access is only available for simulators. | ||
| # ::: | ||
thisac marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| m.state | ||
|
|
||
| ############################################################################### | ||
| # 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. | ||
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| m.sample(num_samples=10) | ||
|
|
||
| ############################################################################### | ||
| # Finally, we can calculate the expected value of the measurment based on a specific number of samples. | ||
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
thisac marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| m.expval(num_samples=10000) | ||
|
|
||
| "" | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| Demos and Examples | ||
| ================== | ||
|
|
||
| ``dwave-gate`` demonstrations and examples. | ||
|
|
||
|
|
||
| Tutorials | ||
| --------- | ||
|
|
||
| .. card:: Beginner's Guide to ``dwave-gate`` | ||
| :link: intro_demo | ||
| :link-type: ref | ||
|
|
||
| Tutorial on how to use ``dwave-gate`` to construct and simulate quantum circuits. | ||
|
|
||
| .. toctree:: | ||
| :maxdepth: 1 | ||
| :hidden: | ||
|
|
||
| out/intro_demo |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,6 +18,7 @@ Documentation | |
| :maxdepth: 1 | ||
|
|
||
| reference/index | ||
| demos/index | ||
| release_notes | ||
|
|
||
| .. toctree:: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,3 +2,9 @@ docutils==0.17.1 | |
| sphinx==5.3.0 | ||
| sphinx-rtd-theme==1.1.1 | ||
| sphinx_autodoc_typehints==1.19.5 | ||
| sphinx-design==0.4.1 | ||
| ipykernel==6.23.1 | ||
| matplotlib==3.71 | ||
|
||
| nbconvert==7.4.0 | ||
thisac marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| jupytext==1.14.5 | ||
| reno[sphinx]==3.5.0 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,6 +17,7 @@ dwave-gate | |
| :maxdepth: 1 | ||
|
|
||
| reference/index | ||
| demos/index | ||
| release_notes | ||
|
|
||
| .. toctree:: | ||
|
|
||




There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can also use sed's insert command to prepend text (slightly simpler expression). When combined with parameter expansion switch as suggested below: