-
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 all 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,279 @@ | ||
| # --- | ||
| # 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 | ||
| 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. | ||
| """ | ||
|
|
||
| from dwave.gate.circuit import Circuit | ||
| import dwave.gate.operations as ops | ||
|
|
||
| ############################################################################### | ||
| # The operations, or gates, contain information related to a particular operation, | ||
| # including its matrix representation, potential decompositions, and how to apply | ||
| # it to a circuit. | ||
| # | ||
| # The `Circuit` keeps track of the operations and the logical | ||
| # flow of their executions. It also stores the qubits, bits and measurements. | ||
| # | ||
| # When initializing a circuit, you need to declare the number of qubits and, | ||
| # optionally, the number of bits (i.e., classical measurement results containers). | ||
| # You can add more qubits and bits using the `Circuit.add_qubit` and `Circuit.add_bit` | ||
| # methods. | ||
|
|
||
| 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, the Pauli X operator. Note that you can | ||
| # instantiate an operation without declaring which qubits it should be applied | ||
| # to. | ||
|
|
||
| ops.X() | ||
|
|
||
| ############################################################################### | ||
| # You can access the matrix property via either the operation class itself or an | ||
| # instance of the operation, which additionally can contain parameters and qubit | ||
| # information. | ||
|
|
||
| ops.X.matrix | ||
|
|
||
| ############################################################################### | ||
| # If the matrix representation of an operator 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 | ||
| # | ||
| # Operations are applied by calling either an operation class, or an instance of | ||
| # an operation class, within the context of the circuit, passing along the | ||
| # qubits on which the operation is applied. | ||
| # | ||
| # ```python | ||
| # with circuit.context: | ||
| # # apply operations here | ||
| # ``` | ||
| # | ||
|
|
||
| ############################################################################### | ||
| # When you activate a 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`. | ||
| # | ||
| # 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. | ||
| # * 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 has 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 | ||
| # | ||
| # 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 as 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 | ||
| # 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 a list of all operations that | ||
| # have been applied to the circuit and prints each one separately. | ||
|
|
||
| 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 | ||
| # | ||
| # `dwave-gate` comes with a performant state-vector simulator. You can call it by | ||
| # passing a circuit to the `simulate` method, which will update the quantum state | ||
| # stored in the circuit, accessible via `Circuit.state`. | ||
|
|
||
| from dwave.gate.simulator import simulate | ||
|
|
||
| ############################################################################### | ||
| # The following example creates a circuit object with 2 qubits and 1 bit in a | ||
| # quantum and a classical register respectively---the bit is required to store a | ||
| # single qubit measurement---and then applies a Hadamard gate and a CNOT gate to | ||
| # the circuit. | ||
|
|
||
| circuit = Circuit(2, 1) | ||
|
|
||
| with circuit.context as (q, c): | ||
| ops.Hadamard(q[0]) | ||
| ops.CNOT(q[0], q[1]) | ||
|
|
||
| ############################################################################### | ||
| # You can now simulate the circuit, updating its stored quantum state. | ||
|
|
||
| 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. | ||
| # | ||
| # The circuit above can be reused by simply unlocking it and appending a `Measurement` to it. | ||
|
|
||
| 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
|
||
| # This example stored the measurement instance as `m`, which you 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. | ||
| # | ||
| # ```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 convenience. | ||
| # | ||
| # ```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 measurement. | ||
|
|
||
| print(circuit) | ||
|
|
||
| ############################################################################### | ||
| # When simulating this circuit, the measurement is applied and the measured | ||
| # value is stored in the classical register. Since a measurement affects the | ||
| # quantum state, the resulting state has collapsed into the expected result | ||
| # dependent on the value which has been measured. | ||
|
|
||
| simulate(circuit) | ||
|
|
||
| ############################################################################### | ||
| # If the measurement result is 0 the state should have collapsed into $\vert00\rangle$, | ||
| # and if the measurement result is 1 the state should have collapsed into $\vert11\rangle$. | ||
| # Outputting the measurement value and the state reveals that this is indeed the case. | ||
|
|
||
| print(circuit.bits[0].value) | ||
| print(circuit.state) | ||
|
|
||
| ############################################################################### | ||
| # ## Measurement Post-Access | ||
| # Since the measurement operation has been stored in `m`, you can use it to access the | ||
| # state as it was before the measurement. | ||
| # | ||
| # :::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 | ||
|
|
||
| ############################################################################### | ||
| # You can also sample that same state again using the `Measurement.sample` method, | ||
| # which by default only samples the state once. Here, request 10 samples. | ||
|
|
||
| m.sample(num_samples=10) | ||
|
|
||
| ############################################################################### | ||
| # Finally, you can calculate the expected value of the measurement based on a | ||
| # specific number of samples. | ||
|
|
||
| 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 |
|---|---|---|
|
|
@@ -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: