├── .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 | --------------------------------------------------------------------------------