├── .coveralls.yml
├── projectq
├── backends
│ ├── _sim
│ │ ├── .gitignore
│ │ ├── __init__.py
│ │ ├── _cppkernels
│ │ │ ├── intrin
│ │ │ │ ├── kernels.hpp
│ │ │ │ ├── kernel1.hpp
│ │ │ │ └── kernel2.hpp
│ │ │ └── nointrin
│ │ │ │ ├── kernels.hpp
│ │ │ │ ├── kernel1.hpp
│ │ │ │ └── kernel2.hpp
│ │ ├── _simulator_test_fixtures.py
│ │ └── _cppsim.cpp
│ ├── _aqt
│ │ └── __init__.py
│ ├── _ibm
│ │ └── __init__.py
│ ├── _ionq
│ │ └── __init__.py
│ ├── _azure
│ │ ├── _exceptions.py
│ │ └── __init__.py
│ ├── _circuits
│ │ └── __init__.py
│ ├── _utils.py
│ ├── _utils_test.py
│ ├── _awsbraket
│ │ └── __init__.py
│ ├── _exceptions.py
│ └── __init__.py
├── tests
│ ├── __init__.py
│ └── _factoring_test.py
├── libs
│ ├── __init__.py
│ ├── hist
│ │ ├── __init__.py
│ │ └── _histogram.py
│ ├── revkit
│ │ ├── __init__.py
│ │ ├── _utils.py
│ │ ├── _phase_test.py
│ │ ├── _control_function_test.py
│ │ └── _permutation_test.py
│ └── math
│ │ └── __init__.py
├── setups
│ ├── __init__.py
│ ├── decompositions
│ │ ├── barrier.py
│ │ ├── globalphase.py
│ │ ├── cnot2cz.py
│ │ ├── entangle.py
│ │ ├── r2rzandph.py
│ │ ├── swap2cnot.py
│ │ ├── rx2rz.py
│ │ ├── ry2rz.py
│ │ ├── ph2r.py
│ │ ├── qft2crandhadamard.py
│ │ ├── crz2cxandrz.py
│ │ ├── sqrtswap2cnot.py
│ │ ├── toffoli2cnotandtgate.py
│ │ ├── controlstate.py
│ │ ├── controlstate_test.py
│ │ ├── qubitop2onequbit.py
│ │ ├── barrier_test.py
│ │ ├── __init__.py
│ │ ├── h2rx.py
│ │ ├── cnot2rxx.py
│ │ ├── rz2rx.py
│ │ ├── cnu2toffoliandcu.py
│ │ ├── stateprep2cnot_test.py
│ │ ├── rx2rz_test.py
│ │ └── ry2rz_test.py
│ ├── default.py
│ ├── ionq_test.py
│ ├── ionq.py
│ ├── aqt_test.py
│ ├── ibm_test.py
│ └── aqt.py
├── types
│ └── __init__.py
├── ops
│ ├── _qpegate_test.py
│ ├── _qftgate_test.py
│ ├── _shortcuts_test.py
│ ├── _qaagate_test.py
│ ├── _qftgate.py
│ ├── _shortcuts.py
│ ├── _qpegate.py
│ ├── _state_prep_test.py
│ ├── __init__.py
│ ├── _state_prep.py
│ └── _uniformly_controlled_rotation_test.py
├── cengines
│ ├── _replacer
│ │ ├── __init__.py
│ │ ├── _decomposition_rule_test.py
│ │ └── _decomposition_rule.py
│ ├── _withflushing_test.py
│ ├── _manualmapper_test.py
│ ├── _cmdmodifier_test.py
│ ├── _tagremover_test.py
│ ├── __init__.py
│ ├── _manualmapper.py
│ ├── _cmdmodifier.py
│ ├── _tagremover.py
│ └── _basicmapper_test.py
├── meta
│ ├── _dirtyqubit.py
│ ├── _exceptions.py
│ ├── _dirtyqubit_test.py
│ ├── _logicalqubit_test.py
│ ├── _logicalqubit.py
│ ├── __init__.py
│ ├── _util_test.py
│ ├── _util.py
│ └── _dagger_test.py
└── __init__.py
├── .codespell.allow
├── .yamllint
├── docs
├── images
│ ├── bellpair_circuit.png
│ └── teleport_circuit.png
├── projectq.rst
├── README.rst
└── index.rst
├── NOTICE
├── MANIFEST.in
├── .editorconfig
├── .github
├── dependabot.yml
└── workflows
│ ├── pull_request.yml
│ ├── format.yml
│ └── draft_release.yml
├── .readthedocs.yaml
├── setup.cfg
└── examples
├── quantum_random_numbers.py
├── quantum_random_numbers_ibm.py
├── bellpair_circuit.py
├── hws4.py
├── teleport_circuit.py
├── hws6.py
├── aqt.py
├── ibm.py
├── grover.py
├── README.rst
├── ionq.py
├── ionq_half_adder.py
├── unitary_simulator.py
├── ionq_bv.py
└── gate_zoo.py
/.coveralls.yml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/projectq/backends/_sim/.gitignore:
--------------------------------------------------------------------------------
1 | *.so
2 |
--------------------------------------------------------------------------------
/.codespell.allow:
--------------------------------------------------------------------------------
1 | Braket
2 | braket
3 | te
4 | Ket
5 | ket
6 |
--------------------------------------------------------------------------------
/.yamllint:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | extends: default
4 |
5 | rules:
6 | line-length:
7 | max: 120
8 | level: error
9 |
--------------------------------------------------------------------------------
/docs/images/bellpair_circuit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProjectQ-Framework/ProjectQ/HEAD/docs/images/bellpair_circuit.png
--------------------------------------------------------------------------------
/docs/images/teleport_circuit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProjectQ-Framework/ProjectQ/HEAD/docs/images/teleport_circuit.png
--------------------------------------------------------------------------------
/NOTICE:
--------------------------------------------------------------------------------
1 | ProjectQ (www.projectq.ch)
2 |
3 | The first release of ProjectQ (v0.1) was developed by Thomas Haener (thomas@projectq.ch) and Damian S. Steiger (damian@projectq.ch) at ETH Zurich in 2016.
4 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include LICENSE
2 | include CHANGELOG.md
3 | include MANIFEST.in
4 | include NOTICE
5 | include README.rst
6 | include setup.py
7 | include setup.cfg
8 | include pyproject.toml
9 |
10 | recursive-include projectq *.py *.hpp *.cpp
11 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | end_of_line = lf
5 | trim_trailing_whitespace = true
6 | insert_final_newline = false
7 | indent_style = space
8 | indent_size = 4
9 |
10 | [*.{yml,yaml}]
11 | indent_style = space
12 | indent_size = 2
13 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "github-actions"
4 | directory: "/"
5 | schedule:
6 | interval: "weekly"
7 | ignore:
8 | # Optional: Official actions have moving tags like v1;
9 | # if you use those, you don't need updates.
10 | - dependency-name: "actions/*"
11 |
--------------------------------------------------------------------------------
/.readthedocs.yaml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | # .readthedocs.yaml
4 | # Read the Docs configuration file
5 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
6 |
7 | # Required
8 | version: 2
9 |
10 | sphinx:
11 | configuration: docs/conf.py
12 |
13 | formats: all
14 |
15 | python:
16 | version: 3.8
17 | install:
18 | - method: pip
19 | path: .
20 | extra_requirements:
21 | - docs
22 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [options]
2 |
3 | zip_safe = False
4 | packages = find:
5 |
6 | # ==============================================================================
7 |
8 | [flake8]
9 |
10 | max-line-length = 120
11 | ignore = E203,W503,E800
12 | exclude =
13 | .git,
14 | __pycache__,
15 | build,
16 | dist,
17 | __init__.py
18 | docstring-quotes = """
19 |
20 | # ==============================================================================
21 |
--------------------------------------------------------------------------------
/examples/quantum_random_numbers.py:
--------------------------------------------------------------------------------
1 | # pylint: skip-file
2 |
3 | """Example of a simple quantum random number generator."""
4 |
5 | from projectq import MainEngine
6 | from projectq.ops import H, Measure
7 |
8 | # create a main compiler engine
9 | eng = MainEngine()
10 |
11 | # allocate one qubit
12 | q1 = eng.allocate_qubit()
13 |
14 | # put it in superposition
15 | H | q1
16 |
17 | # measure
18 | Measure | q1
19 |
20 | eng.flush()
21 | # print the result:
22 | print(f"Measured: {int(q1)}")
23 |
--------------------------------------------------------------------------------
/.github/workflows/pull_request.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | name: PR
4 | on:
5 | merge_group:
6 | pull_request:
7 | types: [opened, synchronize, reopened, ready_for_review, labeled, unlabeled]
8 |
9 | jobs:
10 | # Enforces the update of a changelog file on every pull request
11 | changelog:
12 | runs-on: ubuntu-latest
13 | if: github.ref != 'refs/heads/master'
14 | steps:
15 | - uses: actions/checkout@v3
16 |
17 | - id: changelog-enforcer
18 | uses: dangoslen/changelog-enforcer@v3
19 | with:
20 | changeLogPath: 'CHANGELOG.md'
21 | skipLabels: 'Skip-Changelog'
22 |
--------------------------------------------------------------------------------
/docs/projectq.rst:
--------------------------------------------------------------------------------
1 | .. _code_doc:
2 |
3 | Code Documentation
4 | ==================
5 |
6 | Welcome to the package documentation of ProjectQ. You may now browse through the entire documentation and discover the
7 | capabilities of the ProjectQ framework.
8 |
9 | For a detailed documentation of a subpackage or module, click on its name below:
10 |
11 | .. toctree::
12 | :maxdepth: 1
13 | :titlesonly:
14 |
15 | _doc_gen/projectq.backends
16 | _doc_gen/projectq.cengines
17 | _doc_gen/projectq.libs
18 | _doc_gen/projectq.meta
19 | _doc_gen/projectq.ops
20 | _doc_gen/projectq.setups
21 | _doc_gen/projectq.types
22 |
--------------------------------------------------------------------------------
/examples/quantum_random_numbers_ibm.py:
--------------------------------------------------------------------------------
1 | # pylint: skip-file
2 |
3 | """Example of a simple quantum random number generator using IBM's API."""
4 |
5 | import projectq.setups.ibm
6 | from projectq import MainEngine
7 | from projectq.backends import IBMBackend
8 | from projectq.ops import H, Measure
9 |
10 | # create a main compiler engine
11 | eng = MainEngine(IBMBackend(), engine_list=projectq.setups.ibm.get_engine_list())
12 |
13 | # allocate one qubit
14 | q1 = eng.allocate_qubit()
15 |
16 | # put it in superposition
17 | H | q1
18 |
19 | # measure
20 | Measure | q1
21 |
22 | eng.flush()
23 | # print the result:
24 | print(f"Measured: {int(q1)}")
25 |
--------------------------------------------------------------------------------
/examples/bellpair_circuit.py:
--------------------------------------------------------------------------------
1 | # pylint: skip-file
2 |
3 | """Example implementation of a quantum circuit generating a Bell pair state."""
4 |
5 | import matplotlib.pyplot as plt
6 | from teleport import create_bell_pair
7 |
8 | from projectq import MainEngine
9 | from projectq.backends import CircuitDrawer
10 | from projectq.libs.hist import histogram
11 | from projectq.setups.default import get_engine_list
12 |
13 | # create a main compiler engine
14 | drawing_engine = CircuitDrawer()
15 | eng = MainEngine(engine_list=get_engine_list() + [drawing_engine])
16 |
17 | qb0, qb1 = create_bell_pair(eng)
18 |
19 | eng.flush()
20 | print(drawing_engine.get_latex())
21 |
22 | histogram(eng.backend, [qb0, qb1])
23 | plt.show()
24 |
--------------------------------------------------------------------------------
/projectq/tests/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """ProjectQ testing module."""
16 |
--------------------------------------------------------------------------------
/projectq/libs/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """ProjectQ module containing libraries expanding the basic functionalities of ProjectQ."""
16 |
--------------------------------------------------------------------------------
/examples/hws4.py:
--------------------------------------------------------------------------------
1 | # pylint: skip-file
2 |
3 | """Example of a 4-qubit phase function."""
4 |
5 | from projectq.cengines import MainEngine
6 | from projectq.libs.revkit import PhaseOracle
7 | from projectq.meta import Compute, Uncompute
8 | from projectq.ops import All, H, Measure, X
9 |
10 |
11 | # phase function
12 | def f(a, b, c, d):
13 | """Phase function."""
14 | return (a and b) ^ (c and d)
15 |
16 |
17 | eng = MainEngine()
18 | x1, x2, x3, x4 = qubits = eng.allocate_qureg(4)
19 |
20 | with Compute(eng):
21 | All(H) | qubits
22 | X | x1
23 | PhaseOracle(f) | qubits
24 | Uncompute(eng)
25 |
26 | PhaseOracle(f) | qubits
27 | All(H) | qubits
28 | All(Measure) | qubits
29 |
30 | eng.flush()
31 |
32 | print(f"Shift is {8 * int(x4) + 4 * int(x3) + 2 * int(x2) + int(x1)}")
33 |
--------------------------------------------------------------------------------
/projectq/setups/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """ProjectQ module containing the basic setups for ProjectQ as well as the decomposition rules."""
16 |
--------------------------------------------------------------------------------
/projectq/backends/_aqt/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2020 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """ProjectQ module for supporting the AQT platform."""
16 |
17 | from ._aqt import AQTBackend
18 |
--------------------------------------------------------------------------------
/projectq/backends/_ibm/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """ProjectQ module for supporting the IBM QE platform."""
16 |
17 | from ._ibm import IBMBackend
18 |
--------------------------------------------------------------------------------
/projectq/types/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """ProjectQ module containing all basic types."""
16 |
17 | from ._qubit import BasicQubit, Qubit, Qureg, WeakQubitRef
18 |
--------------------------------------------------------------------------------
/projectq/backends/_ionq/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2021 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """ProjectQ module for supporting the IonQ platform."""
16 |
17 | from ._ionq import IonQBackend
18 |
19 | __all__ = ['IonQBackend']
20 |
--------------------------------------------------------------------------------
/projectq/backends/_sim/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """ProjectQ module dedicated to simulation."""
16 |
17 | from ._classical_simulator import ClassicalSimulator
18 | from ._simulator import Simulator
19 |
--------------------------------------------------------------------------------
/examples/teleport_circuit.py:
--------------------------------------------------------------------------------
1 | # pylint: skip-file
2 |
3 | """Example if drawing of a quantum teleportation circuit."""
4 |
5 | import teleport
6 |
7 | from projectq import MainEngine
8 | from projectq.backends import CircuitDrawer
9 |
10 | if __name__ == "__main__":
11 | # create a main compiler engine with a simulator backend:
12 | drawing_engine = CircuitDrawer()
13 | locations = {0: 1, 1: 2, 2: 0}
14 | drawing_engine.set_qubit_locations(locations)
15 | eng = MainEngine(drawing_engine)
16 |
17 | # we just want to draw the teleportation circuit
18 | def create_state(eng, qb):
19 | """Create a quantum state."""
20 |
21 | # run the teleport and then, let Bob try to uncompute his qubit:
22 | teleport.run_teleport(eng, create_state, verbose=False)
23 |
24 | # print latex code to draw the circuit:
25 | print(drawing_engine.get_latex())
26 |
--------------------------------------------------------------------------------
/projectq/libs/hist/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2020 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """
15 | Measurement histogram plot helper functions.
16 |
17 | Contains a function to plot measurement outcome probabilities as a histogram for the simulator
18 | """
19 |
20 | from ._histogram import histogram
21 |
--------------------------------------------------------------------------------
/projectq/libs/revkit/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """Module containing code to interface with RevKit."""
16 |
17 | from ._control_function import ControlFunctionOracle
18 | from ._permutation import PermutationOracle
19 | from ._phase import PhaseOracle
20 |
--------------------------------------------------------------------------------
/projectq/ops/_qpegate_test.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """Tests for projectq.ops._qpegate."""
15 |
16 | from projectq.ops import X, _qpegate
17 |
18 |
19 | def test_qpe_str():
20 | unitary = X
21 | gate = _qpegate.QPE(unitary)
22 | assert str(gate) == "QPE(X)"
23 |
--------------------------------------------------------------------------------
/projectq/backends/_azure/_exceptions.py:
--------------------------------------------------------------------------------
1 | # Copyright 2022 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """Exception classes for projectq.backends._azure."""
16 |
17 |
18 | class AzureQuantumTargetNotFoundError(Exception):
19 | """Raised when a Azure Quantum target doesn't exist with given target name."""
20 |
--------------------------------------------------------------------------------
/projectq/cengines/_replacer/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from ._decomposition_rule import DecompositionRule, ThisIsNotAGateClassError
16 | from ._decomposition_rule_set import DecompositionRuleSet
17 | from ._replacer import AutoReplacer, InstructionFilter, NoGateDecompositionError
18 |
--------------------------------------------------------------------------------
/projectq/backends/_circuits/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """ProjectQ module for exporting/printing quantum circuits."""
16 |
17 | from ._drawer import CircuitDrawer
18 | from ._drawer_matplotlib import CircuitDrawerMatplotlib
19 | from ._plot import to_draw
20 | from ._to_latex import to_latex
21 |
--------------------------------------------------------------------------------
/projectq/ops/_qftgate_test.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """Tests for projectq.ops._qftgate."""
15 |
16 | from projectq.ops import _qftgate
17 |
18 |
19 | def test_qft_gate_str():
20 | gate = _qftgate.QFT
21 | assert str(gate) == "QFT"
22 |
23 |
24 | def test_qft_equality():
25 | assert _qftgate.QFT == _qftgate.QFTGate()
26 |
--------------------------------------------------------------------------------
/projectq/meta/_dirtyqubit.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """Define the DirtyQubitTag meta tag."""
16 |
17 |
18 | class DirtyQubitTag: # pylint: disable=too-few-public-methods
19 | """Dirty qubit meta tag."""
20 |
21 | def __eq__(self, other):
22 | """Equal operator."""
23 | return isinstance(other, DirtyQubitTag)
24 |
--------------------------------------------------------------------------------
/projectq/meta/_exceptions.py:
--------------------------------------------------------------------------------
1 | # Copyright 2021 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """Exception classes for projectq.meta."""
16 |
17 |
18 | class QubitManagementError(Exception):
19 | """
20 | Exception raised when the lifetime of a qubit is problematic within a context manager.
21 |
22 | This may occur within Loop, Dagger or Compute regions.
23 | """
24 |
--------------------------------------------------------------------------------
/projectq/ops/_shortcuts_test.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """Tests for projectq.ops._shortcuts."""
15 |
16 | from projectq.ops import ControlledGate, Rz, _shortcuts
17 |
18 |
19 | def test_crz():
20 | gate = _shortcuts.CRz(0.5)
21 | assert isinstance(gate, ControlledGate)
22 | assert gate._gate == Rz(0.5)
23 | assert gate._n == 1
24 |
--------------------------------------------------------------------------------
/.github/workflows/format.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | name: Format
4 |
5 | on:
6 | workflow_dispatch:
7 | merge_group:
8 | pull_request:
9 | push:
10 | branches:
11 | - master
12 | - stable
13 | - "v*"
14 |
15 | concurrency:
16 | group: ${{ github.workflow }}-${{ github.ref }}
17 | cancel-in-progress: true
18 |
19 |
20 | jobs:
21 | clang-tidy:
22 | name: Clang-Tidy
23 | runs-on: ubuntu-latest
24 | container: silkeh/clang:14
25 | env:
26 | CC: clang
27 | CXX: clang++
28 |
29 | steps:
30 | - uses: actions/checkout@v3
31 |
32 | - name: Prepare env
33 | run: >
34 | apt-get update && apt-get install -y python3-dev python3-pip python3-setuptools python3-wheel
35 | --no-install-recommends
36 |
37 | - name: Upgrade pybind11 and setuptools
38 | run: python3 -m pip install --upgrade pybind11 "setuptools>=61.0.0" --prefer-binary
39 |
40 | - name: Run clang-tidy
41 | run: python3 setup.py clang_tidy --warning-as-errors
42 |
--------------------------------------------------------------------------------
/projectq/meta/_dirtyqubit_test.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """Tests for projectq.meta._dirtyqubit.py"""
15 |
16 | from projectq.meta import ComputeTag, _dirtyqubit
17 |
18 |
19 | def test_dirty_qubit_tag():
20 | tag0 = _dirtyqubit.DirtyQubitTag()
21 | tag1 = _dirtyqubit.DirtyQubitTag()
22 | tag2 = ComputeTag()
23 | assert tag0 == tag1
24 | assert not tag0 != tag1
25 | assert not tag0 == tag2
26 |
--------------------------------------------------------------------------------
/projectq/ops/_qaagate_test.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """Tests for projectq.ops._qaagate."""
15 |
16 | from projectq.ops import All, H, X, _qaagate
17 |
18 |
19 | def test_qaa_str():
20 | def func_algorithm():
21 | All(H)
22 |
23 | def func_oracle():
24 | All(X)
25 |
26 | gate = _qaagate.QAA(func_algorithm, func_oracle)
27 | assert str(gate) == "QAA(Algorithm = func_algorithm, Oracle = func_oracle)"
28 |
--------------------------------------------------------------------------------
/projectq/ops/_qftgate.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """Definition of the QFT gate."""
16 |
17 | from ._basics import BasicGate
18 |
19 |
20 | class QFTGate(BasicGate):
21 | """Quantum Fourier Transform gate."""
22 |
23 | def __str__(self):
24 | """Return a string representation of the object."""
25 | return "QFT"
26 |
27 |
28 | #: Shortcut (instance of) :class:`projectq.ops.QFTGate`
29 | QFT = QFTGate()
30 |
--------------------------------------------------------------------------------
/projectq/libs/math/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """Math gate definitions."""
16 |
17 | from ._default_rules import all_defined_decomposition_rules
18 | from ._gates import (
19 | AddConstant,
20 | AddConstantModN,
21 | AddQuantum,
22 | ComparatorQuantum,
23 | DivideQuantum,
24 | MultiplyByConstantModN,
25 | MultiplyQuantum,
26 | SubConstant,
27 | SubConstantModN,
28 | SubtractQuantum,
29 | )
30 |
--------------------------------------------------------------------------------
/docs/README.rst:
--------------------------------------------------------------------------------
1 | Documentation
2 | =============
3 |
4 | .. image:: https://readthedocs.org/projects/projectq/badge/?version=latest
5 | :target: http://projectq.readthedocs.io/en/latest/?badge=latest
6 | :alt: Documentation Status
7 |
8 |
9 | Our detailed code documentation can be found online at `Read the Docs `__ and
10 | gets updated automatically. Besides the latest code documentation, there are also previous and offline versions
11 | available for download.
12 |
13 | Building the docs locally
14 | -------------------------
15 |
16 | Before submitting new code, please make sure that the new or changed docstrings render nicely by building the docs
17 | manually. To this end, one has to install sphinx and the Read the Docs theme:
18 |
19 | .. code-block:: bash
20 |
21 | python -m pip install sphinx
22 | python -m pip install sphinx_rtd_theme
23 |
24 | To build the documentation, navigate to this folder and execute:
25 |
26 | .. code-block:: bash
27 |
28 | make clean html
29 |
30 | Open _build/html/index.html to view the docs.
31 |
--------------------------------------------------------------------------------
/projectq/ops/_shortcuts.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """
15 | A few shortcuts for certain gates.
16 |
17 | These include:
18 | * CNOT = C(NOT)
19 | * CRz = C(Rz)
20 | * Toffoli = C(NOT,2) = C(CNOT)
21 | """
22 |
23 | from ._gates import NOT, Rz, Z
24 | from ._metagates import C
25 |
26 |
27 | def CRz(angle):
28 | """Shortcut for C(Rz(angle), n_qubits=1)."""
29 | return C(Rz(angle), n_qubits=1)
30 |
31 |
32 | CNOT = CX = C(NOT)
33 |
34 | CZ = C(Z)
35 |
36 | Toffoli = C(CNOT)
37 |
--------------------------------------------------------------------------------
/projectq/libs/revkit/_utils.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 |
16 | """Module containing some utility functions."""
17 |
18 | # flake8: noqa
19 | # pylint: skip-file
20 |
21 |
22 | def _exec(code, qs):
23 | """
24 | Execute the Python code in 'filename'.
25 |
26 | Args:
27 | code (string): ProjectQ code.
28 | qubits (tuple): Qubits to which the permutation is being applied.
29 | """
30 | from projectq.ops import All, C, X, Z
31 |
32 | exec(code)
33 |
--------------------------------------------------------------------------------
/examples/hws6.py:
--------------------------------------------------------------------------------
1 | # pylint: skip-file
2 |
3 | """Example of a 6-qubit phase function."""
4 |
5 | import revkit
6 |
7 | from projectq.cengines import MainEngine
8 | from projectq.libs.revkit import PermutationOracle, PhaseOracle
9 | from projectq.meta import Compute, Dagger, Uncompute
10 | from projectq.ops import All, H, Measure, X
11 |
12 |
13 | # phase function
14 | def f(a, b, c, d, e, f):
15 | """Phase function."""
16 | return (a and b) ^ (c and d) ^ (e and f)
17 |
18 |
19 | # permutation
20 | pi = [0, 2, 3, 5, 7, 1, 4, 6]
21 |
22 | eng = MainEngine()
23 | qubits = eng.allocate_qureg(6)
24 | x = qubits[::2] # qubits on odd lines
25 | y = qubits[1::2] # qubits on even lines
26 |
27 | # circuit
28 | with Compute(eng):
29 | All(H) | qubits
30 | All(X) | [x[0], x[1]]
31 | PermutationOracle(pi) | y
32 | PhaseOracle(f) | qubits
33 | Uncompute(eng)
34 |
35 | with Compute(eng):
36 | with Dagger(eng):
37 | PermutationOracle(pi, synth=revkit.dbs) | x
38 | PhaseOracle(f) | qubits
39 | Uncompute(eng)
40 |
41 | All(H) | qubits
42 |
43 | All(Measure) | qubits
44 |
45 | # measurement result
46 | print(f"Shift is {sum(int(q) << i for i, q in enumerate(qubits))}")
47 |
--------------------------------------------------------------------------------
/projectq/backends/_utils.py:
--------------------------------------------------------------------------------
1 | # Copyright 2022 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """Module containing some utility functions."""
16 |
17 |
18 | def _rearrange_result(input_result, length):
19 | """Turn ``input_result`` from an integer into a bit-string.
20 |
21 | Args:
22 | input_result (int): An integer representation of qubit states.
23 | length (int): The total number of bits (for padding, if needed).
24 |
25 | Returns:
26 | str: A bit-string representation of ``input_result``.
27 | """
28 | return f'{input_result:0{length}b}'[::-1]
29 |
--------------------------------------------------------------------------------
/projectq/backends/_sim/_cppkernels/intrin/kernels.hpp:
--------------------------------------------------------------------------------
1 | // Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include "cintrin.hpp"
22 | #include "alignedallocator.hpp"
23 |
24 | #define LOOP_COLLAPSE1 2
25 | #define LOOP_COLLAPSE2 3
26 | #define LOOP_COLLAPSE3 4
27 | #define LOOP_COLLAPSE4 5
28 | #define LOOP_COLLAPSE5 6
29 |
30 | #include "kernel1.hpp"
31 | #include "kernel2.hpp"
32 | #include "kernel3.hpp"
33 | #include "kernel4.hpp"
34 | #include "kernel5.hpp"
35 |
--------------------------------------------------------------------------------
/projectq/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """
15 | ProjectQ - An open source software framework for quantum computing.
16 |
17 | Get started:
18 | Simply import the main compiler engine (from projectq import MainEngine)
19 | and start coding!
20 |
21 | For examples, see the example folder, which features implementation of
22 | a quantum random number generator, entanglement demonstration (simulation
23 | or run on the IBM backend), Teleportation, Grover search, and
24 | Shor's algorithm for factoring.
25 | """
26 |
27 | from projectq.cengines import MainEngine
28 |
--------------------------------------------------------------------------------
/projectq/backends/_azure/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2022 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """ProjectQ module for supporting the Azure Quantum platform."""
16 |
17 | try:
18 | from ._azure_quantum import AzureQuantumBackend
19 | except ImportError: # pragma: no cover
20 |
21 | class AzureQuantumBackend:
22 | """Dummy class."""
23 |
24 | def __init__(self, *args, **kwargs):
25 | """Initialize dummy class."""
26 | raise ImportError(
27 | "Missing optional 'azure-quantum' dependencies. To install run: pip install projectq[azure-quantum]"
28 | )
29 |
--------------------------------------------------------------------------------
/projectq/meta/_logicalqubit_test.py:
--------------------------------------------------------------------------------
1 | # Copyright 2018 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """Tests for projectq.meta._logicalqubit.py."""
15 |
16 | from copy import deepcopy
17 |
18 | from projectq.meta import ComputeTag, _logicalqubit
19 |
20 |
21 | def test_logical_qubit_id_tag():
22 | tag0 = _logicalqubit.LogicalQubitIDTag(10)
23 | tag1 = _logicalqubit.LogicalQubitIDTag(1)
24 | tag2 = tag0
25 | tag3 = deepcopy(tag0)
26 | tag3.logical_qubit_id = 9
27 | other_tag = ComputeTag()
28 | assert tag0 == tag2
29 | assert tag0 != tag1
30 | assert not tag0 == tag3
31 | assert not tag0 == other_tag
32 |
--------------------------------------------------------------------------------
/projectq/ops/_qpegate.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """Definition of the quantum phase estimation gate."""
16 |
17 | from ._basics import BasicGate
18 |
19 |
20 | class QPE(BasicGate):
21 | """
22 | Quantum Phase Estimation gate.
23 |
24 | See setups.decompositions for the complete implementation
25 | """
26 |
27 | def __init__(self, unitary):
28 | """Initialize a QPE gate."""
29 | super().__init__()
30 | self.unitary = unitary
31 |
32 | def __str__(self):
33 | """Return a string representation of the object."""
34 | return f'QPE({str(self.unitary)})'
35 |
--------------------------------------------------------------------------------
/projectq/backends/_utils_test.py:
--------------------------------------------------------------------------------
1 | # Copyright 2022 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """Tests for projectq._utils.py."""
16 |
17 | import pytest
18 |
19 | from ._utils import _rearrange_result
20 |
21 |
22 | @pytest.mark.parametrize(
23 | "input_result, length, expected_result",
24 | [
25 | (5, 3, '101'),
26 | (5, 4, '1010'),
27 | (5, 5, '10100'),
28 | (16, 5, '00001'),
29 | (16, 6, '000010'),
30 | (63, 6, '111111'),
31 | (63, 7, '1111110'),
32 | ],
33 | )
34 | def test_rearrange_result(input_result, length, expected_result):
35 | assert expected_result == _rearrange_result(input_result, length)
36 |
--------------------------------------------------------------------------------
/projectq/ops/_state_prep_test.py:
--------------------------------------------------------------------------------
1 | # Copyright 2018 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """Tests for projectq.ops._state_prep."""
15 |
16 | from projectq.ops import X, _state_prep
17 |
18 |
19 | def test_equality_and_hash():
20 | gate1 = _state_prep.StatePreparation([0.5, -0.5, 0.5, -0.5])
21 | gate2 = _state_prep.StatePreparation([0.5, -0.5, 0.5, -0.5])
22 | gate3 = _state_prep.StatePreparation([0.5, -0.5, 0.5, 0.5])
23 | assert gate1 == gate2
24 | assert hash(gate1) == hash(gate2)
25 | assert gate1 != gate3
26 | assert gate1 != X
27 |
28 |
29 | def test_str():
30 | gate1 = _state_prep.StatePreparation([0, 1])
31 | assert str(gate1) == "StatePreparation"
32 |
--------------------------------------------------------------------------------
/projectq/backends/_sim/_cppkernels/nointrin/kernels.hpp:
--------------------------------------------------------------------------------
1 | // Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include "../intrin/alignedallocator.hpp"
22 |
23 | template
24 | inline T add(T a, T b){ return a+b; }
25 |
26 | template
27 | inline T mul(T a, T b){ return a*b; }
28 |
29 |
30 | #define LOOP_COLLAPSE1 2
31 | #define LOOP_COLLAPSE2 3
32 | #define LOOP_COLLAPSE3 4
33 | #define LOOP_COLLAPSE4 5
34 | #define LOOP_COLLAPSE5 6
35 |
36 | #include "kernel1.hpp"
37 | #include "kernel2.hpp"
38 | #include "kernel3.hpp"
39 | #include "kernel4.hpp"
40 | #include "kernel5.hpp"
41 |
--------------------------------------------------------------------------------
/projectq/cengines/_replacer/_decomposition_rule_test.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """Tests for projectq.cengines._replacer._decomposition_rule.py."""
15 |
16 | import pytest
17 |
18 | from projectq.ops import BasicRotationGate
19 |
20 | from . import DecompositionRule, ThisIsNotAGateClassError
21 |
22 |
23 | def test_decomposition_rule_wrong_input():
24 | class WrongInput(BasicRotationGate):
25 | pass
26 |
27 | with pytest.raises(ThisIsNotAGateClassError):
28 | _ = DecompositionRule(WrongInput.__class__, lambda cmd: None, lambda cmd: None)
29 |
30 | with pytest.raises(ThisIsNotAGateClassError):
31 | _ = DecompositionRule(WrongInput(0), lambda cmd: None, lambda cmd: None)
32 |
--------------------------------------------------------------------------------
/projectq/setups/decompositions/barrier.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """
15 | Registers a decomposition rule for barriers.
16 |
17 | Deletes all barriers if they are not supported.
18 | """
19 |
20 | from projectq.cengines import DecompositionRule
21 | from projectq.ops import BarrierGate
22 |
23 |
24 | def _decompose_barrier(cmd): # pylint: disable=unused-argument
25 | """Throw out all barriers if they are not supported."""
26 |
27 |
28 | def _recognize_barrier(cmd): # pylint: disable=unused-argument
29 | """Recognize all barriers."""
30 | return True
31 |
32 |
33 | #: Decomposition rules
34 | all_defined_decomposition_rules = [DecompositionRule(BarrierGate, _decompose_barrier, _recognize_barrier)]
35 |
--------------------------------------------------------------------------------
/projectq/meta/_logicalqubit.py:
--------------------------------------------------------------------------------
1 | # Copyright 2018 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """Definition of LogicalQubitIDTag to annotate a MeasureGate for mapped qubits."""
16 |
17 |
18 | class LogicalQubitIDTag: # pylint: disable=too-few-public-methods
19 | """
20 | LogicalQubitIDTag for a mapped qubit to annotate a MeasureGate.
21 |
22 | Attributes:
23 | logical_qubit_id (int): Logical qubit id
24 | """
25 |
26 | def __init__(self, logical_qubit_id):
27 | """Initialize a LogicalQubitIDTag object."""
28 | self.logical_qubit_id = logical_qubit_id
29 |
30 | def __eq__(self, other):
31 | """Equal operator."""
32 | return isinstance(other, LogicalQubitIDTag) and self.logical_qubit_id == other.logical_qubit_id
33 |
--------------------------------------------------------------------------------
/projectq/backends/_awsbraket/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2021 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """ProjectQ module for supporting the AWS Braket platform."""
16 |
17 | try:
18 | from ._awsbraket import AWSBraketBackend
19 | except ImportError: # pragma: no cover
20 |
21 | class AWSBraketBackend: # pylint: disable=too-few-public-methods
22 | """Dummy class."""
23 |
24 | def __init__(self, *args, **kwargs):
25 | """Initialize dummy class."""
26 | raise RuntimeError(
27 | "Failed to import one of the dependencies required to use "
28 | "the Amazon Braket Backend.\n"
29 | "Did you install ProjectQ using the [braket] extra? "
30 | "(python3 -m pip install projectq[braket])"
31 | )
32 |
--------------------------------------------------------------------------------
/projectq/setups/default.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """
16 | The default setup which provides an `engine_list` for the `MainEngine`.
17 |
18 | It contains `LocalOptimizers` and an `AutoReplacer` which uses most of the decompositions rules defined in
19 | projectq.setups.decompositions
20 | """
21 |
22 | import projectq
23 | import projectq.setups.decompositions
24 | from projectq.cengines import (
25 | AutoReplacer,
26 | DecompositionRuleSet,
27 | LocalOptimizer,
28 | TagRemover,
29 | )
30 |
31 |
32 | def get_engine_list():
33 | """Return the default list of compiler engine."""
34 | rule_set = DecompositionRuleSet(modules=[projectq.setups.decompositions])
35 | return [TagRemover(), LocalOptimizer(10), AutoReplacer(rule_set), TagRemover(), LocalOptimizer(10)]
36 |
--------------------------------------------------------------------------------
/projectq/setups/decompositions/globalphase.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """
15 | Registers a decomposition rule for global phases.
16 |
17 | Deletes global phase gates (which can be ignored).
18 | """
19 |
20 | from projectq.cengines import DecompositionRule
21 | from projectq.meta import get_control_count
22 | from projectq.ops import Ph
23 |
24 |
25 | def _decompose_PhNoCtrl(cmd): # pylint: disable=invalid-name,unused-argument
26 | """Throw out global phases (no controls)."""
27 |
28 |
29 | def _recognize_PhNoCtrl(cmd): # pylint: disable=invalid-name
30 | """Recognize global phases (no controls)."""
31 | return get_control_count(cmd) == 0
32 |
33 |
34 | #: Decomposition rules
35 | all_defined_decomposition_rules = [DecompositionRule(Ph, _decompose_PhNoCtrl, _recognize_PhNoCtrl)]
36 |
--------------------------------------------------------------------------------
/projectq/setups/decompositions/cnot2cz.py:
--------------------------------------------------------------------------------
1 | # Copyright 2018 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """Registers a decomposition to for a CNOT gate in terms of CZ and Hadamard."""
16 |
17 | from projectq.cengines import DecompositionRule
18 | from projectq.meta import Compute, Uncompute, get_control_count
19 | from projectq.ops import CZ, H, X
20 |
21 |
22 | def _decompose_cnot(cmd):
23 | """Decompose CNOT gates."""
24 | ctrl = cmd.control_qubits
25 | eng = cmd.engine
26 | with Compute(eng):
27 | H | cmd.qubits[0]
28 | CZ | (ctrl[0], cmd.qubits[0][0])
29 | Uncompute(eng)
30 |
31 |
32 | def _recognize_cnot(cmd):
33 | return get_control_count(cmd) == 1
34 |
35 |
36 | #: Decomposition rules
37 | all_defined_decomposition_rules = [DecompositionRule(X.__class__, _decompose_cnot, _recognize_cnot)]
38 |
--------------------------------------------------------------------------------
/projectq/setups/decompositions/entangle.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """
15 | Registers a decomposition for the Entangle gate.
16 |
17 | Applies a Hadamard gate to the first qubit and then, conditioned on this first
18 | qubit, CNOT gates to all others.
19 | """
20 |
21 | from projectq.cengines import DecompositionRule
22 | from projectq.meta import Control
23 | from projectq.ops import All, Entangle, H, X
24 |
25 |
26 | def _decompose_entangle(cmd):
27 | """Decompose the entangle gate."""
28 | qureg = cmd.qubits[0]
29 | eng = cmd.engine
30 |
31 | with Control(eng, cmd.control_qubits):
32 | H | qureg[0]
33 | with Control(eng, qureg[0]):
34 | All(X) | qureg[1:]
35 |
36 |
37 | #: Decomposition rules
38 | all_defined_decomposition_rules = [DecompositionRule(Entangle.__class__, _decompose_entangle)]
39 |
--------------------------------------------------------------------------------
/projectq/setups/decompositions/r2rzandph.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """
15 | Registers a decomposition rule for the phase-shift gate.
16 |
17 | Decomposes the (controlled) phase-shift gate using z-rotation and a global
18 | phase gate.
19 | """
20 |
21 | from projectq.cengines import DecompositionRule
22 | from projectq.meta import Control
23 | from projectq.ops import Ph, R, Rz
24 |
25 |
26 | def _decompose_R(cmd): # pylint: disable=invalid-name
27 | """Decompose the (controlled) phase-shift gate, denoted by R(phase)."""
28 | ctrl = cmd.control_qubits
29 | eng = cmd.engine
30 | gate = cmd.gate
31 |
32 | with Control(eng, ctrl):
33 | Ph(0.5 * gate.angle) | cmd.qubits
34 | Rz(gate.angle) | cmd.qubits
35 |
36 |
37 | #: Decomposition rules
38 | all_defined_decomposition_rules = [DecompositionRule(R, _decompose_R)]
39 |
--------------------------------------------------------------------------------
/projectq/meta/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """
15 | Provides meta instructions which help both the user and the compiler in writing/producing efficient code.
16 |
17 | It includes, e.g.,
18 |
19 | * Loop (with Loop(eng): ...)
20 | * Compute/Uncompute (with Compute(eng): ..., [...], Uncompute(eng))
21 | * Control (with Control(eng, ctrl_qubits): ...)
22 | * Dagger (with Dagger(eng): ...)
23 | """
24 |
25 | from ._compute import Compute, ComputeTag, CustomUncompute, Uncompute, UncomputeTag
26 | from ._control import (
27 | Control,
28 | canonical_ctrl_state,
29 | get_control_count,
30 | has_negative_control,
31 | )
32 | from ._dagger import Dagger
33 | from ._dirtyqubit import DirtyQubitTag
34 | from ._logicalqubit import LogicalQubitIDTag
35 | from ._loop import Loop, LoopTag
36 | from ._util import drop_engine_after, insert_engine
37 |
--------------------------------------------------------------------------------
/projectq/setups/decompositions/swap2cnot.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """
15 | Registers a decomposition to achieve a Swap gate.
16 |
17 | Decomposes a Swap gate using 3 CNOT gates, where the one in the middle
18 | features as many control qubits as the Swap gate has control qubits.
19 | """
20 |
21 | from projectq.cengines import DecompositionRule
22 | from projectq.meta import Compute, Control, Uncompute
23 | from projectq.ops import CNOT, Swap
24 |
25 |
26 | def _decompose_swap(cmd):
27 | """Decompose (controlled) swap gates."""
28 | ctrl = cmd.control_qubits
29 | eng = cmd.engine
30 | with Compute(eng):
31 | CNOT | (cmd.qubits[0], cmd.qubits[1])
32 | with Control(eng, ctrl):
33 | CNOT | (cmd.qubits[1], cmd.qubits[0])
34 | Uncompute(eng)
35 |
36 |
37 | #: Decomposition rules
38 | all_defined_decomposition_rules = [DecompositionRule(Swap.__class__, _decompose_swap)]
39 |
--------------------------------------------------------------------------------
/projectq/cengines/_withflushing_test.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """Tests for projectq.cengines.__init__.py."""
15 |
16 | from unittest.mock import MagicMock
17 |
18 | from projectq.cengines import DummyEngine, flushing
19 |
20 |
21 | def test_with_flushing():
22 | """Test with flushing() as eng:"""
23 | with flushing(DummyEngine()) as engine:
24 | engine.flush = MagicMock()
25 | assert engine.flush.call_count == 0
26 | assert engine.flush.call_count == 1
27 |
28 |
29 | def test_with_flushing_with_exception():
30 | """Test with flushing() as eng: with an exception raised in the 'with' block."""
31 | try:
32 | with flushing(DummyEngine()) as engine:
33 | engine.flush = MagicMock()
34 | assert engine.flush.call_count == 0
35 | raise ValueError("An exception is raised in the 'with' block")
36 | except ValueError:
37 | pass
38 | assert engine.flush.call_count == 1
39 |
--------------------------------------------------------------------------------
/projectq/setups/decompositions/rx2rz.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """Register a decomposition for the Rx gate into an Rz gate and Hadamard."""
16 |
17 | from projectq.cengines import DecompositionRule
18 | from projectq.meta import Compute, Control, Uncompute, get_control_count
19 | from projectq.ops import H, Rx, Rz
20 |
21 |
22 | def _decompose_rx(cmd):
23 | """Decompose the Rx gate."""
24 | qubit = cmd.qubits[0]
25 | eng = cmd.engine
26 | angle = cmd.gate.angle
27 |
28 | with Control(eng, cmd.control_qubits):
29 | with Compute(eng):
30 | H | qubit
31 | Rz(angle) | qubit
32 | Uncompute(eng)
33 |
34 |
35 | def _recognize_RxNoCtrl(cmd): # pylint: disable=invalid-name
36 | """For efficiency reasons only if no control qubits."""
37 | return get_control_count(cmd) == 0
38 |
39 |
40 | #: Decomposition rules
41 | all_defined_decomposition_rules = [DecompositionRule(Rx, _decompose_rx, _recognize_RxNoCtrl)]
42 |
--------------------------------------------------------------------------------
/projectq/setups/decompositions/ry2rz.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """Register a decomposition for the Ry gate into an Rz and Rx(pi/2) gate."""
16 |
17 | import math
18 |
19 | from projectq.cengines import DecompositionRule
20 | from projectq.meta import Compute, Control, Uncompute, get_control_count
21 | from projectq.ops import Rx, Ry, Rz
22 |
23 |
24 | def _decompose_ry(cmd):
25 | """Decompose the Ry gate."""
26 | qubit = cmd.qubits[0]
27 | eng = cmd.engine
28 | angle = cmd.gate.angle
29 |
30 | with Control(eng, cmd.control_qubits):
31 | with Compute(eng):
32 | Rx(math.pi / 2.0) | qubit
33 | Rz(angle) | qubit
34 | Uncompute(eng)
35 |
36 |
37 | def _recognize_RyNoCtrl(cmd): # pylint: disable=invalid-name
38 | """For efficiency reasons only if no control qubits."""
39 | return get_control_count(cmd) == 0
40 |
41 |
42 | #: Decomposition rules
43 | all_defined_decomposition_rules = [DecompositionRule(Ry, _decompose_ry, _recognize_RyNoCtrl)]
44 |
--------------------------------------------------------------------------------
/projectq/backends/_exceptions.py:
--------------------------------------------------------------------------------
1 | # Copyright 2021 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """Exception classes for projectq.backends."""
16 |
17 |
18 | class DeviceTooSmall(Exception):
19 | """Raised when a device does not have enough qubits for a desired job."""
20 |
21 |
22 | class DeviceOfflineError(Exception):
23 | """Raised when a device is required but is currently offline."""
24 |
25 |
26 | class DeviceNotHandledError(Exception):
27 | """Exception raised if a selected device cannot handle the circuit or is not supported by ProjectQ."""
28 |
29 |
30 | class RequestTimeoutError(Exception):
31 | """Raised if a request to the job creation API times out."""
32 |
33 |
34 | class JobSubmissionError(Exception):
35 | """Raised when the job creation API contains an error of some kind."""
36 |
37 |
38 | class InvalidCommandError(Exception):
39 | """Raised if the backend encounters an invalid command."""
40 |
41 |
42 | class MidCircuitMeasurementError(Exception):
43 | """Raised when a mid-circuit measurement is detected on a qubit."""
44 |
--------------------------------------------------------------------------------
/projectq/setups/decompositions/ph2r.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """
15 | Registers a decomposition for the controlled global phase gate.
16 |
17 | Turns the controlled global phase gate into a (controlled) phase-shift gate.
18 | Each time this rule is applied, one control can be shaved off.
19 | """
20 |
21 | from projectq.cengines import DecompositionRule
22 | from projectq.meta import Control, get_control_count
23 | from projectq.ops import Ph, R
24 |
25 |
26 | def _decompose_Ph(cmd): # pylint: disable=invalid-name
27 | """Decompose the controlled phase gate (C^nPh(phase))."""
28 | ctrl = cmd.control_qubits
29 | gate = cmd.gate
30 | eng = cmd.engine
31 |
32 | with Control(eng, ctrl[1:]):
33 | R(gate.angle) | ctrl[0]
34 |
35 |
36 | def _recognize_Ph(cmd): # pylint: disable=invalid-name
37 | """Recognize the controlled phase gate."""
38 | return get_control_count(cmd) >= 1
39 |
40 |
41 | #: Decomposition rules
42 | all_defined_decomposition_rules = [DecompositionRule(Ph, _decompose_Ph, _recognize_Ph)]
43 |
--------------------------------------------------------------------------------
/projectq/ops/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """ProjectQ module containing all basic gates (operations)."""
16 |
17 | from ._basics import (
18 | BasicGate,
19 | BasicMathGate,
20 | BasicPhaseGate,
21 | BasicRotationGate,
22 | ClassicalInstructionGate,
23 | FastForwardingGate,
24 | MatrixGate,
25 | NotInvertible,
26 | NotMergeable,
27 | SelfInverseGate,
28 | )
29 | from ._command import Command, CtrlAll, IncompatibleControlState, apply_command
30 | from ._gates import *
31 | from ._metagates import (
32 | All,
33 | C,
34 | ControlledGate,
35 | DaggeredGate,
36 | Tensor,
37 | get_inverse,
38 | is_identity,
39 | )
40 | from ._qaagate import QAA
41 | from ._qftgate import QFT, QFTGate
42 | from ._qpegate import QPE
43 | from ._qubit_operator import QubitOperator
44 | from ._shortcuts import *
45 | from ._state_prep import StatePreparation
46 | from ._time_evolution import TimeEvolution
47 | from ._uniformly_controlled_rotation import UniformlyControlledRy, UniformlyControlledRz
48 |
--------------------------------------------------------------------------------
/projectq/setups/decompositions/qft2crandhadamard.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """
15 | Registers a decomposition rule for the quantum Fourier transform.
16 |
17 | Decomposes the QFT gate into Hadamard and controlled phase-shift gates (R).
18 |
19 | Warning:
20 | The final Swaps are not included, as those are simply a re-indexing of
21 | quantum registers.
22 | """
23 |
24 | import math
25 |
26 | from projectq.cengines import DecompositionRule
27 | from projectq.meta import Control
28 | from projectq.ops import QFT, H, R
29 |
30 |
31 | def _decompose_QFT(cmd): # pylint: disable=invalid-name
32 | qb = cmd.qubits[0]
33 | eng = cmd.engine
34 | with Control(eng, cmd.control_qubits):
35 | for i in range(len(qb)):
36 | H | qb[-1 - i]
37 | for j in range(len(qb) - 1 - i):
38 | with Control(eng, qb[-1 - (j + i + 1)]):
39 | R(math.pi / (1 << (1 + j))) | qb[-1 - i]
40 |
41 |
42 | #: Decomposition rules
43 | all_defined_decomposition_rules = [DecompositionRule(QFT.__class__, _decompose_QFT)]
44 |
--------------------------------------------------------------------------------
/projectq/setups/decompositions/crz2cxandrz.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """
15 | Registers a decomposition for controlled z-rotation gates.
16 |
17 | It uses 2 z-rotations and 2 C^n NOT gates to achieve this gate.
18 | """
19 |
20 | from projectq.cengines import DecompositionRule
21 | from projectq.meta import get_control_count
22 | from projectq.ops import NOT, C, Rz
23 |
24 |
25 | def _decompose_CRz(cmd): # pylint: disable=invalid-name
26 | """Decompose the controlled Rz gate (into CNOT and Rz)."""
27 | qubit = cmd.qubits[0]
28 | ctrl = cmd.control_qubits
29 | gate = cmd.gate
30 | n_controls = get_control_count(cmd)
31 |
32 | Rz(0.5 * gate.angle) | qubit
33 | C(NOT, n_controls) | (ctrl, qubit)
34 | Rz(-0.5 * gate.angle) | qubit
35 | C(NOT, n_controls) | (ctrl, qubit)
36 |
37 |
38 | def _recognize_CRz(cmd): # pylint: disable=invalid-name
39 | """Recognize the controlled Rz gate."""
40 | return get_control_count(cmd) >= 1
41 |
42 |
43 | #: Decomposition rules
44 | all_defined_decomposition_rules = [DecompositionRule(Rz, _decompose_CRz, _recognize_CRz)]
45 |
--------------------------------------------------------------------------------
/projectq/setups/decompositions/sqrtswap2cnot.py:
--------------------------------------------------------------------------------
1 | # Copyright 2018 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """Register a decomposition to achieve a SqrtSwap gate."""
16 |
17 | from projectq.cengines import DecompositionRule
18 | from projectq.meta import Compute, Control, Uncompute
19 | from projectq.ops import CNOT, SqrtSwap, SqrtX
20 |
21 |
22 | def _decompose_sqrtswap(cmd):
23 | """Decompose (controlled) swap gates."""
24 | if len(cmd.qubits) != 2:
25 | raise ValueError('SqrtSwap gate requires two quantum registers')
26 | if not (len(cmd.qubits[0]) == 1 and len(cmd.qubits[1]) == 1):
27 | raise ValueError('SqrtSwap gate requires must act on only 2 qubits')
28 | ctrl = cmd.control_qubits
29 | qubit0 = cmd.qubits[0][0]
30 | qubit1 = cmd.qubits[1][0]
31 | eng = cmd.engine
32 |
33 | with Control(eng, ctrl):
34 | with Compute(eng):
35 | CNOT | (qubit0, qubit1)
36 | with Control(eng, qubit1):
37 | SqrtX | qubit0
38 | Uncompute(eng)
39 |
40 |
41 | #: Decomposition rules
42 | all_defined_decomposition_rules = [DecompositionRule(SqrtSwap.__class__, _decompose_sqrtswap)]
43 |
--------------------------------------------------------------------------------
/projectq/cengines/_manualmapper_test.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """Tests for projectq.cengines._manualmapper.py."""
15 |
16 | from projectq import MainEngine
17 | from projectq.cengines import DummyEngine, ManualMapper
18 | from projectq.meta import LogicalQubitIDTag
19 | from projectq.ops import All, H, Measure
20 |
21 |
22 | def test_manualmapper_mapping():
23 | backend = DummyEngine(save_commands=True)
24 |
25 | def mapping(qubit_id):
26 | return (qubit_id + 1) & 1
27 |
28 | eng = MainEngine(backend=backend, engine_list=[ManualMapper(mapping)])
29 | qb0 = eng.allocate_qubit()
30 | qb1 = eng.allocate_qubit()
31 | H | qb0
32 | H | qb1
33 | All(Measure) | (qb0 + qb1)
34 | eng.flush()
35 |
36 | num_measurements = 0
37 | for cmd in backend.received_commands:
38 | if cmd.gate == Measure:
39 | tag = LogicalQubitIDTag(mapping(cmd.qubits[0][0].id))
40 | assert tag in cmd.tags
41 | wrong_tag = LogicalQubitIDTag(cmd.qubits[0][0].id)
42 | assert wrong_tag not in cmd.tags
43 | num_measurements += 1
44 | assert num_measurements == 2
45 |
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | .. title:: Overview
2 |
3 | ProjectQ
4 | ========
5 |
6 | ProjectQ is an open-source software framework for quantum computing. It aims at providing tools which facilitate
7 | **inventing**, **implementing**, **testing**, **debugging**, and **running** quantum algorithms using either classical
8 | hardware or actual quantum devices.
9 |
10 | The **four core principles** of this open-source effort are
11 |
12 | #. **Open & Free**: *ProjectQ is released under the* **Apache 2** *license*
13 | #. **Simple learning curve**: *It is implemented in Python and has an intuitive syntax*
14 | #. **Easily extensible**: *Anyone can contribute to the compiler, the embedded domain-specific language, and libraries*
15 | #. **Code quality**: *Code reviews, continuous integration testing (unit and functional tests)*
16 |
17 |
18 | Please cite
19 | * Damian S. Steiger, Thomas Häner, and Matthias Troyer "ProjectQ: An Open Source Software Framework for Quantum
20 | Computing" `Quantum 2, 49 (2018) `__ (published on `arXiv
21 | `__ on 23 Dec 2016)
22 | * Thomas Häner, Damian S. Steiger, Krysta M. Svore, and Matthias Troyer "A Software Methodology for Compiling
23 | Quantum Programs" `Quantum Sci. Technol. 3 (2018) 020501 `__ (published
24 | on `arXiv `__ on 5 Apr 2016)
25 |
26 |
27 | Contents
28 | * :ref:`tutorial`: Tutorial containing instructions on how to get started with ProjectQ.
29 | * :ref:`examples`: Example implementations of few quantum algorithms
30 | * :ref:`code_doc`: The code documentation of ProjectQ.
31 |
32 |
33 | .. toctree::
34 | :maxdepth: 2
35 | :hidden:
36 |
37 | tutorials
38 | examples
39 | projectq
40 |
--------------------------------------------------------------------------------
/projectq/cengines/_cmdmodifier_test.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """Tests for projectq.cengines._cmdmodifier.py."""
15 |
16 | from projectq import MainEngine
17 | from projectq.cengines import DummyEngine, _cmdmodifier
18 | from projectq.ops import ClassicalInstructionGate, FastForwardingGate, H
19 |
20 |
21 | def test_command_modifier():
22 | def cmd_mod_fun(cmd):
23 | cmd.tags = "NewTag"
24 | return cmd
25 |
26 | backend = DummyEngine(save_commands=True)
27 | cmd_modifier = _cmdmodifier.CommandModifier(cmd_mod_fun)
28 | main_engine = MainEngine(backend=backend, engine_list=[cmd_modifier])
29 | qubit = main_engine.allocate_qubit()
30 | H | qubit
31 | # Test if H gate was sent through forwarder_eng and tag was added
32 | received_commands = []
33 | # Remove Allocate and Deallocate gates
34 | for cmd in backend.received_commands:
35 | if not (isinstance(cmd.gate, FastForwardingGate) or isinstance(cmd.gate, ClassicalInstructionGate)):
36 | received_commands.append(cmd)
37 | for cmd in received_commands:
38 | print(cmd)
39 | assert len(received_commands) == 1
40 | assert received_commands[0].gate == H
41 | assert received_commands[0].tags == "NewTag"
42 |
--------------------------------------------------------------------------------
/projectq/setups/decompositions/toffoli2cnotandtgate.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """
15 | Registers a decomposition rule for the Toffoli gate.
16 |
17 | Decomposes the Toffoli gate using Hadamard, T, Tdag, and CNOT gates.
18 | """
19 |
20 | from projectq.cengines import DecompositionRule
21 | from projectq.meta import get_control_count
22 | from projectq.ops import CNOT, NOT, H, T, Tdag
23 |
24 |
25 | def _decompose_toffoli(cmd):
26 | """Decompose the Toffoli gate into CNOT, H, T, and Tdagger gates."""
27 | ctrl = cmd.control_qubits
28 |
29 | target = cmd.qubits[0]
30 |
31 | H | target
32 | CNOT | (ctrl[0], target)
33 | T | ctrl[0]
34 | Tdag | target
35 | CNOT | (ctrl[1], target)
36 | CNOT | (ctrl[1], ctrl[0])
37 | Tdag | ctrl[0]
38 | T | target
39 | CNOT | (ctrl[1], ctrl[0])
40 | CNOT | (ctrl[0], target)
41 | Tdag | target
42 | CNOT | (ctrl[1], target)
43 | T | target
44 | T | ctrl[1]
45 | H | target
46 |
47 |
48 | def _recognize_toffoli(cmd):
49 | """Recognize the Toffoli gate."""
50 | return get_control_count(cmd) == 2
51 |
52 |
53 | #: Decomposition rules
54 | all_defined_decomposition_rules = [DecompositionRule(NOT.__class__, _decompose_toffoli, _recognize_toffoli)]
55 |
--------------------------------------------------------------------------------
/projectq/setups/decompositions/controlstate.py:
--------------------------------------------------------------------------------
1 | # Copyright 2021 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """
16 | Register a decomposition to replace turn negatively controlled qubits into positively controlled qubits.
17 |
18 | This achieved by applying X gates to selected qubits.
19 | """
20 |
21 | from copy import deepcopy
22 |
23 | from projectq.cengines import DecompositionRule
24 | from projectq.meta import Compute, Uncompute, has_negative_control
25 | from projectq.ops import BasicGate, X
26 |
27 |
28 | def _decompose_controlstate(cmd):
29 | """Decompose commands with control qubits in negative state (ie. control qubits with state '0' instead of '1')."""
30 | with Compute(cmd.engine):
31 | for state, ctrl in zip(cmd.control_state, cmd.control_qubits):
32 | if state == '0':
33 | X | ctrl
34 |
35 | # Resend the command with the `control_state` cleared
36 | cmd.ctrl_state = '1' * len(cmd.control_state)
37 | orig_engine = cmd.engine
38 | cmd.engine.receive([deepcopy(cmd)]) # NB: deepcopy required here to workaround infinite recursion detection
39 | Uncompute(orig_engine)
40 |
41 |
42 | #: Decomposition rules
43 | all_defined_decomposition_rules = [DecompositionRule(BasicGate, _decompose_controlstate, has_negative_control)]
44 |
--------------------------------------------------------------------------------
/projectq/backends/_sim/_simulator_test_fixtures.py:
--------------------------------------------------------------------------------
1 | # Copyright 2021 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import pytest
16 |
17 | from projectq.cengines import BasicMapperEngine
18 |
19 |
20 | @pytest.fixture(params=["mapper", "no_mapper"])
21 | def mapper(request):
22 | """Add a mapper which changes qubit ids by adding 1."""
23 | if request.param == "mapper":
24 |
25 | class TrivialMapper(BasicMapperEngine):
26 | def __init__(self):
27 | super().__init__()
28 | self.current_mapping = {}
29 |
30 | def receive(self, command_list):
31 | for cmd in command_list:
32 | for qureg in cmd.all_qubits:
33 | for qubit in qureg:
34 | if qubit.id == -1:
35 | continue
36 | elif qubit.id not in self.current_mapping:
37 | previous_map = self.current_mapping
38 | previous_map[qubit.id] = qubit.id + 1
39 | self.current_mapping = previous_map
40 | self._send_cmd_with_mapped_ids(cmd)
41 |
42 | return TrivialMapper()
43 | if request.param == "no_mapper":
44 | return None
45 |
--------------------------------------------------------------------------------
/projectq/backends/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """
15 | Contains back-ends for ProjectQ.
16 |
17 | This includes:
18 |
19 | * a debugging tool to print all received commands (CommandPrinter)
20 | * a circuit drawing engine (which can be used anywhere within the compilation
21 | chain)
22 | * a simulator with emulation capabilities
23 | * a resource counter (counts gates and keeps track of the maximal width of the
24 | circuit)
25 | * an interface to the IBM Quantum Experience chip (and simulator).
26 | * an interface to the AQT trapped ion system (and simulator).
27 | * an interface to the AWS Braket service decives (and simulators)
28 | * an interface to the Azure Quantum service devices (and simulators)
29 | * an interface to the IonQ trapped ionq hardware (and simulator).
30 | """
31 | from ._aqt import AQTBackend
32 | from ._awsbraket import AWSBraketBackend
33 | from ._azure import AzureQuantumBackend
34 | from ._circuits import CircuitDrawer, CircuitDrawerMatplotlib
35 | from ._exceptions import DeviceNotHandledError, DeviceOfflineError, DeviceTooSmall
36 | from ._ibm import IBMBackend
37 | from ._ionq import IonQBackend
38 | from ._printer import CommandPrinter
39 | from ._resource import ResourceCounter
40 | from ._sim import ClassicalSimulator, Simulator
41 | from ._unitary import UnitarySimulator
42 |
--------------------------------------------------------------------------------
/projectq/setups/decompositions/controlstate_test.py:
--------------------------------------------------------------------------------
1 | # Copyright 2021 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """
16 | Tests for the controlstate decomposition rule.
17 | """
18 |
19 | from projectq import MainEngine
20 | from projectq.cengines import (
21 | AutoReplacer,
22 | DecompositionRuleSet,
23 | DummyEngine,
24 | InstructionFilter,
25 | )
26 | from projectq.meta import Control, has_negative_control
27 | from projectq.ops import X
28 | from projectq.setups.decompositions import cnot2cz, controlstate
29 |
30 |
31 | def filter_func(eng, cmd):
32 | if has_negative_control(cmd):
33 | return False
34 | return True
35 |
36 |
37 | def test_controlstate_priority():
38 | saving_backend = DummyEngine(save_commands=True)
39 | rule_set = DecompositionRuleSet(modules=[cnot2cz, controlstate])
40 | eng = MainEngine(backend=saving_backend, engine_list=[AutoReplacer(rule_set), InstructionFilter(filter_func)])
41 | qubit1 = eng.allocate_qubit()
42 | qubit2 = eng.allocate_qubit()
43 | qubit3 = eng.allocate_qubit()
44 | with Control(eng, qubit2, ctrl_state='0'):
45 | X | qubit1
46 | with Control(eng, qubit3, ctrl_state='1'):
47 | X | qubit1
48 | eng.flush()
49 |
50 | assert len(saving_backend.received_commands) == 8
51 | for cmd in saving_backend.received_commands:
52 | assert not has_negative_control(cmd)
53 |
--------------------------------------------------------------------------------
/projectq/setups/decompositions/qubitop2onequbit.py:
--------------------------------------------------------------------------------
1 | # Copyright 2018 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """Register a decomposition rule for a unitary QubitOperator to one qubit gates."""
16 |
17 | import cmath
18 |
19 | from projectq.cengines import DecompositionRule
20 | from projectq.meta import Control, get_control_count
21 | from projectq.ops import Ph, QubitOperator, X, Y, Z
22 |
23 |
24 | def _recognize_qubitop(cmd):
25 | """For efficiency only use this if at most 1 control qubit."""
26 | return get_control_count(cmd) <= 1
27 |
28 |
29 | def _decompose_qubitop(cmd):
30 | if len(cmd.qubits) != 1:
31 | raise ValueError('QubitOperator decomposition can only accept a single quantum register')
32 | qureg = cmd.qubits[0]
33 | eng = cmd.engine
34 | qubit_op = cmd.gate
35 | with Control(eng, cmd.control_qubits):
36 | ((term, coefficient),) = qubit_op.terms.items()
37 | phase = cmath.phase(coefficient)
38 | Ph(phase) | qureg[0]
39 | for index, action in term:
40 | if action == "X":
41 | X | qureg[index]
42 | elif action == "Y":
43 | Y | qureg[index]
44 | elif action == "Z":
45 | Z | qureg[index]
46 |
47 |
48 | #: Decomposition rules
49 | all_defined_decomposition_rules = [DecompositionRule(QubitOperator, _decompose_qubitop, _recognize_qubitop)]
50 |
--------------------------------------------------------------------------------
/projectq/setups/ionq_test.py:
--------------------------------------------------------------------------------
1 | # Copyright 2021 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """Tests for projectq.setup.ionq."""
15 |
16 | import pytest
17 |
18 | from projectq.backends._exceptions import DeviceOfflineError
19 | from projectq.backends._ionq._ionq_http_client import IonQ
20 | from projectq.backends._ionq._ionq_mapper import BoundedQubitMapper
21 |
22 |
23 | def test_basic_ionq_mapper(monkeypatch):
24 | import projectq.setups.ionq
25 |
26 | def mock_show_devices(*args, **kwargs):
27 | return {'dummy': {'nq': 3, 'target': 'dummy'}}
28 |
29 | monkeypatch.setattr(
30 | IonQ,
31 | 'show_devices',
32 | mock_show_devices,
33 | )
34 | engine_list = projectq.setups.ionq.get_engine_list(device='dummy')
35 | assert len(engine_list) > 1
36 | mapper = engine_list[-1]
37 | assert isinstance(mapper, BoundedQubitMapper)
38 | # to match nq in the backend
39 | assert mapper.max_qubits == 3
40 |
41 |
42 | def test_ionq_errors(monkeypatch):
43 | import projectq.setups.ionq
44 |
45 | def mock_show_devices(*args, **kwargs):
46 | return {'dummy': {'nq': 3, 'target': 'dummy'}}
47 |
48 | monkeypatch.setattr(
49 | IonQ,
50 | 'show_devices',
51 | mock_show_devices,
52 | )
53 |
54 | with pytest.raises(DeviceOfflineError):
55 | projectq.setups.ionq.get_engine_list(token='TOKEN', device='simulator')
56 |
--------------------------------------------------------------------------------
/projectq/cengines/_tagremover_test.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """Tests for projectq.cengines._tagremover.py."""
15 |
16 | import pytest
17 |
18 | from projectq import MainEngine
19 | from projectq.cengines import DummyEngine, _tagremover
20 | from projectq.meta import ComputeTag, UncomputeTag
21 | from projectq.ops import Command, H
22 |
23 |
24 | def test_tagremover_default():
25 | tag_remover = _tagremover.TagRemover()
26 | assert tag_remover._tags == [ComputeTag, UncomputeTag]
27 |
28 |
29 | def test_tagremover_invalid():
30 | with pytest.raises(TypeError):
31 | _tagremover.TagRemover(ComputeTag)
32 |
33 |
34 | def test_tagremover():
35 | backend = DummyEngine(save_commands=True)
36 | tag_remover = _tagremover.TagRemover([str])
37 | eng = MainEngine(backend=backend, engine_list=[tag_remover])
38 | # Create a command_list and check if "NewTag" is removed
39 | qubit = eng.allocate_qubit()
40 | cmd0 = Command(eng, H, (qubit,))
41 | cmd0.tags = ["NewTag"]
42 | cmd1 = Command(eng, H, (qubit,))
43 | cmd1.tags = [1, 2, "NewTag", 3]
44 | cmd_list = [cmd0, cmd1, cmd0]
45 | assert len(backend.received_commands) == 1 # AllocateQubitGate
46 | tag_remover.receive(cmd_list)
47 | assert len(backend.received_commands) == 4
48 | assert backend.received_commands[1].tags == []
49 | assert backend.received_commands[2].tags == [1, 2, 3]
50 |
--------------------------------------------------------------------------------
/projectq/setups/decompositions/barrier_test.py:
--------------------------------------------------------------------------------
1 | # -*- codingf53: utf-8 -*-
2 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | """
16 | Tests for barrier.py
17 | """
18 |
19 | from projectq import MainEngine
20 | from projectq.cengines import DummyEngine
21 | from projectq.ops import Barrier, R
22 |
23 | from . import barrier
24 |
25 |
26 | def test_recognize_barrier():
27 | saving_backend = DummyEngine(save_commands=True)
28 | eng = MainEngine(backend=saving_backend)
29 | qubit = eng.allocate_qubit()
30 | R(0.2) | qubit
31 | Barrier | qubit
32 | eng.flush(deallocate_qubits=True)
33 | # Don't test initial allocate and trailing deallocate and flush gate.
34 | count = 0
35 | for cmd in saving_backend.received_commands[1:-2]:
36 | count += barrier._recognize_barrier(cmd)
37 | assert count == 2 # recognizes all gates
38 |
39 |
40 | def test_remove_barrier():
41 | saving_backend = DummyEngine(save_commands=True)
42 |
43 | def my_is_available(cmd):
44 | return not cmd.gate == Barrier
45 |
46 | saving_backend.is_available = my_is_available
47 | eng = MainEngine(backend=saving_backend)
48 | qubit = eng.allocate_qubit()
49 | R(0.2) | qubit
50 | Barrier | qubit
51 | eng.flush(deallocate_qubits=True)
52 | # Don't test initial allocate and trailing deallocate and flush gate.
53 | for cmd in saving_backend.received_commands[1:-2]:
54 | assert not cmd.gate == Barrier
55 | assert len(saving_backend.received_commands[1:-2]) == 1
56 |
--------------------------------------------------------------------------------
/projectq/backends/_sim/_cppkernels/nointrin/kernel1.hpp:
--------------------------------------------------------------------------------
1 | // Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | template
16 | inline void kernel_core(V &psi, std::size_t I, std::size_t d0, M const& m)
17 | {
18 | std::complex v[2];
19 | v[0] = psi[I];
20 | v[1] = psi[I + d0];
21 |
22 | psi[I] = (add(mul(v[0], m[0][0]), mul(v[1], m[0][1])));
23 | psi[I + d0] = (add(mul(v[0], m[1][0]), mul(v[1], m[1][1])));
24 |
25 | }
26 |
27 | // bit indices id[.] are given from high to low (e.g. control first for CNOT)
28 | template
29 | void kernel(V &psi, unsigned id0, M const& m, std::size_t ctrlmask)
30 | {
31 | std::size_t n = psi.size();
32 | std::size_t d0 = 1UL << id0;
33 | std::size_t dsorted[] = {d0 };
34 | std::sort(dsorted, dsorted + 1, std::greater());
35 |
36 | if (ctrlmask == 0){
37 | #pragma omp for collapse(LOOP_COLLAPSE1) schedule(static)
38 | for (std::size_t i0 = 0; i0 < n; i0 += 2 * dsorted[0]){
39 | for (std::size_t i1 = 0; i1 < dsorted[0]; ++i1){
40 | kernel_core(psi, i0 + i1, d0, m);
41 | }
42 | }
43 | }
44 | else{
45 | #pragma omp for collapse(LOOP_COLLAPSE1) schedule(static)
46 | for (std::size_t i0 = 0; i0 < n; i0 += 2 * dsorted[0]){
47 | for (std::size_t i1 = 0; i1 < dsorted[0]; ++i1){
48 | if (((i0 + i1)&ctrlmask) == ctrlmask)
49 | kernel_core(psi, i0 + i1, d0, m);
50 | }
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/projectq/ops/_state_prep.py:
--------------------------------------------------------------------------------
1 | # Copyright 2018 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """Definition of the state preparation gate."""
16 |
17 | from ._basics import BasicGate
18 |
19 |
20 | class StatePreparation(BasicGate):
21 | """Gate for transforming qubits in state |0> to any desired quantum state."""
22 |
23 | def __init__(self, final_state):
24 | """
25 | Initialize a StatePreparation gate.
26 |
27 | Example:
28 | .. code-block:: python
29 |
30 | qureg = eng.allocate_qureg(2)
31 | StatePreparation([0.5, -0.5j, -0.5, 0.5]) | qureg
32 |
33 | Note:
34 | final_state[k] is taken to be the amplitude of the computational basis state whose string is equal to the
35 | binary representation of k.
36 |
37 | Args:
38 | final_state(list[complex]): wavefunction of the desired quantum state. len(final_state) must be
39 | 2**len(qureg). Must be normalized!
40 | """
41 | super().__init__()
42 | self.final_state = list(final_state)
43 |
44 | def __str__(self):
45 | """Return a string representation of the object."""
46 | return "StatePreparation"
47 |
48 | def __eq__(self, other):
49 | """Equal operator."""
50 | if isinstance(other, self.__class__):
51 | return self.final_state == other.final_state
52 | return False
53 |
54 | def __hash__(self):
55 | """Compute the hash of the object."""
56 | return hash(f"StatePreparation({str(self.final_state)})")
57 |
--------------------------------------------------------------------------------
/projectq/setups/decompositions/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """ProjectQ's decomposition rules."""
16 |
17 | from . import (
18 | amplitudeamplification,
19 | arb1qubit2rzandry,
20 | barrier,
21 | carb1qubit2cnotrzandry,
22 | cnot2cz,
23 | cnot2rxx,
24 | cnu2toffoliandcu,
25 | controlstate,
26 | crz2cxandrz,
27 | entangle,
28 | globalphase,
29 | h2rx,
30 | ph2r,
31 | phaseestimation,
32 | qft2crandhadamard,
33 | qubitop2onequbit,
34 | r2rzandph,
35 | rx2rz,
36 | ry2rz,
37 | rz2rx,
38 | sqrtswap2cnot,
39 | stateprep2cnot,
40 | swap2cnot,
41 | time_evolution,
42 | toffoli2cnotandtgate,
43 | uniformlycontrolledr2cnot,
44 | )
45 |
46 | all_defined_decomposition_rules = [
47 | rule
48 | for module in [
49 | arb1qubit2rzandry,
50 | barrier,
51 | carb1qubit2cnotrzandry,
52 | crz2cxandrz,
53 | cnot2rxx,
54 | cnot2cz,
55 | cnu2toffoliandcu,
56 | controlstate,
57 | entangle,
58 | globalphase,
59 | h2rx,
60 | ph2r,
61 | qubitop2onequbit,
62 | qft2crandhadamard,
63 | r2rzandph,
64 | rx2rz,
65 | ry2rz,
66 | rz2rx,
67 | sqrtswap2cnot,
68 | stateprep2cnot,
69 | swap2cnot,
70 | toffoli2cnotandtgate,
71 | time_evolution,
72 | uniformlycontrolledr2cnot,
73 | phaseestimation,
74 | amplitudeamplification,
75 | ]
76 | for rule in module.all_defined_decomposition_rules
77 | ]
78 |
--------------------------------------------------------------------------------
/projectq/meta/_util_test.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import pytest
16 |
17 | from projectq import MainEngine
18 | from projectq.cengines import DummyEngine
19 |
20 | from . import _util
21 |
22 |
23 | def test_insert_then_drop():
24 | d1 = DummyEngine()
25 | d2 = DummyEngine()
26 | d3 = DummyEngine()
27 | eng = MainEngine(backend=d3, engine_list=[d1])
28 |
29 | assert d1.next_engine is d3
30 | assert d2.next_engine is None
31 | assert d3.next_engine is None
32 | assert d1.main_engine is eng
33 | assert d2.main_engine is None
34 | assert d3.main_engine is eng
35 | assert eng.n_engines == 2
36 |
37 | _util.insert_engine(d1, d2)
38 | assert d1.next_engine is d2
39 | assert d2.next_engine is d3
40 | assert d3.next_engine is None
41 | assert d1.main_engine is eng
42 | assert d2.main_engine is eng
43 | assert d3.main_engine is eng
44 | assert eng.n_engines == 3
45 |
46 | _util.drop_engine_after(d1)
47 | assert d1.next_engine is d3
48 | assert d2.next_engine is None
49 | assert d3.next_engine is None
50 | assert d1.main_engine is eng
51 | assert d2.main_engine is None
52 | assert d3.main_engine is eng
53 | assert eng.n_engines == 2
54 |
55 |
56 | def test_too_many_engines():
57 | N = 10
58 |
59 | eng = MainEngine(backend=DummyEngine(), engine_list=[])
60 | eng.n_engines_max = N
61 |
62 | for _ in range(N - 1):
63 | _util.insert_engine(eng, DummyEngine())
64 |
65 | with pytest.raises(RuntimeError):
66 | _util.insert_engine(eng, DummyEngine())
67 |
--------------------------------------------------------------------------------
/projectq/cengines/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """ProjectQ module containing all compiler engines."""
16 |
17 | from contextlib import contextmanager
18 |
19 | from ._basics import BasicEngine, ForwarderEngine, LastEngineException # isort:skip
20 | from ._cmdmodifier import CommandModifier # isort:skip
21 | from ._basicmapper import BasicMapperEngine # isort:skip
22 |
23 | # isort: split
24 |
25 | from ._ibm5qubitmapper import IBM5QubitMapper
26 | from ._linearmapper import LinearMapper, return_swap_depth
27 | from ._main import MainEngine, NotYetMeasuredError, UnsupportedEngineError
28 | from ._manualmapper import ManualMapper
29 | from ._optimize import LocalOptimizer
30 | from ._replacer import (
31 | AutoReplacer,
32 | DecompositionRule,
33 | DecompositionRuleSet,
34 | InstructionFilter,
35 | )
36 | from ._swapandcnotflipper import SwapAndCNOTFlipper
37 | from ._tagremover import TagRemover
38 | from ._testengine import CompareEngine, DummyEngine
39 | from ._twodmapper import GridMapper
40 |
41 |
42 | @contextmanager
43 | def flushing(engine):
44 | """
45 | Context manager to flush the given engine at the end of the 'with' context block.
46 |
47 | Example:
48 | with flushing(MainEngine()) as eng:
49 | qubit = eng.allocate_qubit()
50 | ...
51 |
52 | Calling 'eng.flush()' is no longer needed because the engine will be flushed at the
53 | end of the 'with' block even if an exception has been raised within that block.
54 | """
55 | try:
56 | yield engine
57 | finally:
58 | engine.flush()
59 |
--------------------------------------------------------------------------------
/projectq/setups/decompositions/h2rx.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | #
15 | # Module uses ideas from "Basic circuit compilation techniques for an
16 | # ion-trap quantum machine" by Dmitri Maslov (2017) at
17 | # https://iopscience.iop.org/article/10.1088/1367-2630/aa5e47
18 |
19 | """Register a decomposition for the H gate into an Ry and Rx gate."""
20 |
21 | import math
22 |
23 | from projectq.cengines import DecompositionRule
24 | from projectq.meta import get_control_count
25 | from projectq.ops import H, Ph, Rx, Ry
26 |
27 |
28 | def _decompose_h2rx_M(cmd): # pylint: disable=invalid-name
29 | """Decompose the Ry gate."""
30 | # Labelled 'M' for 'minus' because decomposition ends with a Ry(-pi/2)
31 | qubit = cmd.qubits[0]
32 | Rx(math.pi) | qubit
33 | Ph(math.pi / 2) | qubit
34 | Ry(-1 * math.pi / 2) | qubit
35 |
36 |
37 | def _decompose_h2rx_N(cmd): # pylint: disable=invalid-name
38 | """Decompose the Ry gate."""
39 | # Labelled 'N' for 'neutral' because decomposition doesn't end with
40 | # Ry(pi/2) or Ry(-pi/2)
41 | qubit = cmd.qubits[0]
42 | Ry(math.pi / 2) | qubit
43 | Ph(3 * math.pi / 2) | qubit
44 | Rx(-1 * math.pi) | qubit
45 |
46 |
47 | def _recognize_HNoCtrl(cmd): # pylint: disable=invalid-name
48 | """For efficiency reasons only if no control qubits."""
49 | return get_control_count(cmd) == 0
50 |
51 |
52 | #: Decomposition rules
53 | all_defined_decomposition_rules = [
54 | DecompositionRule(H.__class__, _decompose_h2rx_N, _recognize_HNoCtrl),
55 | DecompositionRule(H.__class__, _decompose_h2rx_M, _recognize_HNoCtrl),
56 | ]
57 |
--------------------------------------------------------------------------------
/projectq/meta/_util.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """Tools to add/remove compiler engines to the MainEngine list."""
16 |
17 |
18 | def insert_engine(prev_engine, engine_to_insert):
19 | """
20 | Insert an engine into the singly-linked list of engines.
21 |
22 | It also sets the correct main_engine for engine_to_insert.
23 |
24 | Args:
25 | prev_engine (projectq.cengines.BasicEngine): The engine just before the insertion point.
26 | engine_to_insert (projectq.cengines.BasicEngine): The engine to insert at the insertion point.
27 | """
28 | if prev_engine.main_engine is not None:
29 | prev_engine.main_engine.n_engines += 1
30 |
31 | if prev_engine.main_engine.n_engines > prev_engine.main_engine.n_engines_max:
32 | raise RuntimeError('Too many compiler engines added to the MainEngine!')
33 |
34 | engine_to_insert.main_engine = prev_engine.main_engine
35 | engine_to_insert.next_engine = prev_engine.next_engine
36 | prev_engine.next_engine = engine_to_insert
37 |
38 |
39 | def drop_engine_after(prev_engine):
40 | """
41 | Remove an engine from the singly-linked list of engines.
42 |
43 | Args:
44 | prev_engine (projectq.cengines.BasicEngine): The engine just before the engine to drop.
45 |
46 | Returns:
47 | Engine: The dropped engine.
48 | """
49 | dropped_engine = prev_engine.next_engine
50 | prev_engine.next_engine = dropped_engine.next_engine
51 | if prev_engine.main_engine is not None:
52 | prev_engine.main_engine.n_engines -= 1
53 | dropped_engine.next_engine = None
54 | dropped_engine.main_engine = None
55 | return dropped_engine
56 |
--------------------------------------------------------------------------------
/projectq/setups/ionq.py:
--------------------------------------------------------------------------------
1 | # Copyright 2021 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """
16 | A setup for IonQ trapped ion devices.
17 |
18 | Defines a setup allowing to compile code for IonQ trapped ion devices:
19 | ->The 11 qubit device
20 | ->The 29 qubits simulator
21 | """
22 | from projectq.backends._exceptions import DeviceOfflineError
23 | from projectq.backends._ionq._ionq_http_client import IonQ
24 | from projectq.backends._ionq._ionq_mapper import BoundedQubitMapper
25 | from projectq.ops import (
26 | Barrier,
27 | H,
28 | Rx,
29 | Rxx,
30 | Ry,
31 | Ryy,
32 | Rz,
33 | Rzz,
34 | S,
35 | Sdag,
36 | SqrtX,
37 | Swap,
38 | T,
39 | Tdag,
40 | X,
41 | Y,
42 | Z,
43 | )
44 | from projectq.setups import restrictedgateset
45 |
46 |
47 | def get_engine_list(token=None, device=None):
48 | """Return the default list of compiler engine for the IonQ platform."""
49 | service = IonQ()
50 | if token is not None:
51 | service.authenticate(token=token)
52 | devices = service.show_devices()
53 | if not device or device not in devices:
54 | raise DeviceOfflineError(f"Error checking engine list: no '{device}' devices available")
55 |
56 | #
57 | # Qubit mapper
58 | #
59 | mapper = BoundedQubitMapper(devices[device]['nq'])
60 |
61 | #
62 | # Basis Gates
63 | #
64 |
65 | # Declare the basis gateset for the IonQ's API.
66 | engine_list = restrictedgateset.get_engine_list(
67 | one_qubit_gates=(X, Y, Z, Rx, Ry, Rz, H, S, Sdag, T, Tdag, SqrtX),
68 | two_qubit_gates=(Swap, Rxx, Ryy, Rzz),
69 | other_gates=(Barrier,),
70 | )
71 | return engine_list + [mapper]
72 |
73 |
74 | __all__ = ['get_engine_list']
75 |
--------------------------------------------------------------------------------
/projectq/cengines/_manualmapper.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """A compiler engine to add mapping information."""
16 |
17 | from ._basicmapper import BasicMapperEngine
18 |
19 |
20 | class ManualMapper(BasicMapperEngine):
21 | """
22 | Manual Mapper which adds QubitPlacementTags to Allocate gate commands according to a user-specified mapping.
23 |
24 | Attributes:
25 | map (function): The function which maps a given qubit id to its location. It gets set when initializing the
26 | mapper.
27 | """
28 |
29 | def __init__(self, map_fun=lambda x: x):
30 | """
31 | Initialize the mapper to a given mapping.
32 |
33 | If no mapping function is provided, the qubit id is used as the location.
34 |
35 | Args:
36 | map_fun (function): Function which, given the qubit id, returns an integer describing the physical
37 | location (must be constant).
38 | """
39 | super().__init__()
40 | self.map = map_fun
41 | self.current_mapping = {}
42 |
43 | def receive(self, command_list):
44 | """
45 | Receives a command list and passes it to the next engine, adding qubit placement tags to allocate gates.
46 |
47 | Args:
48 | command_list (list of Command objects): list of commands to receive.
49 | """
50 | for cmd in command_list:
51 | ids = [qb.id for qr in cmd.qubits for qb in qr]
52 | ids += [qb.id for qb in cmd.control_qubits]
53 | for qubit_id in ids:
54 | if qubit_id not in self.current_mapping:
55 | self._current_mapping[qubit_id] = self.map(qubit_id)
56 | self._send_cmd_with_mapped_ids(cmd)
57 |
--------------------------------------------------------------------------------
/examples/aqt.py:
--------------------------------------------------------------------------------
1 | # pylint: skip-file
2 |
3 | """Example of running a quantum circuit using the AQT APIs."""
4 |
5 | import getpass
6 |
7 | import matplotlib.pyplot as plt
8 |
9 | import projectq.setups.aqt
10 | from projectq import MainEngine
11 | from projectq.backends import AQTBackend
12 | from projectq.libs.hist import histogram
13 | from projectq.ops import All, Entangle, Measure
14 |
15 |
16 | def run_entangle(eng, num_qubits=3):
17 | """
18 | Run an entangling operation on the provided compiler engine.
19 |
20 | Args:
21 | eng (MainEngine): Main compiler engine to use.
22 | num_qubits (int): Number of qubits to entangle.
23 |
24 | Returns:
25 | measurement (list): List of measurement outcomes.
26 | """
27 | # allocate the quantum register to entangle
28 | qureg = eng.allocate_qureg(num_qubits)
29 |
30 | # entangle the qureg
31 | Entangle | qureg
32 |
33 | # measure; should be all-0 or all-1
34 | All(Measure) | qureg
35 |
36 | # run the circuit
37 | eng.flush()
38 |
39 | # access the probabilities via the back-end:
40 | # results = eng.backend.get_probabilities(qureg)
41 | # for state in results:
42 | # print(f"Measured {state} with p = {results[state]}.")
43 | # or plot them directly:
44 | histogram(eng.backend, qureg)
45 | plt.show()
46 |
47 | # return one (random) measurement outcome.
48 | return [int(q) for q in qureg]
49 |
50 |
51 | if __name__ == "__main__":
52 | # devices available to subscription:
53 | # aqt_simulator (11 qubits)
54 | # aqt_simulator_noise (11 qubits)
55 | # aqt_device (4 qubits)
56 | #
57 | # To get a subscription, create a profile at :
58 | # https://gateway-portal.aqt.eu/
59 | #
60 | device = None # replace by the AQT device name you want to use
61 | token = None # replace by the token given by AQT
62 | if token is None:
63 | token = getpass.getpass(prompt='AQT token > ')
64 | if device is None:
65 | device = getpass.getpass(prompt='AQT device > ')
66 | # create main compiler engine for the AQT back-end
67 | eng = MainEngine(
68 | AQTBackend(use_hardware=True, token=token, num_runs=200, verbose=False, device=device),
69 | engine_list=projectq.setups.aqt.get_engine_list(token=token, device=device),
70 | )
71 | # run the circuit and print the result
72 | print(run_entangle(eng))
73 |
--------------------------------------------------------------------------------
/projectq/backends/_sim/_cppkernels/intrin/kernel1.hpp:
--------------------------------------------------------------------------------
1 | // Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | template
16 | inline void kernel_core(V &psi, std::size_t I, std::size_t d0, M const& m, M const& mt)
17 | {
18 | __m256d v[2];
19 |
20 | v[0] = load2(&psi[I]);
21 | v[1] = load2(&psi[I + d0]);
22 |
23 | _mm256_storeu2_m128d((double*)&psi[I + d0], (double*)&psi[I], add(mul(v[0], m[0], mt[0]), mul(v[1], m[1], mt[1])));
24 |
25 | }
26 |
27 | // bit indices id[.] are given from high to low (e.g. control first for CNOT)
28 | template
29 | void kernel(V &psi, unsigned id0, M const& m, std::size_t ctrlmask)
30 | {
31 | std::size_t n = psi.size();
32 | std::size_t d0 = 1UL << id0;
33 |
34 | __m256d mm[] = {load(&m[0][0], &m[1][0]), load(&m[0][1], &m[1][1])};
35 | __m256d mmt[2];
36 |
37 | __m256d neg = _mm256_setr_pd(1.0, -1.0, 1.0, -1.0);
38 | for (unsigned i = 0; i < 2; ++i){
39 | auto badc = _mm256_permute_pd(mm[i], 5);
40 | mmt[i] = _mm256_mul_pd(badc, neg);
41 | }
42 |
43 | std::size_t dsorted[] = {d0};
44 |
45 | if (ctrlmask == 0){
46 | #pragma omp for collapse(LOOP_COLLAPSE1) schedule(static)
47 | for (std::size_t i0 = 0; i0 < n; i0 += 2 * dsorted[0]){
48 | for (std::size_t i1 = 0; i1 < dsorted[0]; ++i1){
49 | kernel_core(psi, i0 + i1, d0, mm, mmt);
50 | }
51 | }
52 | }
53 | else{
54 | #pragma omp for collapse(LOOP_COLLAPSE1) schedule(static)
55 | for (std::size_t i0 = 0; i0 < n; i0 += 2 * dsorted[0]){
56 | for (std::size_t i1 = 0; i1 < dsorted[0]; ++i1){
57 | if (((i0 + i1)&ctrlmask) == ctrlmask)
58 | kernel_core(psi, i0 + i1, d0, mm, mmt);
59 | }
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/projectq/setups/aqt_test.py:
--------------------------------------------------------------------------------
1 | # Copyright 2020 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """Tests for projectq.setup.aqt."""
15 |
16 | import pytest
17 |
18 |
19 | def test_aqt_mapper_in_cengines(monkeypatch):
20 | import projectq.setups.aqt
21 |
22 | def mock_show_devices(*args, **kwargs):
23 | connections = {
24 | (0, 1),
25 | (1, 0),
26 | (1, 2),
27 | (1, 3),
28 | (1, 4),
29 | (2, 1),
30 | (2, 3),
31 | (2, 4),
32 | (3, 1),
33 | (3, 4),
34 | (4, 3),
35 | }
36 | return {'aqt_simulator': {'coupling_map': connections, 'version': '0.0.0', 'nq': 32}}
37 |
38 | monkeypatch.setattr(projectq.setups.aqt, "show_devices", mock_show_devices)
39 | engines_simulator = projectq.setups.aqt.get_engine_list(device='aqt_simulator')
40 | assert len(engines_simulator) == 13
41 |
42 |
43 | def test_aqt_errors(monkeypatch):
44 | import projectq.setups.aqt
45 |
46 | def mock_show_devices(*args, **kwargs):
47 | connections = {
48 | (0, 1),
49 | (1, 0),
50 | (1, 2),
51 | (1, 3),
52 | (1, 4),
53 | (2, 1),
54 | (2, 3),
55 | (2, 4),
56 | (3, 1),
57 | (3, 4),
58 | (4, 3),
59 | }
60 | return {'aqt_imaginary': {'coupling_map': connections, 'version': '0.0.0', 'nq': 6}}
61 |
62 | monkeypatch.setattr(projectq.setups.aqt, "show_devices", mock_show_devices)
63 | with pytest.raises(projectq.setups.aqt.DeviceOfflineError):
64 | projectq.setups.aqt.get_engine_list(device='simulator')
65 | with pytest.raises(projectq.setups.aqt.DeviceNotHandledError):
66 | projectq.setups.aqt.get_engine_list(device='aqt_imaginary')
67 |
--------------------------------------------------------------------------------
/projectq/cengines/_cmdmodifier.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """
15 | A CommandModifier engine that can be used to apply a user-defined transformation to all incoming commands.
16 |
17 | A CommandModifier engine can be used to, e.g., modify the tags of all commands which pass by (see the
18 | AutoReplacer for an example).
19 | """
20 |
21 | from ._basics import BasicEngine
22 |
23 |
24 | class CommandModifier(BasicEngine):
25 | """
26 | Compiler engine applying a user-defined transformation to all incoming commands.
27 |
28 | CommandModifier is a compiler engine which applies a function to all incoming commands, sending on the resulting
29 | command instead of the original one.
30 | """
31 |
32 | def __init__(self, cmd_mod_fun):
33 | """
34 | Initialize the CommandModifier.
35 |
36 | Args:
37 | cmd_mod_fun (function): Function which, given a command cmd, returns the command it should send instead.
38 |
39 | Example:
40 | .. code-block:: python
41 |
42 | def cmd_mod_fun(cmd):
43 | cmd.tags += [MyOwnTag()]
44 |
45 |
46 | compiler_engine = CommandModifier(cmd_mod_fun)
47 | ...
48 | """
49 | super().__init__()
50 | self._cmd_mod_fun = cmd_mod_fun
51 |
52 | def receive(self, command_list):
53 | """
54 | Receive a list of commands.
55 |
56 | Receive a list of commands from the previous engine, modify all commands, and send them on to the next engine.
57 |
58 | Args:
59 | command_list (list): List of commands to receive and then (after modification) send on.
60 | """
61 | new_command_list = [self._cmd_mod_fun(cmd) for cmd in command_list]
62 | self.send(new_command_list)
63 |
--------------------------------------------------------------------------------
/examples/ibm.py:
--------------------------------------------------------------------------------
1 | # pylint: skip-file
2 |
3 | """Example of running a quantum circuit using the IBM QE APIs."""
4 |
5 | import getpass
6 |
7 | import matplotlib.pyplot as plt
8 |
9 | import projectq.setups.ibm
10 | from projectq import MainEngine
11 | from projectq.backends import IBMBackend
12 | from projectq.libs.hist import histogram
13 | from projectq.ops import All, Entangle, Measure
14 |
15 |
16 | def run_entangle(eng, num_qubits=3):
17 | """
18 | Run an entangling operation on the provided compiler engine.
19 |
20 | Args:
21 | eng (MainEngine): Main compiler engine to use.
22 | num_qubits (int): Number of qubits to entangle.
23 |
24 | Returns:
25 | measurement (list): List of measurement outcomes.
26 | """
27 | # allocate the quantum register to entangle
28 | qureg = eng.allocate_qureg(num_qubits)
29 |
30 | # entangle the qureg
31 | Entangle | qureg
32 |
33 | # measure; should be all-0 or all-1
34 | All(Measure) | qureg
35 |
36 | # run the circuit
37 | eng.flush()
38 |
39 | # access the probabilities via the back-end:
40 | # results = eng.backend.get_probabilities(qureg)
41 | # for state in results:
42 | # print(f"Measured {state} with p = {results[state]}.")
43 | # or plot them directly:
44 | histogram(eng.backend, qureg)
45 | plt.show()
46 |
47 | # return one (random) measurement outcome.
48 | return [int(q) for q in qureg]
49 |
50 |
51 | if __name__ == "__main__":
52 | # devices commonly available :
53 | # ibmq_16_melbourne (15 qubit)
54 | # ibmq_essex (5 qubit)
55 | # ibmq_qasm_simulator (32 qubits)
56 | # and plenty of other 5 qubits devices!
57 | #
58 | # To get a token, create a profile at:
59 | # https://quantum-computing.ibm.com/
60 | #
61 | device = None # replace by the IBM device name you want to use
62 | token = None # replace by the token given by IBMQ
63 | if token is None:
64 | token = getpass.getpass(prompt='IBM Q token > ')
65 | if device is None:
66 | device = getpass.getpass(prompt='IBM device > ')
67 | # create main compiler engine for the IBM back-end
68 | eng = MainEngine(
69 | IBMBackend(use_hardware=True, token=token, num_runs=1024, verbose=False, device=device),
70 | engine_list=projectq.setups.ibm.get_engine_list(token=token, device=device),
71 | )
72 | # run the circuit and print the result
73 | print(run_entangle(eng))
74 |
--------------------------------------------------------------------------------
/projectq/setups/decompositions/cnot2rxx.py:
--------------------------------------------------------------------------------
1 | # Copyright 2018 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | #
15 | # Module uses ideas from "Basic circuit compilation techniques
16 | # for an ion-trap quantum machine" by Dmitri Maslov (2017) at
17 | # https://iopscience.iop.org/article/10.1088/1367-2630/aa5e47
18 |
19 | """Register a decomposition to for a CNOT gate in terms of Rxx, Rx and Ry gates."""
20 |
21 | import math
22 |
23 | from projectq.cengines import DecompositionRule
24 | from projectq.meta import get_control_count
25 | from projectq.ops import Ph, Rx, Rxx, Ry, X
26 |
27 |
28 | def _decompose_cnot2rxx_M(cmd): # pylint: disable=invalid-name
29 | """Decompose CNOT gate into Rxx gate."""
30 | # Labelled 'M' for 'minus' because decomposition ends with a Ry(-pi/2)
31 | ctrl = cmd.control_qubits
32 | Ry(math.pi / 2) | ctrl[0]
33 | Ph(7 * math.pi / 4) | ctrl[0]
34 | Rx(-math.pi / 2) | ctrl[0]
35 | Rx(-math.pi / 2) | cmd.qubits[0][0]
36 | Rxx(math.pi / 2) | (ctrl[0], cmd.qubits[0][0])
37 | Ry(-1 * math.pi / 2) | ctrl[0]
38 |
39 |
40 | def _decompose_cnot2rxx_P(cmd): # pylint: disable=invalid-name
41 | """Decompose CNOT gate into Rxx gate."""
42 | # Labelled 'P' for 'plus' because decomposition ends with a Ry(+pi/2)
43 | ctrl = cmd.control_qubits
44 | Ry(-math.pi / 2) | ctrl[0]
45 | Ph(math.pi / 4) | ctrl[0]
46 | Rx(-math.pi / 2) | ctrl[0]
47 | Rx(math.pi / 2) | cmd.qubits[0][0]
48 | Rxx(math.pi / 2) | (ctrl[0], cmd.qubits[0][0])
49 | Ry(math.pi / 2) | ctrl[0]
50 |
51 |
52 | def _recognize_cnot2(cmd):
53 | """Identify that the command is a CNOT gate (control - X gate)."""
54 | return get_control_count(cmd) == 1
55 |
56 |
57 | #: Decomposition rules
58 | all_defined_decomposition_rules = [
59 | DecompositionRule(X.__class__, _decompose_cnot2rxx_M, _recognize_cnot2),
60 | DecompositionRule(X.__class__, _decompose_cnot2rxx_P, _recognize_cnot2),
61 | ]
62 |
--------------------------------------------------------------------------------
/projectq/libs/revkit/_phase_test.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """Tests for libs.revkit._phase."""
15 |
16 | import numpy as np
17 | import pytest
18 |
19 | from projectq import MainEngine
20 | from projectq.backends import Simulator
21 | from projectq.cengines import DummyEngine
22 | from projectq.libs.revkit import PhaseOracle
23 | from projectq.ops import All, H, Measure
24 |
25 | # run this test only if RevKit Python module can be loaded
26 | revkit = pytest.importorskip('revkit')
27 |
28 |
29 | def test_phase_majority():
30 | sim = Simulator()
31 | main_engine = MainEngine(sim)
32 |
33 | qureg = main_engine.allocate_qureg(3)
34 | All(H) | qureg
35 | PhaseOracle(0xE8) | qureg
36 |
37 | main_engine.flush()
38 |
39 | assert np.array_equal(np.sign(sim.cheat()[1]), [1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0])
40 | All(Measure) | qureg
41 |
42 |
43 | def test_phase_majority_from_python():
44 | dormouse = pytest.importorskip('dormouse') # noqa: F841
45 |
46 | def maj(a, b, c):
47 | return (a and b) or (a and c) or (b and c) # pragma: no cover
48 |
49 | sim = Simulator()
50 | main_engine = MainEngine(sim)
51 |
52 | qureg = main_engine.allocate_qureg(3)
53 | All(H) | qureg
54 | PhaseOracle(maj) | qureg
55 |
56 | main_engine.flush()
57 |
58 | assert np.array_equal(np.sign(sim.cheat()[1]), [1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0])
59 | All(Measure) | qureg
60 |
61 |
62 | def test_phase_invalid_function():
63 | main_engine = MainEngine(backend=DummyEngine(), engine_list=[DummyEngine()])
64 |
65 | qureg = main_engine.allocate_qureg(3)
66 |
67 | with pytest.raises(AttributeError):
68 | PhaseOracle(-42) | qureg
69 |
70 | with pytest.raises(AttributeError):
71 | PhaseOracle(0xCAFE) | qureg
72 |
73 | with pytest.raises(RuntimeError):
74 | PhaseOracle(0x8E, synth=lambda: revkit.esopbs()) | qureg
75 |
--------------------------------------------------------------------------------
/projectq/setups/decompositions/rz2rx.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | #
15 | # Module uses ideas from "Basic circuit compilation techniques for an
16 | # ion-trap quantum machine" by Dmitri Maslov (2017) at
17 | # https://iopscience.iop.org/article/10.1088/1367-2630/aa5e47
18 |
19 | """Registers a decomposition for the Rz gate into an Rx and Ry(pi/2) or Ry(-pi/2) gate."""
20 |
21 | import math
22 |
23 | from projectq.cengines import DecompositionRule
24 | from projectq.meta import Compute, Control, Uncompute, get_control_count
25 | from projectq.ops import Rx, Ry, Rz
26 |
27 |
28 | def _decompose_rz2rx_P(cmd): # pylint: disable=invalid-name
29 | """Decompose the Rz using negative angle."""
30 | # Labelled 'P' for 'plus' because decomposition ends with a Ry(+pi/2)
31 | qubit = cmd.qubits[0]
32 | eng = cmd.engine
33 | angle = cmd.gate.angle
34 |
35 | with Control(eng, cmd.control_qubits):
36 | with Compute(eng):
37 | Ry(-math.pi / 2.0) | qubit
38 | Rx(-angle) | qubit
39 | Uncompute(eng)
40 |
41 |
42 | def _decompose_rz2rx_M(cmd): # pylint: disable=invalid-name
43 | """Decompose the Rz using positive angle."""
44 | # Labelled 'M' for 'minus' because decomposition ends with a Ry(-pi/2)
45 | qubit = cmd.qubits[0]
46 | eng = cmd.engine
47 | angle = cmd.gate.angle
48 |
49 | with Control(eng, cmd.control_qubits):
50 | with Compute(eng):
51 | Ry(math.pi / 2.0) | qubit
52 | Rx(angle) | qubit
53 | Uncompute(eng)
54 |
55 |
56 | def _recognize_RzNoCtrl(cmd): # pylint: disable=invalid-name
57 | """Decompose the gate only if the command represents a single qubit gate (if it is not part of a control gate)."""
58 | return get_control_count(cmd) == 0
59 |
60 |
61 | #: Decomposition rules
62 | all_defined_decomposition_rules = [
63 | DecompositionRule(Rz, _decompose_rz2rx_P, _recognize_RzNoCtrl),
64 | DecompositionRule(Rz, _decompose_rz2rx_M, _recognize_RzNoCtrl),
65 | ]
66 |
--------------------------------------------------------------------------------
/projectq/libs/revkit/_control_function_test.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """Tests for libs.revkit._control_function."""
15 |
16 | import pytest
17 |
18 | from projectq import MainEngine
19 | from projectq.cengines import DummyEngine
20 | from projectq.libs.revkit import ControlFunctionOracle
21 |
22 | # run this test only if RevKit Python module can be loaded
23 | revkit = pytest.importorskip('revkit')
24 |
25 |
26 | def test_control_function_majority():
27 | saving_backend = DummyEngine(save_commands=True)
28 | main_engine = MainEngine(backend=saving_backend, engine_list=[DummyEngine()])
29 |
30 | qubit0 = main_engine.allocate_qubit()
31 | qubit1 = main_engine.allocate_qubit()
32 | qubit2 = main_engine.allocate_qubit()
33 | qubit3 = main_engine.allocate_qubit()
34 |
35 | ControlFunctionOracle(0xE8) | (qubit0, qubit1, qubit2, qubit3)
36 |
37 | assert len(saving_backend.received_commands) == 7
38 |
39 |
40 | def test_control_function_majority_from_python():
41 | dormouse = pytest.importorskip('dormouse') # noqa: F841
42 |
43 | def maj(a, b, c):
44 | return (a and b) or (a and c) or (b and c) # pragma: no cover
45 |
46 | saving_backend = DummyEngine(save_commands=True)
47 | main_engine = MainEngine(backend=saving_backend, engine_list=[DummyEngine()])
48 |
49 | qubit0 = main_engine.allocate_qubit()
50 | qubit1 = main_engine.allocate_qubit()
51 | qubit2 = main_engine.allocate_qubit()
52 | qubit3 = main_engine.allocate_qubit()
53 |
54 | ControlFunctionOracle(maj) | (qubit0, qubit1, qubit2, qubit3)
55 |
56 |
57 | def test_control_function_invalid_function():
58 | main_engine = MainEngine(backend=DummyEngine(), engine_list=[DummyEngine()])
59 |
60 | qureg = main_engine.allocate_qureg(3)
61 |
62 | with pytest.raises(AttributeError):
63 | ControlFunctionOracle(-42) | qureg
64 |
65 | with pytest.raises(AttributeError):
66 | ControlFunctionOracle(0x8E) | qureg
67 |
68 | with pytest.raises(RuntimeError):
69 | ControlFunctionOracle(0x8, synth=revkit.esopps) | qureg
70 |
--------------------------------------------------------------------------------
/projectq/cengines/_tagremover.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """
15 | The TagRemover compiler engine.
16 |
17 | A TagRemover engine removes temporary command tags (such as Compute/Uncompute), thus enabling optimization across meta
18 | statements (loops after unrolling, compute/uncompute, ...)
19 | """
20 | from projectq.meta import ComputeTag, UncomputeTag
21 |
22 | from ._basics import BasicEngine
23 |
24 |
25 | class TagRemover(BasicEngine):
26 | """
27 | Compiler engine that remove temporary command tags.
28 |
29 | TagRemover is a compiler engine which removes temporary command tags (see the tag classes such as LoopTag in
30 | projectq.meta._loop).
31 |
32 | Removing tags is important (after having handled them if necessary) in order to enable optimizations across
33 | meta-function boundaries (compute/ action/uncompute or loops after unrolling)
34 | """
35 |
36 | def __init__(self, tags=None):
37 | """
38 | Initialize a TagRemover object.
39 |
40 | Args:
41 | tags: A list of meta tag classes (e.g., [ComputeTag, UncomputeTag])
42 | denoting the tags to remove
43 | """
44 | super().__init__()
45 | if not tags:
46 | self._tags = [ComputeTag, UncomputeTag]
47 | elif isinstance(tags, list):
48 | self._tags = tags
49 | else:
50 | raise TypeError(f'tags should be a list! Got: {tags}')
51 |
52 | def receive(self, command_list):
53 | """
54 | Receive a list of commands.
55 |
56 | Receive a list of commands from the previous engine, remove all tags which are an instance of at least one of
57 | the meta tags provided in the constructor, and then send them on to the next compiler engine.
58 |
59 | Args:
60 | command_list (list): List of commands to receive and then (after removing tags) send on.
61 | """
62 | for cmd in command_list:
63 | for tag in self._tags:
64 | cmd.tags = [t for t in cmd.tags if not isinstance(t, tag)]
65 | self.send([cmd])
66 |
--------------------------------------------------------------------------------
/examples/grover.py:
--------------------------------------------------------------------------------
1 | # pylint: skip-file
2 |
3 | """Example implementation of Grover's algorithm."""
4 |
5 | import math
6 |
7 | from projectq import MainEngine
8 | from projectq.meta import Compute, Control, Loop, Uncompute
9 | from projectq.ops import All, H, Measure, X, Z
10 |
11 |
12 | def run_grover(eng, n, oracle):
13 | """
14 | Run Grover's algorithm on n qubit using the provided quantum oracle.
15 |
16 | Args:
17 | eng (MainEngine): Main compiler engine to run Grover on.
18 | n (int): Number of bits in the solution.
19 | oracle (function): Function accepting the engine, an n-qubit register,
20 | and an output qubit which is flipped by the oracle for the correct
21 | bit string.
22 |
23 | Returns:
24 | solution (list): Solution bit-string.
25 | """
26 | x = eng.allocate_qureg(n)
27 |
28 | # start in uniform superposition
29 | All(H) | x
30 |
31 | # number of iterations we have to run:
32 | num_it = int(math.pi / 4.0 * math.sqrt(1 << n))
33 |
34 | # prepare the oracle output qubit (the one that is flipped to indicate the
35 | # solution. start in state 1/sqrt(2) * (|0> - |1>) s.t. a bit-flip turns
36 | # into a (-1)-phase.
37 | oracle_out = eng.allocate_qubit()
38 | X | oracle_out
39 | H | oracle_out
40 |
41 | # run num_it iterations
42 | with Loop(eng, num_it):
43 | # oracle adds a (-1)-phase to the solution
44 | oracle(eng, x, oracle_out)
45 |
46 | # reflection across uniform superposition
47 | with Compute(eng):
48 | All(H) | x
49 | All(X) | x
50 |
51 | with Control(eng, x[0:-1]):
52 | Z | x[-1]
53 |
54 | Uncompute(eng)
55 |
56 | All(Measure) | x
57 | Measure | oracle_out
58 |
59 | eng.flush()
60 | # return result
61 | return [int(qubit) for qubit in x]
62 |
63 |
64 | def alternating_bits_oracle(eng, qubits, output):
65 | """
66 | Alternating bit oracle.
67 |
68 | Mark the solution string 1,0,1,0,...,0,1 by flipping the output qubit, conditioned on qubits being equal to the
69 | alternating bit-string.
70 |
71 | Args:
72 | eng (MainEngine): Main compiler engine the algorithm is being run on.
73 | qubits (Qureg): n-qubit quantum register Grover search is run on.
74 | output (Qubit): Output qubit to flip in order to mark the solution.
75 | """
76 | with Compute(eng):
77 | All(X) | qubits[1::2]
78 | with Control(eng, qubits):
79 | X | output
80 | Uncompute(eng)
81 |
82 |
83 | if __name__ == "__main__":
84 | eng = MainEngine() # use default compiler engine
85 | # run Grover search to find a 7-bit solution
86 | print(run_grover(eng, 7, alternating_bits_oracle))
87 |
--------------------------------------------------------------------------------
/examples/README.rst:
--------------------------------------------------------------------------------
1 | Examples and Tutorials
2 | ======================
3 |
4 | This folder contains a collection of **examples** and **tutorials** for how to use ProjectQ. They offer a great way to
5 | get started. While this collection is growing, it will never be possible to cover everything. Therefore, we refer the
6 | readers to also have a look at:
7 |
8 | * Our complete **code documentation** which can be found online `here
9 | `__. Besides the newest version of the documentation it also provides older
10 | versions. Moreover, these docs can be downloaded for offline usage.
11 |
12 | * Our **unit tests**. More than 99% of all lines of code are covered with various unit tests since the first
13 | release. Tests are really important to us. Therefore, if you are wondering how a specific feature can be used, have a
14 | look at the **unit tests**, where you can find plenty of examples. Finding the unit tests is very easy: E.g., the
15 | tests of the simulator implemented in *ProjectQ/projectq/backends/_sim/_simulator.py* can all be found in the same
16 | folder in the file *ProjectQ/projectq/backends/_sim/_simulator_test.py*.
17 |
18 | Getting started / background information
19 | ----------------------------------------
20 |
21 | It might be a good starting point to have a look at our paper which explains the goals of the ProjectQ framework and
22 | also gives a good overview:
23 |
24 | * Damian S. Steiger, Thomas Häner, and Matthias Troyer "ProjectQ: An Open Source Software Framework for Quantum
25 | Computing" `Quantum 2, 49 (2018) `__ (published on `arXiv
26 | `__ on 23 Dec 2016)
27 |
28 | Our second paper looks at a few aspects of ProjectQ in more details:
29 |
30 | * Damian S. Steiger, Thomas Häner, and Matthias Troyer "Advantages of a modular high-level quantum programming
31 | framework" `[arxiv:1806.01861] `__
32 |
33 | Examples and tutorials in this folder
34 | -------------------------------------
35 |
36 | 1. Some of the files in this folder are explained in the `documentation
37 | `__.
38 |
39 | 2. Take a look at the *simulator_tutorial.ipynb* for a detailed introduction to most of the features of our high
40 | performance quantum simulator.
41 |
42 | 3. Running on the IBM QE chip is explained in more details in *ibm_entangle.ipynb*.
43 |
44 | 4. A small tutorial on the compiler is available in *compiler_tutorial.ipynb* which explains how to compile to a
45 | specific gate set.
46 |
47 | 5. A small tutorial on the mappers is available in *mapper_tutorial.ipynb* which explains how to map a quantum circuit
48 | to a linear chain or grid of physical qubits.
49 |
--------------------------------------------------------------------------------
/examples/ionq.py:
--------------------------------------------------------------------------------
1 | # Copyright 2021 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | # pylint: skip-file
15 |
16 | """Example of a basic entangling operation using an IonQBackend."""
17 |
18 | import getpass
19 |
20 | import matplotlib.pyplot as plt
21 |
22 | import projectq.setups.ionq
23 | from projectq import MainEngine
24 | from projectq.backends import IonQBackend
25 | from projectq.libs.hist import histogram
26 | from projectq.ops import All, Entangle, Measure
27 |
28 |
29 | def run_entangle(eng, num_qubits=3):
30 | """
31 | Run an entangling operation on the provided compiler engine.
32 |
33 | Args:
34 | eng (MainEngine): Main compiler engine to use.
35 | num_qubits (int): Number of qubits to entangle.
36 |
37 | Returns:
38 | measurement (list): List of measurement outcomes.
39 | """
40 | # allocate the quantum register to entangle
41 | qureg = eng.allocate_qureg(num_qubits)
42 |
43 | # entangle the qureg
44 | Entangle | qureg
45 |
46 | # measure; should be all-0 or all-1
47 | All(Measure) | qureg
48 |
49 | # run the circuit
50 | eng.flush()
51 |
52 | # access the probabilities via the back-end:
53 | # results = eng.backend.get_probabilities(qureg)
54 | # for state in results:
55 | # print(f"Measured {state} with p = {results[state]}.")
56 | # or plot them directly:
57 | histogram(eng.backend, qureg)
58 | plt.show()
59 |
60 | # return one (random) measurement outcome.
61 | return [int(q) for q in qureg]
62 |
63 |
64 | if __name__ == '__main__':
65 | token = None
66 | device = None
67 | if token is None:
68 | token = getpass.getpass(prompt='IonQ apiKey > ')
69 | if device is None:
70 | device = input('IonQ device > ')
71 |
72 | # create an IonQBackend
73 | backend = IonQBackend(
74 | use_hardware=True,
75 | token=token,
76 | num_runs=200,
77 | verbose=True,
78 | device=device,
79 | )
80 | engine_list = projectq.setups.ionq.get_engine_list(
81 | token=token,
82 | device=device,
83 | )
84 | engine = MainEngine(backend, engine_list)
85 | # run the circuit and print the result
86 | print(run_entangle(engine))
87 |
--------------------------------------------------------------------------------
/projectq/backends/_sim/_cppkernels/nointrin/kernel2.hpp:
--------------------------------------------------------------------------------
1 | // Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | template
16 | inline void kernel_core(V &psi, std::size_t I, std::size_t d0, std::size_t d1, M const& m)
17 | {
18 | std::complex v[4];
19 | v[0] = psi[I];
20 | v[1] = psi[I + d0];
21 | v[2] = psi[I + d1];
22 | v[3] = psi[I + d0 + d1];
23 |
24 | psi[I] = (add(mul(v[0], m[0][0]), add(mul(v[1], m[0][1]), add(mul(v[2], m[0][2]), mul(v[3], m[0][3])))));
25 | psi[I + d0] = (add(mul(v[0], m[1][0]), add(mul(v[1], m[1][1]), add(mul(v[2], m[1][2]), mul(v[3], m[1][3])))));
26 | psi[I + d1] = (add(mul(v[0], m[2][0]), add(mul(v[1], m[2][1]), add(mul(v[2], m[2][2]), mul(v[3], m[2][3])))));
27 | psi[I + d0 + d1] = (add(mul(v[0], m[3][0]), add(mul(v[1], m[3][1]), add(mul(v[2], m[3][2]), mul(v[3], m[3][3])))));
28 |
29 | }
30 |
31 | // bit indices id[.] are given from high to low (e.g. control first for CNOT)
32 | template
33 | void kernel(V &psi, unsigned id1, unsigned id0, M const& m, std::size_t ctrlmask)
34 | {
35 | std::size_t n = psi.size();
36 | std::size_t d0 = 1UL << id0;
37 | std::size_t d1 = 1UL << id1;
38 | std::size_t dsorted[] = {d0 , d1};
39 | std::sort(dsorted, dsorted + 2, std::greater());
40 |
41 | if (ctrlmask == 0){
42 | #pragma omp for collapse(LOOP_COLLAPSE2) schedule(static)
43 | for (std::size_t i0 = 0; i0 < n; i0 += 2 * dsorted[0]){
44 | for (std::size_t i1 = 0; i1 < dsorted[0]; i1 += 2 * dsorted[1]){
45 | for (std::size_t i2 = 0; i2 < dsorted[1]; ++i2){
46 | kernel_core(psi, i0 + i1 + i2, d0, d1, m);
47 | }
48 | }
49 | }
50 | }
51 | else{
52 | #pragma omp for collapse(LOOP_COLLAPSE2) schedule(static)
53 | for (std::size_t i0 = 0; i0 < n; i0 += 2 * dsorted[0]){
54 | for (std::size_t i1 = 0; i1 < dsorted[0]; i1 += 2 * dsorted[1]){
55 | for (std::size_t i2 = 0; i2 < dsorted[1]; ++i2){
56 | if (((i0 + i1 + i2)&ctrlmask) == ctrlmask)
57 | kernel_core(psi, i0 + i1 + i2, d0, d1, m);
58 | }
59 | }
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/projectq/ops/_uniformly_controlled_rotation_test.py:
--------------------------------------------------------------------------------
1 | # Copyright 2018 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """Tests for projectq.ops._uniformly_controlled_rotation."""
15 | import math
16 |
17 | import pytest
18 |
19 | from projectq.ops import Rx
20 | from projectq.ops import _uniformly_controlled_rotation as ucr
21 |
22 | from ._basics import NotMergeable
23 |
24 |
25 | @pytest.mark.parametrize("gate_class", [ucr.UniformlyControlledRy, ucr.UniformlyControlledRz])
26 | def test_init_rounding(gate_class):
27 | gate = gate_class([0.1 + 4 * math.pi, -1e-14])
28 | assert gate.angles == [0.1, 0.0]
29 |
30 |
31 | @pytest.mark.parametrize("gate_class", [ucr.UniformlyControlledRy, ucr.UniformlyControlledRz])
32 | def test_get_inverse(gate_class):
33 | gate = gate_class([0.1, 0.2, 0.3, 0.4])
34 | inverse = gate.get_inverse()
35 | assert inverse == gate_class([-0.1, -0.2, -0.3, -0.4])
36 |
37 |
38 | @pytest.mark.parametrize("gate_class", [ucr.UniformlyControlledRy, ucr.UniformlyControlledRz])
39 | def test_get_merged(gate_class):
40 | gate1 = gate_class([0.1, 0.2, 0.3, 0.4])
41 | gate2 = gate_class([0.1, 0.2, 0.3, 0.4])
42 | merged_gate = gate1.get_merged(gate2)
43 | assert merged_gate == gate_class([0.2, 0.4, 0.6, 0.8])
44 | with pytest.raises(NotMergeable):
45 | gate1.get_merged(Rx(0.1))
46 |
47 |
48 | def test_str_and_hash():
49 | gate1 = ucr.UniformlyControlledRy([0.1, 0.2, 0.3, 0.4])
50 | gate2 = ucr.UniformlyControlledRz([0.1, 0.2, 0.3, 0.4])
51 | assert str(gate1) == "UniformlyControlledRy([0.1, 0.2, 0.3, 0.4])"
52 | assert str(gate2) == "UniformlyControlledRz([0.1, 0.2, 0.3, 0.4])"
53 | assert hash(gate1) == hash("UniformlyControlledRy([0.1, 0.2, 0.3, 0.4])")
54 | assert hash(gate2) == hash("UniformlyControlledRz([0.1, 0.2, 0.3, 0.4])")
55 |
56 |
57 | @pytest.mark.parametrize("gate_class", [ucr.UniformlyControlledRy, ucr.UniformlyControlledRz])
58 | def test_equality(gate_class):
59 | gate1 = gate_class([0.1, 0.2])
60 | gate2 = gate_class([0.1, 0.2 + 1e-14])
61 | assert gate1 == gate2
62 | gate3 = gate_class([0.1, 0.2, 0.1, 0.2])
63 | assert gate2 != gate3
64 | gate4 = ucr.UniformlyControlledRz([0.1, 0.2])
65 | gate5 = ucr.UniformlyControlledRy([0.1, 0.2])
66 | assert gate4 != gate5
67 | assert not gate5 == gate4
68 |
--------------------------------------------------------------------------------
/examples/ionq_half_adder.py:
--------------------------------------------------------------------------------
1 | # Copyright 2021 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | # pylint: skip-file
15 |
16 | """Example of a basic 'half-adder' circuit using an IonQBackend."""
17 |
18 | import getpass
19 | import random
20 |
21 | import matplotlib.pyplot as plt
22 |
23 | import projectq.setups.default
24 | import projectq.setups.ionq
25 | from projectq import MainEngine
26 | from projectq.backends import IonQBackend
27 | from projectq.libs.hist import histogram
28 | from projectq.ops import CNOT, All, Barrier, Measure, Toffoli, X
29 |
30 |
31 | def run_half_adder(eng):
32 | """Run the half-adder circuit."""
33 | # allocate the quantum register to entangle
34 | circuit = eng.allocate_qureg(4)
35 | qubit1, qubit2, qubit3, qubit4 = circuit
36 | result_qubits = [qubit3, qubit4]
37 |
38 | # X gates on the first two qubits
39 | All(X) | [qubit1, qubit2]
40 |
41 | # Barrier
42 | Barrier | circuit
43 |
44 | # Cx gates
45 | CNOT | (qubit1, qubit3)
46 | CNOT | (qubit2, qubit3)
47 |
48 | # CCNOT
49 | Toffoli | (qubit1, qubit2, qubit4)
50 |
51 | # Barrier
52 | Barrier | circuit
53 |
54 | # Measure result qubits
55 | All(Measure) | result_qubits
56 |
57 | # Flush the circuit (this submits a job to the IonQ API)
58 | eng.flush()
59 |
60 | # Show the histogram
61 | histogram(eng.backend, result_qubits)
62 | plt.show()
63 |
64 | # return a random answer from our results
65 | probabilities = eng.backend.get_probabilities(result_qubits)
66 | random_answer = random.choice(list(probabilities.keys()))
67 | return [int(s) for s in random_answer]
68 |
69 |
70 | if __name__ == '__main__':
71 | token = None
72 | device = None
73 | if token is None:
74 | token = getpass.getpass(prompt='IonQ apiKey > ')
75 | if device is None:
76 | device = input('IonQ device > ')
77 |
78 | backend = IonQBackend(
79 | use_hardware=True,
80 | token=token,
81 | num_runs=200,
82 | verbose=True,
83 | device=device,
84 | )
85 | engine_list = projectq.setups.ionq.get_engine_list(
86 | token=token,
87 | device=device,
88 | )
89 | engine = MainEngine(backend, engine_list)
90 | # run the circuit and print the result
91 | print(run_half_adder(engine))
92 |
--------------------------------------------------------------------------------
/examples/unitary_simulator.py:
--------------------------------------------------------------------------------
1 | # Copyright 2021 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | # pylint: skip-file
15 |
16 | """Example of using the UnitarySimulator."""
17 |
18 |
19 | import numpy as np
20 |
21 | from projectq.backends import UnitarySimulator
22 | from projectq.cengines import MainEngine
23 | from projectq.meta import Control
24 | from projectq.ops import QFT, All, CtrlAll, Measure, X
25 |
26 |
27 | def run_circuit(eng, n_qubits, circuit_num, gate_after_measure=False):
28 | """Run a quantum circuit demonstrating the capabilities of the UnitarySimulator."""
29 | qureg = eng.allocate_qureg(n_qubits)
30 |
31 | if circuit_num == 1:
32 | All(X) | qureg
33 | elif circuit_num == 2:
34 | X | qureg[0]
35 | with Control(eng, qureg[:2]):
36 | All(X) | qureg[2:]
37 | elif circuit_num == 3:
38 | with Control(eng, qureg[:2], ctrl_state=CtrlAll.Zero):
39 | All(X) | qureg[2:]
40 | elif circuit_num == 4:
41 | QFT | qureg
42 |
43 | eng.flush()
44 | All(Measure) | qureg
45 |
46 | if gate_after_measure:
47 | QFT | qureg
48 | eng.flush()
49 | All(Measure) | qureg
50 |
51 |
52 | def main():
53 | """Definition of the main function of this example."""
54 | # Create a MainEngine with a unitary simulator backend
55 | eng = MainEngine(backend=UnitarySimulator())
56 |
57 | n_qubits = 3
58 |
59 | # Run out quantum circuit
60 | # 1 - circuit applying X on all qubits
61 | # 2 - circuit applying an X gate followed by a controlled-X gate
62 | # 3 - circuit applying a off-controlled-X gate
63 | # 4 - circuit applying a QFT on all qubits (QFT will get decomposed)
64 | run_circuit(eng, n_qubits, 3, gate_after_measure=True)
65 |
66 | # Output the unitary transformation of the circuit
67 | print('The unitary of the circuit is:')
68 | print(eng.backend.unitary)
69 |
70 | # Output the final state of the qubits (assuming they all start in state |0>)
71 | print('The final state of the qubits is:')
72 | print(eng.backend.unitary @ np.array([1] + ([0] * (2**n_qubits - 1))))
73 | print('\n')
74 |
75 | # Show the unitaries separated by measurement:
76 | for history in eng.backend.history:
77 | print('Previous unitary is: \n', history, '\n')
78 |
79 |
80 | if __name__ == '__main__':
81 | main()
82 |
--------------------------------------------------------------------------------
/projectq/meta/_dagger_test.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """Tests for projectq.meta._dagger.py"""
15 |
16 | import types
17 |
18 | import pytest
19 |
20 | from projectq import MainEngine
21 | from projectq.cengines import DummyEngine
22 | from projectq.meta import DirtyQubitTag, _dagger
23 | from projectq.ops import CNOT, Allocate, Deallocate, H, Rx, X
24 |
25 |
26 | def test_dagger_with_dirty_qubits():
27 | backend = DummyEngine(save_commands=True)
28 |
29 | def allow_dirty_qubits(self, meta_tag):
30 | return meta_tag == DirtyQubitTag
31 |
32 | backend.is_meta_tag_handler = types.MethodType(allow_dirty_qubits, backend)
33 | eng = MainEngine(backend=backend, engine_list=[DummyEngine()])
34 | qubit = eng.allocate_qubit()
35 | with _dagger.Dagger(eng):
36 | ancilla = eng.allocate_qubit(dirty=True)
37 | Rx(0.6) | ancilla
38 | CNOT | (ancilla, qubit)
39 | H | qubit
40 | Rx(-0.6) | ancilla
41 | del ancilla[0]
42 | eng.flush(deallocate_qubits=True)
43 | assert len(backend.received_commands) == 9
44 | assert backend.received_commands[0].gate == Allocate
45 | assert backend.received_commands[1].gate == Allocate
46 | assert backend.received_commands[2].gate == Rx(0.6)
47 | assert backend.received_commands[3].gate == H
48 | assert backend.received_commands[4].gate == X
49 | assert backend.received_commands[5].gate == Rx(-0.6)
50 | assert backend.received_commands[6].gate == Deallocate
51 | assert backend.received_commands[7].gate == Deallocate
52 | assert backend.received_commands[1].tags == [DirtyQubitTag()]
53 | assert backend.received_commands[6].tags == [DirtyQubitTag()]
54 |
55 |
56 | def test_dagger_qubit_management_error():
57 | eng = MainEngine(backend=DummyEngine(), engine_list=[DummyEngine()])
58 | with pytest.raises(_dagger.QubitManagementError):
59 | with _dagger.Dagger(eng):
60 | ancilla = eng.allocate_qubit() # noqa: F841
61 |
62 |
63 | def test_dagger_raises_only_single_error():
64 | eng = MainEngine(backend=DummyEngine(), engine_list=[])
65 | # Tests that QubitManagementError is not sent in addition
66 | with pytest.raises(RuntimeError):
67 | with _dagger.Dagger(eng):
68 | ancilla = eng.allocate_qubit() # noqa: F841
69 | raise RuntimeError
70 |
--------------------------------------------------------------------------------
/projectq/setups/decompositions/cnu2toffoliandcu.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """
16 | Register a decomposition rule for multi-controlled gates.
17 |
18 | Implements the decomposition of Nielsen and Chuang (Fig. 4.10) which
19 | decomposes a C^n(U) gate into a sequence of 2 * (n-1) Toffoli gates and one
20 | C(U) gate by using (n-1) ancilla qubits and circuit depth of 2n-1.
21 | """
22 |
23 | from projectq.cengines import DecompositionRule
24 | from projectq.meta import Compute, Control, Uncompute, get_control_count
25 | from projectq.ops import BasicGate, Toffoli, XGate
26 |
27 |
28 | def _recognize_CnU(cmd): # pylint: disable=invalid-name
29 | """Recognize an arbitrary gate which has n>=2 control qubits, except a Toffoli gate."""
30 | if get_control_count(cmd) == 2:
31 | if not isinstance(cmd.gate, XGate):
32 | return True
33 | elif get_control_count(cmd) > 2:
34 | return True
35 | return False
36 |
37 |
38 | def _decompose_CnU(cmd): # pylint: disable=invalid-name
39 | """
40 | Decompose a multi-controlled gate U with n control qubits into a single- controlled U.
41 |
42 | It uses (n-1) work qubits and 2 * (n-1) Toffoli gates for general U and (n-2) work qubits and 2n - 3 Toffoli gates
43 | if U is an X-gate.
44 | """
45 | eng = cmd.engine
46 | qubits = cmd.qubits
47 | ctrl_qureg = cmd.control_qubits
48 | gate = cmd.gate
49 | n_controls = get_control_count(cmd)
50 |
51 | # specialized for X-gate
52 | if gate == XGate() and n_controls > 2:
53 | n_controls -= 1
54 | ancilla_qureg = eng.allocate_qureg(n_controls - 1)
55 |
56 | with Compute(eng):
57 | Toffoli | (ctrl_qureg[0], ctrl_qureg[1], ancilla_qureg[0])
58 | for ctrl_index in range(2, n_controls):
59 | Toffoli | (
60 | ctrl_qureg[ctrl_index],
61 | ancilla_qureg[ctrl_index - 2],
62 | ancilla_qureg[ctrl_index - 1],
63 | )
64 | ctrls = [ancilla_qureg[-1]]
65 |
66 | # specialized for X-gate
67 | if gate == XGate() and get_control_count(cmd) > 2:
68 | ctrls += [ctrl_qureg[-1]]
69 | with Control(eng, ctrls):
70 | gate | qubits
71 |
72 | Uncompute(eng)
73 |
74 |
75 | #: Decomposition rules
76 | all_defined_decomposition_rules = [DecompositionRule(BasicGate, _decompose_CnU, _recognize_CnU)]
77 |
--------------------------------------------------------------------------------
/projectq/cengines/_basicmapper_test.py:
--------------------------------------------------------------------------------
1 | # Copyright 2018 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """Tests for projectq.cengines._basicmapper.py."""
15 |
16 | from projectq.cengines import DummyEngine, _basicmapper
17 | from projectq.meta import LogicalQubitIDTag
18 | from projectq.ops import Allocate, BasicGate, Command, Deallocate, FlushGate, Measure
19 | from projectq.types import WeakQubitRef
20 |
21 |
22 | def test_basic_mapper_engine_send_cmd_with_mapped_ids():
23 | mapper = _basicmapper.BasicMapperEngine()
24 | mapper.current_mapping = {0: 3, 1: 2, 2: 1, 3: 0}
25 | backend = DummyEngine(save_commands=True)
26 | backend.is_last_engine = True
27 | mapper.next_engine = backend
28 | # generate a few commands
29 | qb0 = WeakQubitRef(engine=None, idx=0)
30 | qb1 = WeakQubitRef(engine=None, idx=1)
31 | qb2 = WeakQubitRef(engine=None, idx=2)
32 | qb3 = WeakQubitRef(engine=None, idx=3)
33 | cmd0 = Command(engine=None, gate=Allocate, qubits=([qb0],), controls=[], tags=[])
34 | cmd1 = Command(engine=None, gate=Deallocate, qubits=([qb1],), controls=[], tags=[])
35 | cmd2 = Command(engine=None, gate=Measure, qubits=([qb2],), controls=[], tags=["SomeTag"])
36 | cmd3 = Command(
37 | engine=None,
38 | gate=BasicGate(),
39 | qubits=([qb0, qb1], [qb2]),
40 | controls=[qb3],
41 | tags=[],
42 | )
43 | cmd4 = Command(None, FlushGate(), ([WeakQubitRef(None, -1)],))
44 | mapper._send_cmd_with_mapped_ids(cmd0)
45 | mapper._send_cmd_with_mapped_ids(cmd1)
46 | mapper._send_cmd_with_mapped_ids(cmd2)
47 | mapper._send_cmd_with_mapped_ids(cmd3)
48 | mapper._send_cmd_with_mapped_ids(cmd4)
49 | rcmd0 = backend.received_commands[0]
50 | rcmd1 = backend.received_commands[1]
51 | rcmd2 = backend.received_commands[2]
52 | rcmd3 = backend.received_commands[3]
53 | rcmd4 = backend.received_commands[4]
54 | assert rcmd0.gate == Allocate
55 | assert rcmd0.qubits == ([qb3],)
56 | assert rcmd1.gate == Deallocate
57 | assert rcmd1.qubits == ([qb2],)
58 | assert rcmd2.gate == Measure
59 | assert rcmd2.qubits == ([qb1],)
60 | assert rcmd2.tags == ["SomeTag", LogicalQubitIDTag(2)]
61 | assert rcmd3.gate == BasicGate()
62 | assert rcmd3.qubits == ([qb3, qb2], [qb1])
63 | assert rcmd3.control_qubits == [qb0]
64 | assert len(rcmd4.qubits) == 1
65 | assert len(rcmd4.qubits[0]) == 1
66 | assert rcmd4.qubits[0][0].id == -1
67 |
--------------------------------------------------------------------------------
/examples/ionq_bv.py:
--------------------------------------------------------------------------------
1 | # Copyright 2021 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | # pylint: skip-file
15 |
16 | """Example of a basic Bernstein-Vazirani circuit using an IonQBackend."""
17 |
18 | import getpass
19 | import random
20 |
21 | import matplotlib.pyplot as plt
22 |
23 | import projectq.setups.ionq
24 | from projectq import MainEngine
25 | from projectq.backends import IonQBackend
26 | from projectq.libs.hist import histogram
27 | from projectq.ops import CX, All, Barrier, H, Measure, Z
28 |
29 |
30 | def oracle(qureg, input_size, s):
31 | """Apply the 'oracle'."""
32 | for bit in range(input_size):
33 | if s[input_size - 1 - bit] == '1':
34 | CX | (qureg[bit], qureg[input_size])
35 |
36 |
37 | def run_bv_circuit(eng, input_size, s_int):
38 | """Run the quantum circuit."""
39 | s = f"{s_int:0{input_size}b}"
40 | print("Secret string: ", s)
41 | print("Number of qubits: ", str(input_size + 1))
42 | circuit = eng.allocate_qureg(input_size + 1)
43 | All(H) | circuit
44 | Z | circuit[input_size]
45 |
46 | Barrier | circuit
47 |
48 | oracle(circuit, input_size, s)
49 |
50 | Barrier | circuit
51 |
52 | qubits = circuit[:input_size]
53 | All(H) | qubits
54 | All(Measure) | qubits
55 | eng.flush()
56 |
57 | # return a random answer from our results
58 | histogram(eng.backend, qubits)
59 | plt.show()
60 |
61 | # return a random answer from our results
62 | probabilities = eng.backend.get_probabilities(qubits)
63 | random_answer = random.choice(list(probabilities.keys()))
64 | print("Probability of getting correct string: ", probabilities[s[::-1]])
65 | return [int(s) for s in random_answer]
66 |
67 |
68 | if __name__ == '__main__':
69 | token = None
70 | device = None
71 | if token is None:
72 | token = getpass.getpass(prompt='IonQ apiKey > ')
73 | if device is None:
74 | device = input('IonQ device > ')
75 |
76 | # create main compiler engine for the IonQ back-end
77 | backend = IonQBackend(
78 | use_hardware=True,
79 | token=token,
80 | num_runs=1,
81 | verbose=False,
82 | device=device,
83 | )
84 | engine_list = projectq.setups.ionq.get_engine_list(
85 | token=token,
86 | device=device,
87 | )
88 | engine = MainEngine(backend, engine_list)
89 |
90 | # run the circuit and print the result
91 | print(run_bv_circuit(engine, 3, 3))
92 |
--------------------------------------------------------------------------------
/.github/workflows/draft_release.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | name: "Draft new release"
4 |
5 | on: # yamllint disable-line rule:truthy
6 | workflow_dispatch:
7 | inputs:
8 | tag:
9 | description: 'Tag to prepare (format: vXX.YY.ZZ)'
10 | required: true
11 | jobs:
12 | new-release:
13 | name: "Draft a new release"
14 | runs-on: ubuntu-latest
15 | steps:
16 | - name: Install git-flow
17 | run: sudo apt update && sudo apt install -y git-flow
18 |
19 | - uses: actions/checkout@v3
20 |
21 | - name: Setup Python
22 | uses: actions/setup-python@v3
23 | with:
24 | python-version: '3.11'
25 | cache: 'pip'
26 | cache-dependency-path: '**/setup.cfg'
27 |
28 | - name: Configure git-flow
29 | run: |
30 | git fetch --tags --depth=1 origin master develop
31 | git flow init --default --tag v
32 |
33 | - name: Create release branch
34 | run: git flow release start ${{ github.event.inputs.tag }}
35 |
36 | - name: Initialize mandatory git config
37 | run: |
38 | git config user.name "GitHub actions"
39 | git config user.email noreply@github.com
40 |
41 | - name: Update CHANGELOG
42 | run: |
43 | python3 -m pip install mdformat-gfm 'git+https://github.com/Takishima/keepachangelog@v1.0.1'
44 | python3 -m keepachangelog release "${{ github.event.inputs.tag }}"
45 | python3 -m mdformat CHANGELOG.md
46 |
47 | - name: Commit changelog and manifest files
48 | id: make-commit
49 | run: |
50 | git add CHANGELOG.md
51 | git commit --message "Preparing release ${{ github.event.inputs.tag }}"
52 |
53 | echo "::set-output name=commit::$(git rev-parse HEAD)"
54 |
55 | - name: Push new branch
56 | run: git flow release publish ${{ github.event.inputs.tag }}
57 |
58 | # yamllint disable rule:line-length
59 | - name: Create pull request
60 | uses: thomaseizinger/create-pull-request@1.3.1
61 | env:
62 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
63 | with:
64 | head: release/${{ github.event.inputs.tag }}
65 | base: master
66 | title: Release version ${{ github.event.inputs.tag }}
67 | reviewers: ${{ github.actor }}
68 | # Write a nice message to the user.
69 | # We are claiming things here based on the `publish-new-release.yml` workflow.
70 | # You should obviously adopt it to say the truth depending on your release workflow :)
71 | body: |
72 | Hi @${{ github.actor }}!
73 |
74 | This PR was created in response to a manual trigger of the release workflow here: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}.
75 | I've updated the changelog and bumped the versions in the manifest files in this commit: ${{ steps.make-commit.outputs.commit }}.
76 |
77 | Merging this PR will create a GitHub release and upload any assets that are created as part of the release build.
78 |
--------------------------------------------------------------------------------
/projectq/libs/hist/_histogram.py:
--------------------------------------------------------------------------------
1 | # Copyright 2020 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """Functions to plot a histogram of measured data."""
16 |
17 | import matplotlib.pyplot as plt
18 |
19 | from projectq.backends import Simulator
20 |
21 |
22 | def histogram(backend, qureg):
23 | """
24 | Make a measurement outcome probability histogram for the given qubits.
25 |
26 | Args:
27 | backend (BasicEngine): A ProjectQ backend
28 | qureg (list of qubits and/or quregs): The qubits,
29 | for which to make the histogram
30 |
31 | Returns:
32 | A tuple (fig, axes, probabilities), where:
33 | fig: The histogram as figure
34 | axes: The axes of the histogram
35 | probabilities (dict): A dictionary mapping outcomes as string
36 | to their probabilities
37 |
38 | Note:
39 | Don't forget to call eng.flush() before using this function.
40 | """
41 | qubit_list = []
42 | for qb in qureg:
43 | if isinstance(qb, list):
44 | qubit_list.extend(qb)
45 | else:
46 | qubit_list.append(qb)
47 |
48 | if len(qubit_list) > 5:
49 | print(f'Warning: For {len(qubit_list)} qubits there are 2^{len(qubit_list)} different outcomes')
50 | print("The resulting histogram may look bad and/or take too long.")
51 | print("Consider calling histogram() with a sublist of the qubits.")
52 |
53 | if hasattr(backend, 'get_probabilities'):
54 | probabilities = backend.get_probabilities(qureg)
55 | elif isinstance(backend, Simulator):
56 | outcome = [0] * len(qubit_list)
57 | n_outcomes = 1 << len(qubit_list)
58 | probabilities = {}
59 | for i in range(n_outcomes):
60 | for pos in range(len(qubit_list)):
61 | if (1 << pos) & i:
62 | outcome[pos] = 1
63 | else:
64 | outcome[pos] = 0
65 | probabilities[''.join([str(bit) for bit in outcome])] = backend.get_probability(outcome, qubit_list)
66 | else:
67 | raise RuntimeError('Unable to retrieve probabilities from backend')
68 |
69 | # Empirical figure size for up to 5 qubits
70 | fig, axes = plt.subplots(figsize=(min(21.2, 2 + 0.6 * (1 << len(qubit_list))), 7))
71 | names = list(probabilities.keys())
72 | values = list(probabilities.values())
73 | axes.bar(names, values)
74 | fig.suptitle('Measurement Probabilities')
75 | return (fig, axes, probabilities)
76 |
--------------------------------------------------------------------------------
/projectq/setups/decompositions/stateprep2cnot_test.py:
--------------------------------------------------------------------------------
1 | # Copyright 2018 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """Tests for projectq.setups.decompositions.stateprep2cnot."""
15 |
16 | import cmath
17 | import math
18 | from copy import deepcopy
19 |
20 | import numpy as np
21 | import pytest
22 |
23 | import projectq
24 | import projectq.setups.decompositions.stateprep2cnot as stateprep2cnot
25 | from projectq.ops import All, Command, Measure, Ph, Ry, Rz, StatePreparation
26 | from projectq.setups import restrictedgateset
27 | from projectq.types import WeakQubitRef
28 |
29 |
30 | def test_invalid_arguments():
31 | qb0 = WeakQubitRef(engine=None, idx=0)
32 | qb1 = WeakQubitRef(engine=None, idx=1)
33 | cmd = Command(None, StatePreparation([0, 1j]), qubits=([qb0], [qb1]))
34 | with pytest.raises(ValueError):
35 | stateprep2cnot._decompose_state_preparation(cmd)
36 |
37 |
38 | def test_wrong_final_state():
39 | qb0 = WeakQubitRef(engine=None, idx=0)
40 | qb1 = WeakQubitRef(engine=None, idx=1)
41 | cmd = Command(None, StatePreparation([0, 1j]), qubits=([qb0, qb1],))
42 | with pytest.raises(ValueError):
43 | stateprep2cnot._decompose_state_preparation(cmd)
44 | cmd2 = Command(None, StatePreparation([0, 0.999j]), qubits=([qb0],))
45 | with pytest.raises(ValueError):
46 | stateprep2cnot._decompose_state_preparation(cmd2)
47 |
48 |
49 | @pytest.mark.parametrize("zeros", [True, False])
50 | @pytest.mark.parametrize("n_qubits", [1, 2, 3, 4])
51 | def test_state_preparation(n_qubits, zeros):
52 | engine_list = restrictedgateset.get_engine_list(one_qubit_gates=(Ry, Rz, Ph))
53 | eng = projectq.MainEngine(engine_list=engine_list)
54 | qureg = eng.allocate_qureg(n_qubits)
55 | eng.flush()
56 |
57 | f_state = [0.2 + 0.1 * x * cmath.exp(0.1j + 0.2j * x) for x in range(2**n_qubits)]
58 | if zeros:
59 | for i in range(2 ** (n_qubits - 1)):
60 | f_state[i] = 0
61 | norm = 0
62 | for amplitude in f_state:
63 | norm += abs(amplitude) ** 2
64 | f_state = [x / math.sqrt(norm) for x in f_state]
65 |
66 | StatePreparation(f_state) | qureg
67 | eng.flush()
68 |
69 | wavefunction = deepcopy(eng.backend.cheat()[1])
70 | # Test that simulator hasn't reordered wavefunction
71 | mapping = eng.backend.cheat()[0]
72 | for key in mapping:
73 | assert mapping[key] == key
74 | All(Measure) | qureg
75 | eng.flush()
76 | assert np.allclose(wavefunction, f_state, rtol=1e-10, atol=1e-10)
77 |
--------------------------------------------------------------------------------
/projectq/backends/_sim/_cppsim.cpp:
--------------------------------------------------------------------------------
1 | // Licensed under the Apache License, Version 2.0 (the "License");
2 | // you may not use this file except in compliance with the License.
3 | // You may obtain a copy of the License at
4 | //
5 | // http://www.apache.org/licenses/LICENSE-2.0
6 | //
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 |
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #if defined(_OPENMP)
22 | #include
23 | #endif
24 | #include "_cppkernels/simulator.hpp"
25 |
26 | namespace py = pybind11;
27 |
28 | using c_type = std::complex;
29 | using ArrayType = std::vector>;
30 | using MatrixType = std::vector;
31 | using QuRegs = std::vector>;
32 |
33 | template
34 | void emulate_math_wrapper(Simulator &sim, py::function const& pyfunc, QR const& qr, std::vector const& ctrls){
35 | auto f = [&](std::vector& x) {
36 | pybind11::gil_scoped_acquire acquire;
37 | x = pyfunc(x).cast>();
38 | };
39 | pybind11::gil_scoped_release release;
40 | sim.emulate_math(f, qr, ctrls);
41 | }
42 |
43 | PYBIND11_MODULE(_cppsim, m)
44 | {
45 | py::class_(m, "Simulator")
46 | .def(py::init())
47 | .def("allocate_qubit", &Simulator::allocate_qubit)
48 | .def("deallocate_qubit", &Simulator::deallocate_qubit)
49 | .def("get_classical_value", &Simulator::get_classical_value)
50 | .def("is_classical", &Simulator::is_classical)
51 | .def("measure_qubits", &Simulator::measure_qubits_return)
52 | .def("apply_controlled_gate", &Simulator::apply_controlled_gate)
53 | .def("emulate_math", &emulate_math_wrapper)
54 | .def("emulate_math_addConstant", &Simulator::emulate_math_addConstant)
55 | .def("emulate_math_addConstantModN", &Simulator::emulate_math_addConstantModN)
56 | .def("emulate_math_multiplyByConstantModN", &Simulator::emulate_math_multiplyByConstantModN)
57 | .def("get_expectation_value", &Simulator::get_expectation_value)
58 | .def("apply_qubit_operator", &Simulator::apply_qubit_operator)
59 | .def("emulate_time_evolution", &Simulator::emulate_time_evolution)
60 | .def("get_probability", &Simulator::get_probability)
61 | .def("get_amplitude", &Simulator::get_amplitude)
62 | .def("set_wavefunction", &Simulator::set_wavefunction)
63 | .def("collapse_wavefunction", &Simulator::collapse_wavefunction)
64 | .def("run", &Simulator::run)
65 | .def("cheat", &Simulator::cheat)
66 | ;
67 | }
68 |
--------------------------------------------------------------------------------
/projectq/setups/ibm_test.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """Tests for projectq.setup.ibm."""
15 |
16 | import pytest
17 |
18 |
19 | def test_ibm_cnot_mapper_in_cengines(monkeypatch):
20 | import projectq.setups.ibm
21 |
22 | def mock_show_devices(*args, **kwargs):
23 | connections = {
24 | (0, 1),
25 | (1, 0),
26 | (1, 2),
27 | (1, 3),
28 | (1, 4),
29 | (2, 1),
30 | (2, 3),
31 | (2, 4),
32 | (3, 1),
33 | (3, 4),
34 | (4, 3),
35 | }
36 | return {
37 | 'ibmq_burlington': {
38 | 'coupling_map': connections,
39 | 'version': '0.0.0',
40 | 'nq': 5,
41 | },
42 | 'ibmq_16_melbourne': {
43 | 'coupling_map': connections,
44 | 'version': '0.0.0',
45 | 'nq': 15,
46 | },
47 | 'ibmq_qasm_simulator': {
48 | 'coupling_map': connections,
49 | 'version': '0.0.0',
50 | 'nq': 32,
51 | },
52 | }
53 |
54 | monkeypatch.setattr(projectq.setups.ibm, "show_devices", mock_show_devices)
55 | engines_5qb = projectq.setups.ibm.get_engine_list(device='ibmq_burlington')
56 | engines_15qb = projectq.setups.ibm.get_engine_list(device='ibmq_16_melbourne')
57 | engines_simulator = projectq.setups.ibm.get_engine_list(device='ibmq_qasm_simulator')
58 | assert len(engines_5qb) == 15
59 | assert len(engines_15qb) == 16
60 | assert len(engines_simulator) == 13
61 |
62 |
63 | def test_ibm_errors(monkeypatch):
64 | import projectq.setups.ibm
65 |
66 | def mock_show_devices(*args, **kwargs):
67 | connections = {
68 | (0, 1),
69 | (1, 0),
70 | (1, 2),
71 | (1, 3),
72 | (1, 4),
73 | (2, 1),
74 | (2, 3),
75 | (2, 4),
76 | (3, 1),
77 | (3, 4),
78 | (4, 3),
79 | }
80 | return {'ibmq_imaginary': {'coupling_map': connections, 'version': '0.0.0', 'nq': 6}}
81 |
82 | monkeypatch.setattr(projectq.setups.ibm, "show_devices", mock_show_devices)
83 | with pytest.raises(projectq.setups.ibm.DeviceOfflineError):
84 | projectq.setups.ibm.get_engine_list(device='ibmq_burlington')
85 | with pytest.raises(projectq.setups.ibm.DeviceNotHandledError):
86 | projectq.setups.ibm.get_engine_list(device='ibmq_imaginary')
87 |
--------------------------------------------------------------------------------
/projectq/setups/aqt.py:
--------------------------------------------------------------------------------
1 | # Copyright 2020 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """
16 | A setup for AQT trapped ion devices.
17 |
18 | Defines a setup allowing to compile code for the AQT trapped ion devices:
19 | ->The 4 qubits device
20 | ->The 11 qubits simulator
21 | ->The 11 qubits noisy simulator
22 |
23 | It provides the `engine_list` for the `MainEngine' based on the requested
24 | device. Decompose the circuit into a Rx/Ry/Rxx gate set that will be
25 | translated in the backend in the Rx/Ry/MS gate set.
26 | """
27 |
28 | from projectq.backends._aqt._aqt_http_client import show_devices
29 | from projectq.backends._exceptions import DeviceNotHandledError, DeviceOfflineError
30 | from projectq.cengines import BasicMapperEngine
31 | from projectq.ops import Barrier, Rx, Rxx, Ry
32 | from projectq.setups import restrictedgateset
33 |
34 |
35 | def get_engine_list(token=None, device=None):
36 | """Return the default list of compiler engine for the AQT platform."""
37 | # Access to the hardware properties via show_devices
38 | # Can also be extended to take into account gate fidelities, new available
39 | # gate, etc..
40 | devices = show_devices(token)
41 | aqt_setup = []
42 | if device not in devices:
43 | raise DeviceOfflineError('Error when configuring engine list: device requested for Backend not connected')
44 | if device == 'aqt_simulator':
45 | # The 11 qubit online simulator doesn't need a specific mapping for
46 | # gates. Can also run wider gateset but this setup keep the
47 | # restrictedgateset setup for coherence
48 | mapper = BasicMapperEngine()
49 | # Note: Manual Mapper doesn't work, because its map is updated only if
50 | # gates are applied if gates in the register are not used, then it
51 | # will lead to state errors
52 | res = {}
53 | for i in range(devices[device]['nq']):
54 | res[i] = i
55 | mapper.current_mapping = res
56 | aqt_setup = [mapper]
57 | else:
58 | # If there is an online device not handled into ProjectQ it's not too
59 | # bad, the engine_list can be constructed manually with the
60 | # appropriate mapper and the 'coupling_map' parameter
61 | raise DeviceNotHandledError('Device not yet fully handled by ProjectQ')
62 |
63 | # Most gates need to be decomposed into a subset that is manually converted
64 | # in the backend (until the implementation of the U1,U2,U3)
65 | setup = restrictedgateset.get_engine_list(one_qubit_gates=(Rx, Ry), two_qubit_gates=(Rxx,), other_gates=(Barrier,))
66 | setup.extend(aqt_setup)
67 | return setup
68 |
--------------------------------------------------------------------------------
/projectq/libs/revkit/_permutation_test.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | """Tests for libs.revkit._permutation."""
15 |
16 | import pytest
17 |
18 | from projectq import MainEngine
19 | from projectq.cengines import DummyEngine
20 | from projectq.libs.revkit import PermutationOracle
21 |
22 | # run this test only if RevKit Python module can be loaded
23 | revkit = pytest.importorskip('revkit')
24 |
25 |
26 | def test_basic_permutation():
27 | saving_backend = DummyEngine(save_commands=True)
28 | main_engine = MainEngine(backend=saving_backend, engine_list=[DummyEngine()])
29 |
30 | qubit0 = main_engine.allocate_qubit()
31 | qubit1 = main_engine.allocate_qubit()
32 |
33 | PermutationOracle([0, 2, 1, 3]) | (qubit0, qubit1)
34 |
35 | assert len(saving_backend.received_commands) == 5
36 |
37 |
38 | def test_invalid_permutation():
39 | main_engine = MainEngine(backend=DummyEngine(), engine_list=[DummyEngine()])
40 |
41 | qubit0 = main_engine.allocate_qubit()
42 | qubit1 = main_engine.allocate_qubit()
43 |
44 | with pytest.raises(AttributeError):
45 | PermutationOracle([1, 2, 3, 4]) | (qubit0, qubit1)
46 |
47 | with pytest.raises(AttributeError):
48 | PermutationOracle([0, 2, 3, 4]) | (qubit0, qubit1)
49 |
50 | with pytest.raises(AttributeError):
51 | PermutationOracle([0, 1, 1, 2]) | (qubit0, qubit1)
52 |
53 | with pytest.raises(AttributeError):
54 | PermutationOracle([0, 1, 2]) | (qubit0, qubit1)
55 |
56 | with pytest.raises(AttributeError):
57 | PermutationOracle([0, 1, 2, 3, 4]) | (qubit0, qubit1)
58 |
59 |
60 | def test_synthesis_with_adjusted_tbs():
61 | saving_backend = DummyEngine(save_commands=True)
62 | main_engine = MainEngine(backend=saving_backend, engine_list=[DummyEngine()])
63 |
64 | qubit0 = main_engine.allocate_qubit()
65 | qubit1 = main_engine.allocate_qubit()
66 |
67 | def synth():
68 | import revkit
69 |
70 | return revkit.tbs()
71 |
72 | PermutationOracle([0, 2, 1, 3], synth=synth) | (qubit0, qubit1)
73 |
74 | assert len(saving_backend.received_commands) == 5
75 |
76 |
77 | def test_synthesis_with_synthesis_script():
78 | saving_backend = DummyEngine(save_commands=True)
79 | main_engine = MainEngine(backend=saving_backend, engine_list=[DummyEngine()])
80 |
81 | qubit0 = main_engine.allocate_qubit()
82 | qubit1 = main_engine.allocate_qubit()
83 |
84 | def synth():
85 | import revkit
86 |
87 | revkit.tbs()
88 |
89 | PermutationOracle([0, 2, 1, 3], synth=synth) | (qubit0, qubit1)
90 |
91 | assert len(saving_backend.received_commands) == 5
92 |
--------------------------------------------------------------------------------
/projectq/backends/_sim/_cppkernels/intrin/kernel2.hpp:
--------------------------------------------------------------------------------
1 | // Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | template
16 | inline void kernel_core(V &psi, std::size_t I, std::size_t d0, std::size_t d1, M const& m, M const& mt)
17 | {
18 | __m256d v[4];
19 |
20 | v[0] = load2(&psi[I]);
21 | v[1] = load2(&psi[I + d0]);
22 | v[2] = load2(&psi[I + d1]);
23 | v[3] = load2(&psi[I + d0 + d1]);
24 |
25 | _mm256_storeu2_m128d((double*)&psi[I + d0], (double*)&psi[I], add(mul(v[0], m[0], mt[0]), add(mul(v[1], m[1], mt[1]), add(mul(v[2], m[2], mt[2]), mul(v[3], m[3], mt[3])))));
26 | _mm256_storeu2_m128d((double*)&psi[I + d0 + d1], (double*)&psi[I + d1], add(mul(v[0], m[4], mt[4]), add(mul(v[1], m[5], mt[5]), add(mul(v[2], m[6], mt[6]), mul(v[3], m[7], mt[7])))));
27 |
28 | }
29 |
30 | // bit indices id[.] are given from high to low (e.g. control first for CNOT)
31 | template
32 | void kernel(V &psi, unsigned id1, unsigned id0, M const& m, std::size_t ctrlmask)
33 | {
34 | std::size_t n = psi.size();
35 | std::size_t d0 = 1UL << id0;
36 | std::size_t d1 = 1UL << id1;
37 |
38 | __m256d mm[] = {load(&m[0][0], &m[1][0]), load(&m[0][1], &m[1][1]), load(&m[0][2], &m[1][2]), load(&m[0][3], &m[1][3]), load(&m[2][0], &m[3][0]), load(&m[2][1], &m[3][1]), load(&m[2][2], &m[3][2]), load(&m[2][3], &m[3][3])};
39 | __m256d mmt[8];
40 |
41 | __m256d neg = _mm256_setr_pd(1.0, -1.0, 1.0, -1.0);
42 | for (unsigned i = 0; i < 8; ++i){
43 | auto badc = _mm256_permute_pd(mm[i], 5);
44 | mmt[i] = _mm256_mul_pd(badc, neg);
45 | }
46 |
47 | std::size_t dsorted[] = {d0 , d1};
48 | std::sort(dsorted, dsorted + 2, std::greater());
49 |
50 | if (ctrlmask == 0){
51 | #pragma omp for collapse(LOOP_COLLAPSE2) schedule(static)
52 | for (std::size_t i0 = 0; i0 < n; i0 += 2 * dsorted[0]){
53 | for (std::size_t i1 = 0; i1 < dsorted[0]; i1 += 2 * dsorted[1]){
54 | for (std::size_t i2 = 0; i2 < dsorted[1]; ++i2){
55 | kernel_core(psi, i0 + i1 + i2, d0, d1, mm, mmt);
56 | }
57 | }
58 | }
59 | }
60 | else{
61 | #pragma omp for collapse(LOOP_COLLAPSE2) schedule(static)
62 | for (std::size_t i0 = 0; i0 < n; i0 += 2 * dsorted[0]){
63 | for (std::size_t i1 = 0; i1 < dsorted[0]; i1 += 2 * dsorted[1]){
64 | for (std::size_t i2 = 0; i2 < dsorted[1]; ++i2){
65 | if (((i0 + i1 + i2)&ctrlmask) == ctrlmask)
66 | kernel_core(psi, i0 + i1 + i2, d0, d1, mm, mmt);
67 | }
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/projectq/cengines/_replacer/_decomposition_rule.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """Module containing the definition of a decomposition rule."""
16 |
17 | from projectq.ops import BasicGate
18 |
19 |
20 | class ThisIsNotAGateClassError(TypeError):
21 | """Exception raised when a gate instance is encountered instead of a gate class in a decomposition rule."""
22 |
23 |
24 | class DecompositionRule: # pylint: disable=too-few-public-methods
25 | """A rule for breaking down specific gates into sequences of simpler gates."""
26 |
27 | def __init__(self, gate_class, gate_decomposer, gate_recognizer=lambda cmd: True):
28 | """
29 | Initialize a DecompositionRule object.
30 |
31 | Args:
32 | gate_class (type): The type of gate that this rule decomposes.
33 |
34 | The gate class is redundant information used to make lookups faster when iterating over a circuit and
35 | deciding "which rules apply to this gate?" again and again.
36 |
37 | Note that this parameter is a gate type, not a gate instance. You supply gate_class=MyGate or
38 | gate_class=MyGate().__class__, not gate_class=MyGate().
39 |
40 | gate_decomposer (function[projectq.ops.Command]): Function which, given the command to decompose, applies
41 | a sequence of gates corresponding to the high-level function of a gate of type gate_class.
42 |
43 | gate_recognizer (function[projectq.ops.Command] : boolean): A predicate that determines if the
44 | decomposition applies to the given command (on top of the filtering by gate_class).
45 |
46 | For example, a decomposition rule may only to apply rotation gates that rotate by a specific angle.
47 |
48 | If no gate_recognizer is given, the decomposition applies to all gates matching the gate_class.
49 | """
50 | # Check for common gate_class type mistakes.
51 | if isinstance(gate_class, BasicGate):
52 | raise ThisIsNotAGateClassError(
53 | "gate_class is a gate instance instead of a type of BasicGate."
54 | "\nDid you pass in someGate instead of someGate.__class__?"
55 | )
56 | if gate_class == type.__class__:
57 | raise ThisIsNotAGateClassError(
58 | "gate_class is type.__class__ instead of a type of BasicGate."
59 | "\nDid you pass in GateType.__class__ instead of GateType?"
60 | )
61 |
62 | self.gate_class = gate_class
63 | self.gate_decomposer = gate_decomposer
64 | self.gate_recognizer = gate_recognizer
65 |
--------------------------------------------------------------------------------
/projectq/setups/decompositions/rx2rz_test.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | "Tests for projectq.setups.decompositions.rx2rz.py"
16 |
17 | import math
18 |
19 | import pytest
20 |
21 | from projectq.backends import Simulator
22 | from projectq.cengines import (
23 | AutoReplacer,
24 | DecompositionRuleSet,
25 | DummyEngine,
26 | InstructionFilter,
27 | MainEngine,
28 | )
29 | from projectq.meta import Control
30 | from projectq.ops import Measure, Rx
31 |
32 | from . import rx2rz
33 |
34 |
35 | def test_recognize_correct_gates():
36 | saving_backend = DummyEngine(save_commands=True)
37 | eng = MainEngine(backend=saving_backend)
38 | qubit = eng.allocate_qubit()
39 | ctrl_qubit = eng.allocate_qubit()
40 | eng.flush()
41 | Rx(0.3) | qubit
42 | with Control(eng, ctrl_qubit):
43 | Rx(0.4) | qubit
44 | eng.flush(deallocate_qubits=True)
45 | assert rx2rz._recognize_RxNoCtrl(saving_backend.received_commands[3])
46 | assert not rx2rz._recognize_RxNoCtrl(saving_backend.received_commands[4])
47 |
48 |
49 | def rx_decomp_gates(eng, cmd):
50 | g = cmd.gate
51 | if isinstance(g, Rx):
52 | return False
53 | else:
54 | return True
55 |
56 |
57 | @pytest.mark.parametrize("angle", [0, math.pi, 2 * math.pi, 4 * math.pi, 0.5])
58 | def test_decomposition(angle):
59 | for basis_state in ([1, 0], [0, 1]):
60 | correct_dummy_eng = DummyEngine(save_commands=True)
61 | correct_eng = MainEngine(backend=Simulator(), engine_list=[correct_dummy_eng])
62 |
63 | rule_set = DecompositionRuleSet(modules=[rx2rz])
64 | test_dummy_eng = DummyEngine(save_commands=True)
65 | test_eng = MainEngine(
66 | backend=Simulator(),
67 | engine_list=[
68 | AutoReplacer(rule_set),
69 | InstructionFilter(rx_decomp_gates),
70 | test_dummy_eng,
71 | ],
72 | )
73 |
74 | correct_qb = correct_eng.allocate_qubit()
75 | Rx(angle) | correct_qb
76 | correct_eng.flush()
77 |
78 | test_qb = test_eng.allocate_qubit()
79 | Rx(angle) | test_qb
80 | test_eng.flush()
81 |
82 | assert correct_dummy_eng.received_commands[1].gate == Rx(angle)
83 | assert test_dummy_eng.received_commands[1].gate != Rx(angle)
84 |
85 | for fstate in ['0', '1']:
86 | test = test_eng.backend.get_amplitude(fstate, test_qb)
87 | correct = correct_eng.backend.get_amplitude(fstate, correct_qb)
88 | assert correct == pytest.approx(test, rel=1e-12, abs=1e-12)
89 |
90 | Measure | test_qb
91 | Measure | correct_qb
92 |
--------------------------------------------------------------------------------
/projectq/setups/decompositions/ry2rz_test.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | "Tests for projectq.setups.decompositions.ry2rz.py"
16 |
17 | import math
18 |
19 | import pytest
20 |
21 | from projectq.backends import Simulator
22 | from projectq.cengines import (
23 | AutoReplacer,
24 | DecompositionRuleSet,
25 | DummyEngine,
26 | InstructionFilter,
27 | MainEngine,
28 | )
29 | from projectq.meta import Control
30 | from projectq.ops import Measure, Ry
31 |
32 | from . import ry2rz
33 |
34 |
35 | def test_recognize_correct_gates():
36 | saving_backend = DummyEngine(save_commands=True)
37 | eng = MainEngine(backend=saving_backend)
38 | qubit = eng.allocate_qubit()
39 | ctrl_qubit = eng.allocate_qubit()
40 | eng.flush()
41 | Ry(0.3) | qubit
42 | with Control(eng, ctrl_qubit):
43 | Ry(0.4) | qubit
44 | eng.flush(deallocate_qubits=True)
45 | assert ry2rz._recognize_RyNoCtrl(saving_backend.received_commands[3])
46 | assert not ry2rz._recognize_RyNoCtrl(saving_backend.received_commands[4])
47 |
48 |
49 | def ry_decomp_gates(eng, cmd):
50 | g = cmd.gate
51 | if isinstance(g, Ry):
52 | return False
53 | else:
54 | return True
55 |
56 |
57 | @pytest.mark.parametrize("angle", [0, math.pi, 2 * math.pi, 4 * math.pi, 0.5])
58 | def test_decomposition(angle):
59 | for basis_state in ([1, 0], [0, 1]):
60 | correct_dummy_eng = DummyEngine(save_commands=True)
61 | correct_eng = MainEngine(backend=Simulator(), engine_list=[correct_dummy_eng])
62 |
63 | rule_set = DecompositionRuleSet(modules=[ry2rz])
64 | test_dummy_eng = DummyEngine(save_commands=True)
65 | test_eng = MainEngine(
66 | backend=Simulator(),
67 | engine_list=[
68 | AutoReplacer(rule_set),
69 | InstructionFilter(ry_decomp_gates),
70 | test_dummy_eng,
71 | ],
72 | )
73 |
74 | correct_qb = correct_eng.allocate_qubit()
75 | Ry(angle) | correct_qb
76 | correct_eng.flush()
77 |
78 | test_qb = test_eng.allocate_qubit()
79 | Ry(angle) | test_qb
80 | test_eng.flush()
81 |
82 | assert correct_dummy_eng.received_commands[1].gate == Ry(angle)
83 | assert test_dummy_eng.received_commands[1].gate != Ry(angle)
84 |
85 | for fstate in ['0', '1']:
86 | test = test_eng.backend.get_amplitude(fstate, test_qb)
87 | correct = correct_eng.backend.get_amplitude(fstate, correct_qb)
88 | assert correct == pytest.approx(test, rel=1e-12, abs=1e-12)
89 |
90 | Measure | test_qb
91 | Measure | correct_qb
92 |
--------------------------------------------------------------------------------
/examples/gate_zoo.py:
--------------------------------------------------------------------------------
1 | # pylint: skip-file
2 |
3 | """Showcase most of the quantum gates available in ProjectQ."""
4 |
5 | import os
6 | import sys
7 |
8 | from projectq import MainEngine
9 | from projectq.backends import CircuitDrawer
10 | from projectq.ops import (
11 | CNOT,
12 | QFT,
13 | All,
14 | Barrier,
15 | BasicMathGate,
16 | C,
17 | Entangle,
18 | H,
19 | Measure,
20 | Ph,
21 | QubitOperator,
22 | Rx,
23 | Ry,
24 | Rz,
25 | S,
26 | SqrtSwap,
27 | SqrtX,
28 | Swap,
29 | T,
30 | Tensor,
31 | TimeEvolution,
32 | Toffoli,
33 | X,
34 | Y,
35 | Z,
36 | get_inverse,
37 | )
38 |
39 |
40 | def zoo_profile():
41 | """Generate and display the zoo of quantum gates."""
42 | # create a main compiler engine with a drawing backend
43 | drawing_engine = CircuitDrawer()
44 | locations = {0: 1, 1: 2, 2: 0, 3: 3}
45 | drawing_engine.set_qubit_locations(locations)
46 | main_eng = MainEngine(drawing_engine)
47 | qureg = main_eng.allocate_qureg(4)
48 |
49 | # define a zoo of gates
50 | te_gate = TimeEvolution(0.5, 0.1 * QubitOperator('X0 Y2'))
51 |
52 | def add(x, y):
53 | return x, y + 1
54 |
55 | zoo = [
56 | (X, 3),
57 | (Y, 2),
58 | (Z, 0),
59 | (Rx(0.5), 2),
60 | (Ry(0.5), 1),
61 | (Rz(0.5), 1),
62 | (Ph(0.5), 0),
63 | (S, 3),
64 | (T, 2),
65 | (H, 1),
66 | (Toffoli, (0, 1, 2)),
67 | (Barrier, None),
68 | (Swap, (0, 3)),
69 | (SqrtSwap, (0, 1)),
70 | (get_inverse(SqrtSwap), (2, 3)),
71 | (SqrtX, 2),
72 | (C(get_inverse(SqrtX)), (0, 2)),
73 | (C(Ry(0.5)), (2, 3)),
74 | (CNOT, (2, 1)),
75 | (Entangle, None),
76 | (te_gate, None),
77 | (QFT, None),
78 | (Tensor(H), None),
79 | (BasicMathGate(add), (2, 3)),
80 | (All(Measure), None),
81 | ]
82 |
83 | # apply them
84 | for gate, pos in zoo:
85 | if pos is None:
86 | gate | qureg
87 | elif isinstance(pos, tuple):
88 | gate | tuple(qureg[i] for i in pos)
89 | else:
90 | gate | qureg[pos]
91 |
92 | main_eng.flush()
93 |
94 | # generate latex code to draw the circuit
95 | s = drawing_engine.get_latex()
96 | prefix = 'zoo'
97 | with open(f'{prefix}.tex', 'w') as f:
98 | f.write(s)
99 |
100 | # compile latex source code and open pdf file
101 | os.system(f'pdflatex {prefix}.tex')
102 | openfile(f'{prefix}.pdf')
103 |
104 |
105 | def openfile(filename):
106 | """
107 | Open a file.
108 |
109 | Args:
110 | filename (str): the target file.
111 |
112 | Return:
113 | bool: succeed if True.
114 | """
115 | platform = sys.platform
116 | if platform == "linux" or platform == "linux2":
117 | os.system('xdg-open %s' % filename)
118 | elif platform == "darwin":
119 | os.system('open %s' % filename)
120 | elif platform == "win32":
121 | os.startfile(filename)
122 | else:
123 | print('Can not open file, platform %s not handled!' % platform)
124 | return False
125 | return True
126 |
127 |
128 | if __name__ == "__main__":
129 | zoo_profile()
130 |
--------------------------------------------------------------------------------
/projectq/tests/_factoring_test.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 ProjectQ-Framework (www.projectq.ch)
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import pytest
16 |
17 | import projectq.libs.math
18 | import projectq.setups.decompositions
19 | from projectq.backends._sim._simulator_test import sim
20 | from projectq.cengines import (
21 | AutoReplacer,
22 | DecompositionRuleSet,
23 | InstructionFilter,
24 | LocalOptimizer,
25 | MainEngine,
26 | TagRemover,
27 | )
28 | from projectq.libs.math import MultiplyByConstantModN
29 | from projectq.meta import Control
30 | from projectq.ops import QFT, All, BasicMathGate, H, Measure, Swap, X, get_inverse
31 |
32 | rule_set = DecompositionRuleSet(modules=(projectq.libs.math, projectq.setups.decompositions))
33 |
34 | assert sim # Asserts to tools that the fixture import is used.
35 |
36 |
37 | def high_level_gates(eng, cmd):
38 | g = cmd.gate
39 | if g == QFT or get_inverse(g) == QFT or g == Swap:
40 | return True
41 | if isinstance(g, BasicMathGate):
42 | return False
43 | return eng.next_engine.is_available(cmd)
44 |
45 |
46 | def get_main_engine(sim):
47 | engine_list = [
48 | AutoReplacer(rule_set),
49 | InstructionFilter(high_level_gates),
50 | TagRemover(),
51 | LocalOptimizer(3),
52 | AutoReplacer(rule_set),
53 | TagRemover(),
54 | LocalOptimizer(3),
55 | ]
56 | return MainEngine(sim, engine_list)
57 |
58 |
59 | def test_factoring(sim):
60 | eng = get_main_engine(sim)
61 |
62 | ctrl_qubit = eng.allocate_qubit()
63 |
64 | N = 15
65 | a = 2
66 |
67 | x = eng.allocate_qureg(4)
68 | X | x[0]
69 |
70 | H | ctrl_qubit
71 | with Control(eng, ctrl_qubit):
72 | MultiplyByConstantModN(pow(a, 2**7, N), N) | x
73 |
74 | H | ctrl_qubit
75 | eng.flush()
76 | cheat_tpl = sim.cheat()
77 | idx = cheat_tpl[0][ctrl_qubit[0].id]
78 | vec = cheat_tpl[1]
79 |
80 | for i in range(len(vec)):
81 | if abs(vec[i]) > 1.0e-8:
82 | assert ((i >> idx) & 1) == 0
83 |
84 | Measure | ctrl_qubit
85 | assert int(ctrl_qubit) == 0
86 | del vec, cheat_tpl
87 |
88 | H | ctrl_qubit
89 | with Control(eng, ctrl_qubit):
90 | MultiplyByConstantModN(pow(a, 2, N), N) | x
91 |
92 | H | ctrl_qubit
93 | eng.flush()
94 | cheat_tpl = sim.cheat()
95 | idx = cheat_tpl[0][ctrl_qubit[0].id]
96 | vec = cheat_tpl[1]
97 |
98 | probability = 0.0
99 | for i in range(len(vec)):
100 | if abs(vec[i]) > 1.0e-8:
101 | if ((i >> idx) & 1) == 0:
102 | probability += abs(vec[i]) ** 2
103 |
104 | assert probability == pytest.approx(0.5)
105 |
106 | Measure | ctrl_qubit
107 | All(Measure) | x
108 |
--------------------------------------------------------------------------------