From d094c05155510cfea08a0b40b38e2b0d491b7b7d Mon Sep 17 00:00:00 2001 From: Juan Gomez Date: Thu, 14 Nov 2019 15:04:51 +0100 Subject: [PATCH 01/12] Rotate changelog --- CHANGELOG.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ebf713b28..544dc31639 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,9 +15,24 @@ Changelog](http://keepachangelog.com/en/1.0.0/). > - **Fixed**: for any bug fixes. > - **Security**: in case of vulnerabilities. -[UNRELEASED](https://github.com/Qiskit/qiskit-aer/compare/0.3.2...HEAD) +[UNRELEASED](https://github.com/Qiskit/qiskit-aer/compare/0.3.3...HEAD) ======================================================================= +Added +----- + +Changed +------- + +Removed +------- + +Fixed +----- + +[0.3.3](https://github.com/Qiskit/qiskit-aer/compare/0.3.2...0.3.3) - 2019-11-14 +==================================================================================== + Added ----- - Added controlled gates (``cu1``, ``cu2``, ``cu3``) to simulator basis_gates (\#417) From 2fcc16fb16c20ccbff3521f2117cdfdcdab0541f Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Thu, 14 Nov 2019 11:37:57 -0500 Subject: [PATCH 02/12] Switch to running tests in parallel with stestr This commit switches the test runner for running the aer tests to stestr. stestr is a unittest compatible test runner that executes tests in parallel by default. This can provide significant speeds ups for running a test suite. It also provides a rich set of scheduling [1] and test selection [2] features which we can use to fine tune how we execute tests. [1] https://stestr.readthedocs.io/en/stable/MANUAL.html#test-scheduling [2] https://stestr.readthedocs.io/en/stable/MANUAL.html#test-selection --- .gitignore | 1 + .stestr.conf | 3 +++ .travis.yml | 21 ++++++++++++++++++--- azure-pipelines.yml | 2 +- requirements-dev.txt | 1 + tox.ini | 12 +++++++++++- 6 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 .stestr.conf diff --git a/.gitignore b/.gitignore index c0ae8d0b94..14c1bba494 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ contrib/standalone/version.hpp test/.asv .tox/ +.stestr/ docs/_build/ docs/stubs/ diff --git a/.stestr.conf b/.stestr.conf new file mode 100644 index 0000000000..becd85f436 --- /dev/null +++ b/.stestr.conf @@ -0,0 +1,3 @@ +[DEFAULT] +test_path=./test/terra +group_regex=(test.terra.backends.test_qasm_matrix_product_state|test.terra.backends.test_qasm_mps_simulator) diff --git a/.travis.yml b/.travis.yml index ad4a02e9ec..5148ad6c47 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,10 @@ notifications: email: false -cache: pip +cache: + pip: true + directories: + - .stestr sudo: false ############################################################################### @@ -42,10 +45,15 @@ stage_linux: &stage_linux - sudo apt-get -y update - sudo apt-get -y install g++-7 - sudo apt-get -y install libopenblas-dev + before_script: + - | + if [ ! "$(ls -A .stestr)" ]; then + rm -rf .stestr + fi script: - python setup.py bdist_wheel -- -DCMAKE_CXX_COMPILER=g++-7 -- -j4 - pip install dist/qiskit_aer*whl - - python -m unittest discover -s test -v + - stestr run stage_osx: &stage_osx <<: *stage_generic @@ -56,6 +64,7 @@ stage_osx: &stage_osx pip: true directories: - ~/python-interpreters/ + - .stestr before_install: # Travis does not provide support for Python 3 under osx - it needs to be # installed manually. @@ -71,10 +80,16 @@ stage_osx: &stage_osx virtualenv --python ~/python-interpreters/$PYTHON_VERSION/bin/python venv source venv/bin/activate fi + before_script: + - | + if [ ! "$(ls -A .stestr)" ]; then + rm -rf .stestr + fi + script: - python setup.py bdist_wheel -- -- -j4 - pip install dist/qiskit_aer*whl - - python -m unittest discover -s test -v + - stestr run ############################################################################### # Stage-related definitions diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 7e45c0c7b2..cd9e7fa8bb 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -75,5 +75,5 @@ jobs: set -e source activate qiskit-aer-$(Build.BuildNumber) pip install dist/qiskit_aer*.whl - python -m unittest discover -s test/terra -v + stestr run displayName: 'Install Aer and Run Tests' diff --git a/requirements-dev.txt b/requirements-dev.txt index fe871be83e..3ad3901704 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -10,3 +10,4 @@ Sphinx>=1.8.3 sphinx-rtd-theme>=0.4.0 sphinx-tabs>=1.1.11 jupyter-sphinx +stestr>=2.5.0 diff --git a/tox.ini b/tox.ini index d147f493ee..aa2c0b1f0d 100644 --- a/tox.ini +++ b/tox.ini @@ -15,7 +15,17 @@ deps = commands = python setup.py bdist_wheel -- -- -j4 pip install --find-links={toxinidir}/dist qiskit_aer - python -m unittest discover -s test -v + stestr run {posargs} + +[testenv:coverage] +basepython = python3 +setenv = + {[testenv]setenv} + PYTHON=coverage3 run --source qiskit --parallel-mode +commands = + stestr run {posargs} + coverage3 combine + coverage3 report [testenv:lint] deps = From 9b290bf419702446b7c16389fbde7aff44f6bdd0 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Thu, 14 Nov 2019 14:27:33 -0500 Subject: [PATCH 03/12] Add slowest flag to see if there are slow outliers --- .travis.yml | 4 ++-- azure-pipelines.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5148ad6c47..83f0206ed5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -53,7 +53,7 @@ stage_linux: &stage_linux script: - python setup.py bdist_wheel -- -DCMAKE_CXX_COMPILER=g++-7 -- -j4 - pip install dist/qiskit_aer*whl - - stestr run + - stestr run --slowest stage_osx: &stage_osx <<: *stage_generic @@ -89,7 +89,7 @@ stage_osx: &stage_osx script: - python setup.py bdist_wheel -- -- -j4 - pip install dist/qiskit_aer*whl - - stestr run + - stestr run --slowest ############################################################################### # Stage-related definitions diff --git a/azure-pipelines.yml b/azure-pipelines.yml index cd9e7fa8bb..22c9907c09 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -75,5 +75,5 @@ jobs: set -e source activate qiskit-aer-$(Build.BuildNumber) pip install dist/qiskit_aer*.whl - stestr run + stestr run --slowest displayName: 'Install Aer and Run Tests' From 692c33f3a937a9db830cbe31cebbc8a01f511379 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Thu, 14 Nov 2019 14:47:30 -0500 Subject: [PATCH 04/12] Switch group regex to parallel-class --- .stestr.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stestr.conf b/.stestr.conf index becd85f436..07d513239d 100644 --- a/.stestr.conf +++ b/.stestr.conf @@ -1,3 +1,3 @@ [DEFAULT] test_path=./test/terra -group_regex=(test.terra.backends.test_qasm_matrix_product_state|test.terra.backends.test_qasm_mps_simulator) +parallel_class=True From 6697a5bc3b10b26d7a11de25343ab6b49900d253 Mon Sep 17 00:00:00 2001 From: kurarrr Date: Tue, 19 Nov 2019 15:14:32 +0900 Subject: [PATCH 05/12] Added Benchmarks for Fusion Optimization * Quantum Fourier Transformation * Randomly generated benchmarks Co-authored-by: Stefan Hillmich Co-authored-by: Ryota Yonekura --- src/transpile/fusion.hpp | 6 +- test/asv.linux.conf.json | 4 +- test/benchmark/fusion_benchmarks.py | 110 ++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 test/benchmark/fusion_benchmarks.py diff --git a/src/transpile/fusion.hpp b/src/transpile/fusion.hpp index 7e7614f35f..de627768ac 100644 --- a/src/transpile/fusion.hpp +++ b/src/transpile/fusion.hpp @@ -174,8 +174,7 @@ void Fusion::optimize_circuit(Circuit& circ, const opset_t &allowed_opset, ExperimentData &data) const { - if (circ.num_qubits < threshold_ - || !active_) + if (circ.num_qubits < threshold_ || !active_) return; bool applied = false; @@ -190,8 +189,7 @@ void Fusion::optimize_circuit(Circuit& circ, } } - if (fusion_start < circ.ops.size() - && aggregate_operations(circ.ops, fusion_start, circ.ops.size())) + if (fusion_start < circ.ops.size() && aggregate_operations(circ.ops, fusion_start, circ.ops.size())) applied = true; if (applied) { diff --git a/test/asv.linux.conf.json b/test/asv.linux.conf.json index f5dffc0bb1..3be6cc22d1 100644 --- a/test/asv.linux.conf.json +++ b/test/asv.linux.conf.json @@ -31,8 +31,8 @@ // ], "install_command": [ - "python -c \"import shutil; shutil.rmtree('{build_dir}/qiskit')\"", - "python -c \"import shutil; shutil.rmtree('{build_dir}/qiskit_aer.egg-info')\"", + "python -c \"import shutil; shutil.rmtree('{build_dir}/qiskit', True)\"", + "python -c \"import shutil; shutil.rmtree('{build_dir}/qiskit_aer.egg-info', True)\"", "python -mpip install {wheel_file}" ], "uninstall_command": [ diff --git a/test/benchmark/fusion_benchmarks.py b/test/benchmark/fusion_benchmarks.py new file mode 100644 index 0000000000..eadc745387 --- /dev/null +++ b/test/benchmark/fusion_benchmarks.py @@ -0,0 +1,110 @@ +import numpy as np +import math +from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit +from qiskit.compiler import assemble +from qiskit.providers.aer import QasmSimulator +from qiskit.quantum_info.random import random_unitary +from qiskit.quantum_info.synthesis import two_qubit_cnot_decompose + + +class QuantumFourierTransformFusionSuite: + def __init__(self): + self.timeout = 60 * 20 + self.backend = QasmSimulator() + num_qubits = [5, 10, 15, 20, 25] + self.circuit = {} + for num_qubit in num_qubits: + for use_cu1 in [True, False]: + circuit = self.qft_circuit(num_qubit, use_cu1) + self.circuit[(num_qubit, use_cu1)] = assemble(circuit, self.backend, shots=1) + self.param_names = ["Quantum Fourier Transform", "Fusion Activated", "Use cu1 gate"] + self.params = (num_qubits, [True, False], [True, False]) + + @staticmethod + def qft_circuit(num_qubit, use_cu1): + qreg = QuantumRegister(num_qubit,"q") + creg = ClassicalRegister(num_qubit, "c") + circuit = QuantumCircuit(qreg, creg) + + for i in range(num_qubit): + circuit.h(qreg[i]) + + for i in range(num_qubit): + for j in range(i): + l = math.pi/float(2**(i-j)) + if use_cu1: + circuit.cu1(l, qreg[i], qreg[j]) + else: + circuit.u1(l/2, qreg[i]) + circuit.cx(qreg[i], qreg[j]) + circuit.u1(-l/2, qreg[j]) + circuit.cx(qreg[i], qreg[j]) + circuit.u1(l/2, qreg[j]) + circuit.h(qreg[i]) + + circuit.barrier() + for i in range(num_qubit): + circuit.measure(qreg[i], creg[i]) + + return circuit + + def time_quantum_fourier_transform(self, num_qubit, fusion_enable, use_cu1): + """ Benchmark QFT """ + result = self.backend.run(self.circuit[(num_qubit, use_cu1)], backend_options={'fusion_enable': fusion_enable}).result() + if result.status != 'COMPLETED': + raise QiskitError("Simulation failed. Status: " + result.status) + + +class RandomFusionSuite: + def __init__(self): + self.timeout = 60 * 20 + self.backend = QasmSimulator() + self.param_names = ["Number of Qubits", "Fusion Activated"] + self.params = ([5, 10, 15, 20, 25], [True, False]) + + @staticmethod + def build_model_circuit_kak(width, depth, seed=None): + """Create quantum volume model circuit on quantum register qreg of given + depth (default depth is equal to width) and random seed. + The model circuits consist of layers of Haar random + elements of U(4) applied between corresponding pairs + of qubits in a random bipartition. + """ + qreg = QuantumRegister(width) + depth = depth or width + + np.random.seed(seed) + circuit = QuantumCircuit(qreg, name="Qvolume: %s by %s, seed: %s" % (width, depth, seed)) + + for _ in range(depth): + # Generate uniformly random permutation Pj of [0...n-1] + perm = np.random.permutation(width) + + # For each pair p in Pj, generate Haar random U(4) + # Decompose each U(4) into CNOT + SU(2) + for k in range(width // 2): + U = random_unitary(4, seed).data + for gate in two_qubit_cnot_decompose(U): + qs = [qreg[int(perm[2 * k + i.index])] for i in gate[1]] + pars = gate[0].params + name = gate[0].name + if name == "cx": + circuit.cx(qs[0], qs[1]) + elif name == "u1": + circuit.u1(pars[0], qs[0]) + elif name == "u2": + circuit.u2(*pars[:2], qs[0]) + elif name == "u3": + circuit.u3(*pars[:3], qs[0]) + elif name == "id": + pass # do nothing + else: + raise Exception("Unexpected gate name: %s" % name) + return circuit + + def time_random_transform(self, num_qubits, fusion_enable): + circ = self.build_model_circuit_kak(num_qubits, num_qubits, 1) + qobj = assemble(circ) + result = self.backend.run(qobj, backend_options={'fusion_enable': fusion_enable}).result() + if result.status != 'COMPLETED': + raise QiskitError("Simulation failed. Status: " + result.status) \ No newline at end of file From fdc961d94686eecf354ad63f4095d221d813ed83 Mon Sep 17 00:00:00 2001 From: merav-aharoni <46567124+merav-aharoni@users.noreply.github.com> Date: Mon, 25 Nov 2019 09:24:47 +0200 Subject: [PATCH 06/12] Cleaned up code for the function that handles 2-qubit gates in MPS (#431) --- .../matrix_product_state_internal.cpp | 136 +++++++++--------- .../matrix_product_state_tensor.hpp | 28 ++-- .../qasm_simulator/qasm_unitary_gate.py | 9 ++ test/terra/reference/ref_unitary_gate.py | 41 ++++++ 4 files changed, 139 insertions(+), 75 deletions(-) diff --git a/src/simulators/matrix_product_state/matrix_product_state_internal.cpp b/src/simulators/matrix_product_state/matrix_product_state_internal.cpp index 853632e0ca..f4e670151a 100644 --- a/src/simulators/matrix_product_state/matrix_product_state_internal.cpp +++ b/src/simulators/matrix_product_state/matrix_product_state_internal.cpp @@ -251,72 +251,76 @@ void MPS::apply_swap(uint_t index_A, uint_t index_B) void MPS::apply_2_qubit_gate(uint_t index_A, uint_t index_B, Gates gate_type, cmatrix_t mat) { - //for MPS - if(index_A + 1 < index_B) - { - apply_swap(index_A,index_B-1); - apply_2_qubit_gate(index_B-1,index_B, gate_type, mat); - apply_swap(index_A,index_B-1); - return; - } - else if(index_A > index_B + 1) - { - apply_swap(index_A-1,index_B); - apply_2_qubit_gate(index_A,index_A-1, gate_type, mat); - apply_swap(index_A-1,index_B); - return; - } - - bool swapped = false; - if(index_A > index_B) - { - std::swap(index_A, index_B); - swapped = true; - } - - MPS_Tensor A = q_reg_[index_A], B = q_reg_[index_B]; - rvector_t left_lambda, right_lambda; - //There is no lambda in the edges of the MPS - left_lambda = (index_A != 0) ? lambda_reg_[index_A-1] : rvector_t {1.0}; - right_lambda = (index_B != num_qubits_-1) ? lambda_reg_[index_B ] : rvector_t {1.0}; - - q_reg_[index_A].mul_Gamma_by_left_Lambda(left_lambda); - q_reg_[index_B].mul_Gamma_by_right_Lambda(right_lambda); - MPS_Tensor temp = MPS_Tensor::contract(q_reg_[index_A], lambda_reg_[index_A], q_reg_[index_B]); - - switch (gate_type) { - case cx: - temp.apply_cnot(swapped); - break; - case cz: - temp.apply_cz(); - break; - case id: - break; - case cu1: - { - cmatrix_t Zeros = AER::Utils::Matrix::I-AER::Utils::Matrix::I; - cmatrix_t temp1 = AER::Utils::concatenate(AER::Utils::Matrix::I, Zeros , 1), - temp2 = AER::Utils::concatenate(Zeros, mat, 1); - cmatrix_t cu = AER::Utils::concatenate(temp1, temp2 ,0) ; - temp.apply_matrix(cu); - break; - } - case su4: - temp.apply_matrix(mat); - break; - - default: - throw std::invalid_argument("illegal gate for apply_2_qubit_gate"); - } - MPS_Tensor left_gamma,right_gamma; - rvector_t lambda; - MPS_Tensor::Decompose(temp, left_gamma, lambda, right_gamma); - left_gamma.div_Gamma_by_left_Lambda(left_lambda); - right_gamma.div_Gamma_by_right_Lambda(right_lambda); - q_reg_[index_A] = left_gamma; - lambda_reg_[index_A] = lambda; - q_reg_[index_B] = right_gamma; + // We first move the two qubits to be in consecutive positions + // If index_B > index_A, we move the qubit at index_B to index_A+1 + // If index_B < index_A, we move the qubit at index_B to index_A-1, and then + // swap between the qubits + uint_t A = index_A; + bool swapped = false, greater = false, smaller = false; + + if (index_B > index_A+1) { + greater = true; + change_position(index_B, index_A+1); // Move B to be right after A + } else if (index_A > 0 && index_B < index_A-1) { + smaller = true; + change_position(index_B, index_A-1); // Move B to be right before A + } + if (index_B < index_A) { + A = index_A - 1; + swapped = true; + } + // After we moved the qubits as necessary, + // the operation is always between qubits A and A+1 + rvector_t left_lambda, right_lambda; + //There is no lambda on the edges of the MPS + left_lambda = (A != 0) ? lambda_reg_[A-1] : rvector_t {1.0}; + right_lambda = (A+1 != num_qubits_-1) ? lambda_reg_[A+1] : rvector_t {1.0}; + + q_reg_[A].mul_Gamma_by_left_Lambda(left_lambda); + q_reg_[A+1].mul_Gamma_by_right_Lambda(right_lambda); + MPS_Tensor temp = MPS_Tensor::contract(q_reg_[A], lambda_reg_[A], q_reg_[A+1]); + + switch (gate_type) { + case cx: + temp.apply_cnot(swapped); + break; + case cz: + temp.apply_cz(); + break; + case id: + break; + case cu1: + { + cmatrix_t Zeros = AER::Utils::Matrix::I-AER::Utils::Matrix::I; + cmatrix_t temp1 = AER::Utils::concatenate(AER::Utils::Matrix::I, Zeros , 1), + temp2 = AER::Utils::concatenate(Zeros, mat, 1); + cmatrix_t cu = AER::Utils::concatenate(temp1, temp2 ,0) ; + temp.apply_matrix(cu); + break; + } + case su4: + // We reverse the order of the qubits, according to the Qiskit convention. + // Effectively, this reverses swap for 2-qubit gates + temp.apply_matrix(mat, !swapped); + break; + + default: + throw std::invalid_argument("illegal gate for apply_2_qubit_gate"); + } + MPS_Tensor left_gamma,right_gamma; + rvector_t lambda; + MPS_Tensor::Decompose(temp, left_gamma, lambda, right_gamma); + left_gamma.div_Gamma_by_left_Lambda(left_lambda); + right_gamma.div_Gamma_by_right_Lambda(right_lambda); + q_reg_[A] = left_gamma; + lambda_reg_[A] = lambda; + q_reg_[A+1] = right_gamma; + + if (greater) { + change_position(index_A+1, index_B); // Move B back to its original position + } else if (smaller) { + change_position(index_A-1, index_B); + } } void MPS::apply_matrix(const reg_t & qubits, const cmatrix_t &mat) diff --git a/src/simulators/matrix_product_state/matrix_product_state_tensor.hpp b/src/simulators/matrix_product_state/matrix_product_state_tensor.hpp index 98de76969b..e980df6bd3 100644 --- a/src/simulators/matrix_product_state/matrix_product_state_tensor.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state_tensor.hpp @@ -117,7 +117,7 @@ class MPS_Tensor void apply_u1(double lambda); void apply_u2(double phi, double lambda); void apply_u3(double theta, double phi, double lambda); - void apply_matrix(const cmatrix_t &mat); + void apply_matrix(const cmatrix_t &mat, bool swapped=false); void apply_cnot(bool swapped = false); void apply_swap(); void apply_cz(); @@ -259,16 +259,26 @@ void MPS_Tensor::apply_tdg() data_[1] = data_[1] * complex_t(SQR_HALF, -SQR_HALF); } -void MPS_Tensor::apply_matrix(const cmatrix_t &mat) +void MPS_Tensor::apply_matrix(const cmatrix_t &mat, bool swapped) { - cvector_t temp; - for (uint_t a1 = 0; a1 < data_[0].GetRows(); a1++) - for (uint_t a2 = 0; a2 < data_[0].GetColumns(); a2++) - { - temp = get_data(a1,a2); - temp = mat * temp; - insert_data(a1,a2,temp); + if (swapped) + swap(data_[1], data_[2]); + + MPS_Tensor new_tensor; + // initialize by multiplying first column of mat by data_[0] + for (uint_t i=0; i Date: Wed, 4 Dec 2019 15:01:55 +0200 Subject: [PATCH 07/12] Add probabilities and pauli expval snapshots to stabilizer method (#423) --- CHANGELOG.md | 1 + src/simulators/stabilizer/clifford.hpp | 11 + .../stabilizer/stabilizer_state.hpp | 204 +++++++++++++----- .../statevector/statevector_state.hpp | 4 +- .../backends/qasm_simulator/qasm_snapshot.py | 14 +- 5 files changed, 175 insertions(+), 59 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 544dc31639..c20eedd24c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ Changelog](http://keepachangelog.com/en/1.0.0/). Added ----- +- Added support for probabilities snapshot and Pauli expectation value snapshot in the stabilizer simulator (\#423) Changed ------- diff --git a/src/simulators/stabilizer/clifford.hpp b/src/simulators/stabilizer/clifford.hpp index 8e3d9828de..98e8b55d40 100644 --- a/src/simulators/stabilizer/clifford.hpp +++ b/src/simulators/stabilizer/clifford.hpp @@ -97,6 +97,10 @@ class Clifford { // Measurement //----------------------------------------------------------------------- + // If we perform a single qubit Z measurement, + // will the outcome be random or deterministic. + bool is_deterministic_outcome(const uint64_t& qubit) const; + // Return the outcome (0 or 1) of a single qubit Z measurement, and // update the stabilizer to the conditional (post measurement) state if // the outcome was random. @@ -285,6 +289,13 @@ std::pair Clifford::x_anticommuting(const uint64_t qubit) const // Measurement //------------------------------------------------------------------------------ +bool Clifford::is_deterministic_outcome(const uint64_t& qubit) const { + // Clifford state measurements only have three probabilities: + // (p0, p1) = (0.5, 0.5), (1, 0), or (0, 1) + // The random case happens if there is a row anti-commuting with Z[qubit] + return !z_anticommuting(qubit).first; +} + bool Clifford::measure_and_update(const uint64_t qubit, const uint64_t randint) { // Clifford state measurements only have three probabilities: // (p0, p1) = (0.5, 0.5), (1, 0), or (0, 1) diff --git a/src/simulators/stabilizer/stabilizer_state.hpp b/src/simulators/stabilizer/stabilizer_state.hpp index c41ab432fb..6e89108867 100644 --- a/src/simulators/stabilizer/stabilizer_state.hpp +++ b/src/simulators/stabilizer/stabilizer_state.hpp @@ -32,11 +32,13 @@ enum class Gates {id, x, y, z, h, s, sdg, cx, cz, swap}; // Allowed snapshots enum class enum class Snapshots { stabilizer, cmemory, cregister, - probs, probs_var - /* TODO: the following snapshots still need to be implemented */ - //expval_pauli, expval_pauli_var, // TODO + probs, probs_var, + expval_pauli, expval_pauli_var, expval_pauli_shot }; +// Enum class for different types of expectation values +enum class SnapshotDataType {average, average_var, pershot}; + //============================================================================ // Stabilizer Table state class //============================================================================ @@ -76,7 +78,12 @@ class State : public Base::State { // Return the set of qobj snapshot types supported by the State virtual stringset_t allowed_snapshots() const override { - return {"stabilizer", "memory", "register"}; + return {"stabilizer", "memory", "register", + "probabilities", "probabilities_with_variance", + "expectation_value_pauli", + "expectation_value_pauli_with_variance", + "expectation_value_pauli_single_shot" + }; } // Apply a sequence of operations by looping over list @@ -118,7 +125,7 @@ class State : public Base::State { void apply_gate(const Operations::Op &op); // Measure qubits and return a list of outcomes [q0, q1, ...] - // If a state subclass supports this function it then "measure" + // If a state subclass supports this function then "measure" // should be contained in the set returned by the 'allowed_ops' // method. virtual void apply_measure(const reg_t &qubits, @@ -159,12 +166,15 @@ class State : public Base::State { ExperimentData &data, bool variance); - /* TODO + void snapshot_probabilities_auxiliary(const reg_t& qubits, + std::string outcome, + double outcome_prob, + stringmap_t& probs); + // Snapshot the expectation value of a Pauli operator void snapshot_pauli_expval(const Operations::Op &op, ExperimentData &data, - bool variance); - */ + SnapshotDataType type); //----------------------------------------------------------------------- // Config Settings @@ -211,9 +221,10 @@ const stringmap_t State::snapshotset_({ {"memory", Snapshots::cmemory}, {"register", Snapshots::cregister}, {"probabilities", Snapshots::probs}, - {"probabilities_with_variance", Snapshots::probs_var} - //{"expectation_value_pauli", Snapshots::expval_pauli}, // TODO - //{"expectation_value_pauli_with_variance", Snapshots::expval_pauli_var} // TODO + {"probabilities_with_variance", Snapshots::probs_var}, + {"expectation_value_pauli", Snapshots::expval_pauli}, + {"expectation_value_pauli_with_variance", Snapshots::expval_pauli_var}, + {"expectation_value_pauli_single_shot", Snapshots::expval_pauli_shot} }); @@ -442,6 +453,15 @@ void State::apply_snapshot(const Operations::Op &op, case Snapshots::probs_var: { snapshot_probabilities(op, data, true); } break; + case Snapshots::expval_pauli: { + snapshot_pauli_expval(op, data, SnapshotDataType::average); + } break; + case Snapshots::expval_pauli_var: { + snapshot_pauli_expval(op, data, SnapshotDataType::average_var); + } break; + case Snapshots::expval_pauli_shot: { + snapshot_pauli_expval(op, data, SnapshotDataType::pershot); + } break; default: // We shouldn't get here unless there is a bug in the snapshotset throw std::invalid_argument("Stabilizer::State::invalid snapshot instruction \'" + @@ -478,56 +498,140 @@ void State::snapshot_probabilities(const Operations::Op &op, throw std::runtime_error(msg); } - // build X-stabilizer matrix for measure qubits - std::vector x_stab; - for(const auto& qubit : op.qubits){ - reg_t row; - for(const auto& qubit2 : op.qubits){ - row.push_back(qreg_.stabilizer(qubit).X[qubit2]); + stringmap_t probs; + snapshot_probabilities_auxiliary(op.qubits, + std::string(op.qubits.size(), 'X'), + 1, probs); + + // Add snapshot to data + data.add_average_snapshot("probabilities", op.string_params[0], + BaseState::creg_.memory_hex(), probs, variance); +} + + +void State::snapshot_probabilities_auxiliary(const reg_t& qubits, + std::string outcome, + double outcome_prob, + stringmap_t& probs) { + uint_t qubit_for_branching = -1; + for(uint_t i=0; i probs; - const uint_t num_outcomes = 1ULL << num_qubits; - for (uint_t b=0; b < num_outcomes; b++) { - uint_t outcome = sample_outcome; - for (size_t j=0; j < num_qubits; j++) { - // Check if j-th bit is 1 - if (b & (1ULL << j)) - outcome ^= x_stab[j]; + for(uint_t single_qubit_outcome = 0; single_qubit_outcome<2; ++single_qubit_outcome) { + std::string new_outcome = outcome; + if(single_qubit_outcome) { + new_outcome[qubit_for_branching] = '1'; } - // Check if outcome is in already in the probabilities - // map and if not add it. We will renormalize at the end. - const std::string outcome_hex = Utils::int2hex(outcome); - if (probs.find(outcome_hex) == probs.end()) { - probs[outcome_hex] = 1.0; + else { + new_outcome[qubit_for_branching] = '0'; } + + auto copy_of_qreg = BaseState::qreg_; + BaseState::qreg_.measure_and_update(qubits[qubits.size()-qubit_for_branching-1], single_qubit_outcome); + snapshot_probabilities_auxiliary(qubits, new_outcome, 0.5*outcome_prob, probs); + BaseState::qreg_ = copy_of_qreg; } +} - // Renormalize outcomes - auto renorm = probs.size(); - for (auto &pair : probs) { - pair.second /= renorm; +void State::snapshot_pauli_expval(const Operations::Op &op, + ExperimentData &data, + SnapshotDataType type) { + // Check empty edge case + if (op.params_expval_pauli.empty()) { + throw std::invalid_argument("Invalid expval snapshot (Pauli components are empty)."); } - // Add snapshot to data - data.add_average_snapshot("probabilities", op.string_params[0], - BaseState::creg_.memory_hex(), probs, variance); + // Compute expval components + auto copy_of_qreg = BaseState::qreg_; + complex_t expval(0., 0.); + for (const auto ¶m : op.params_expval_pauli) { + const auto& coeff = param.first; + const auto& pauli = param.second; + reg_t measured_qubits; + for (uint_t pos=0; pos < op.qubits.size(); ++pos) { + uint_t qubit = op.qubits[pos]; + switch (pauli[pauli.size() - 1 - pos]) { + case 'I': + break; + case 'X': + BaseState::qreg_.append_h(qubit); + measured_qubits.push_back(qubit); + break; + case 'Y': + BaseState::qreg_.append_s(qubit); + BaseState::qreg_.append_z(qubit); + measured_qubits.push_back(qubit); + break; + case 'Z': + measured_qubits.push_back(qubit); + break; + default: { + std::stringstream msg; + msg << "QubitVectorState::invalid Pauli string \'" << pauli[pos] << "\'."; + throw std::invalid_argument(msg.str()); + } + } + } + + stringmap_t probs; + snapshot_probabilities_auxiliary(measured_qubits, + std::string(measured_qubits.size(), 'X'), + 1, probs); + + complex_t local_val(0., 0.); + for(auto it = probs.begin(); it != probs.end(); ++it) { + std::string outcome = Utils::hex2bin(it->first); + int_t parity = 0; + for(uint_t pos=0; pos < measured_qubits.size(); ++pos) { + // first two characters of outcome are always 0b + int_t bit = ((outcome[pos+2] == '1') ? 1 : 0); + parity = ((parity + bit) % 2); + } + local_val += (it->second * ((-parity*2)+1)); + } + + // Pauli expecation values should always be real for a valid state + // so we truncate the imaginary part + expval += coeff * std::real(local_val); + + BaseState::qreg_ = copy_of_qreg; + } + + // add to snapshot + Utils::chop_inplace(expval, json_chop_threshold_); + switch (type) { + case SnapshotDataType::average: + data.add_average_snapshot("expectation_value", op.string_params[0], + BaseState::creg_.memory_hex(), expval, false); + break; + case SnapshotDataType::average_var: + data.add_average_snapshot("expectation_value", op.string_params[0], + BaseState::creg_.memory_hex(), expval, true); + break; + case SnapshotDataType::pershot: + data.add_pershot_snapshot("expectation_values", op.string_params[0], expval); + break; + } } diff --git a/src/simulators/statevector/statevector_state.hpp b/src/simulators/statevector/statevector_state.hpp index 1c4bae084d..b94fbf8860 100755 --- a/src/simulators/statevector/statevector_state.hpp +++ b/src/simulators/statevector/statevector_state.hpp @@ -103,7 +103,7 @@ class State : public Base::State { } // Apply a sequence of operations by looping over list - // If the input is not in allowed_ops an exeption will be raised. + // If the input is not in allowed_ops an exception will be raised. virtual void apply_ops(const std::vector &ops, ExperimentData &data, RngEngine &rng) override; @@ -230,7 +230,7 @@ class State : public Base::State { // should be left in the pre-snapshot state. //----------------------------------------------------------------------- - // Snapshot current qubit probabilities for a measurement (average) + // Snapshot current amplitudes void snapshot_statevector(const Operations::Op &op, ExperimentData &data, SnapshotDataType type); diff --git a/test/terra/backends/qasm_simulator/qasm_snapshot.py b/test/terra/backends/qasm_simulator/qasm_snapshot.py index 6d7ae135e0..3ccb98a2f2 100644 --- a/test/terra/backends/qasm_simulator/qasm_snapshot.py +++ b/test/terra/backends/qasm_simulator/qasm_snapshot.py @@ -510,12 +510,12 @@ class QasmSnapshotProbabilitiesTests: SIMULATOR = QasmSimulator() SUPPORTED_QASM_METHODS = [ - 'automatic', 'statevector', 'density_matrix', 'matrix_product_state' + 'automatic', 'statevector', 'stabilizer', 'density_matrix', 'matrix_product_state' ] BACKEND_OPTS = {} @staticmethod - def probabilitiy_snapshots(data, labels): + def probability_snapshots(data, labels): """Format snapshots as nested dicts""" # Check snapshot entry exists in data output = {} @@ -547,7 +547,7 @@ def test_snapshot_probabilities_pre_measure(self): # Check snapshots for j, circuit in enumerate(circuits): data = result.data(circuit) - all_snapshots = self.probabilitiy_snapshots(data, labels) + all_snapshots = self.probability_snapshots(data, labels) for label in labels: snaps = all_snapshots.get(label, {}) self.assertTrue(len(snaps), 1) @@ -577,7 +577,7 @@ def test_snapshot_probabilities_post_measure(self): # Check snapshots for j, circuit in enumerate(circuits): data = result.data(circuit) - all_snapshots = self.probabilitiy_snapshots(data, labels) + all_snapshots = self.probability_snapshots(data, labels) for label in labels: snaps = all_snapshots.get(label, {}) for memory, value in snaps.items(): @@ -590,7 +590,7 @@ class QasmSnapshotExpValPauliTests: SIMULATOR = QasmSimulator() SUPPORTED_QASM_METHODS = [ - 'automatic', 'statevector', 'matrix_product_state' + 'automatic', 'statevector', 'stabilizer', 'matrix_product_state' ] BACKEND_OPTS = {} @@ -640,7 +640,7 @@ def test_snapshot_expval_pauli_pre_measure(self): self.assertAlmostEqual(value, target, delta=1e-7) def test_snapshot_expval_pauli_post_measure(self): - """Test snapshot expectation value (pauli) before final measurement""" + """Test snapshot expectation value (pauli) after final measurement""" shots = 1000 labels = snapshot_expval_labels() counts_targets = snapshot_expval_counts(shots) @@ -723,7 +723,7 @@ def test_snapshot_expval_matrix_pre_measure(self): self.assertAlmostEqual(value, target, delta=1e-7) def test_snapshot_expval_matrix_post_measure(self): - """Test snapshot expectation value (matrix) before final measurement""" + """Test snapshot expectation value (matrix) after final measurement""" shots = 1000 labels = snapshot_expval_labels() counts_targets = snapshot_expval_counts(shots) From 5083f13618b0eff2a3730228af7c83dff613995f Mon Sep 17 00:00:00 2001 From: merav-aharoni <46567124+merav-aharoni@users.noreply.github.com> Date: Wed, 4 Dec 2019 18:52:56 +0200 Subject: [PATCH 08/12] New computation of expectation value for mps method (#344) --- CHANGELOG.md | 2 +- .../matrix_product_state.hpp | 8 +- .../matrix_product_state_internal.cpp | 233 +++++++++++++----- .../matrix_product_state_internal.hpp | 45 +++- .../matrix_product_state_tensor.hpp | 137 ++++++++-- src/simulators/matrix_product_state/svd.cpp | 131 +++++----- src/simulators/matrix_product_state/svd.hpp | 12 +- 7 files changed, 390 insertions(+), 178 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c20eedd24c..eeab407ced 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -69,7 +69,7 @@ Removed Fixed ----- - Fix sdist to always attempt to build (\#401) - +- New (efficient) implementation for expectation_value_pauli in MPS simulation method (\#344) [0.3.1](https://github.com/Qiskit/qiskit-aer/compare/0.3.0...0.3.1) - 2019-10-15 diff --git a/src/simulators/matrix_product_state/matrix_product_state.hpp b/src/simulators/matrix_product_state/matrix_product_state.hpp index 8b92896e42..4b8e4853c1 100644 --- a/src/simulators/matrix_product_state/matrix_product_state.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state.hpp @@ -469,13 +469,13 @@ void State::snapshot_pauli_expval(const Operations::Op &op, //Compute expval components complex_t expval(0., 0.); - double one_expval = 0; for (const auto ¶m : op.params_expval_pauli) { complex_t coeff = param.first; - string pauli_matrices = param.second; - one_expval = qreg_.expectation_value(op.qubits, pauli_matrices); - expval += coeff * one_expval;; + std::string pauli_matrices = param.second; + complex_t pauli_expval = qreg_.expectation_value_pauli(op.qubits, pauli_matrices); + + expval += coeff * pauli_expval; } data.add_pershot_snapshot("expectation_value", op.string_params[0], expval); } diff --git a/src/simulators/matrix_product_state/matrix_product_state_internal.cpp b/src/simulators/matrix_product_state/matrix_product_state_internal.cpp index f4e670151a..b04913c296 100644 --- a/src/simulators/matrix_product_state/matrix_product_state_internal.cpp +++ b/src/simulators/matrix_product_state/matrix_product_state_internal.cpp @@ -53,7 +53,7 @@ static const cmatrix_t one_measure = //---------------------------------------------------------------- cvector_t reverse_all_bits(const cvector_t& statevector, uint_t num_qubits); uint_t reverse_bits(uint_t num, uint_t len); -vector calc_new_indexes(vector indexes); + std::vector calc_new_indexes(std::vector indexes); // The following two functions are helper functions used by // initialize_from_statevector @@ -92,11 +92,11 @@ cvector_t reverse_all_bits(const cvector_t& statevector, uint_t num_qubits) return output_vector; } -vector calc_new_indexes(vector indexes) +std::vector calc_new_indexes(std::vector indexes) { uint_t n = indexes.size(); - uint_t avg = round(accumulate( indexes.begin(), indexes.end(), 0.0)/ n ); - vector new_indexes( n ); + uint_t avg = std::round(std::accumulate( indexes.begin(), indexes.end(), 0.0)/ n ); + std::vector new_indexes( n ); std::iota( std::begin( new_indexes ), std::end( new_indexes ), avg-n/2); return new_indexes; } @@ -122,7 +122,7 @@ cmatrix_t mul_matrix_by_lambda(const cmatrix_t &mat, } cmatrix_t reshape_matrix(cmatrix_t input_matrix) { - vector res(2); + std::vector res(2); AER::Utils::split(input_matrix, res[0], res[1], 1); cmatrix_t reshaped_matrix = AER::Utils::concatenate(res[0], res[1], 0); return reshaped_matrix; @@ -223,7 +223,7 @@ void MPS::apply_swap(uint_t index_A, uint_t index_B) q_reg_[index_A].mul_Gamma_by_left_Lambda(left_lambda); q_reg_[index_B].mul_Gamma_by_right_Lambda(right_lambda); - MPS_Tensor temp = MPS_Tensor::contract(q_reg_[index_A],lambda_reg_[index_A], q_reg_[index_B]); + MPS_Tensor temp = MPS_Tensor::contract(q_reg_[index_A], lambda_reg_[index_A], q_reg_[index_B]); temp.apply_swap(); MPS_Tensor left_gamma,right_gamma; @@ -363,26 +363,11 @@ void MPS::change_position(uint_t src, uint_t dst) cmatrix_t MPS::density_matrix(const reg_t &qubits) const { - // ***** Assuming ascending sorted qubits register ***** - vector internalIndexes; - for (uint_t index : qubits) - internalIndexes.push_back(index); - MPS temp_MPS; - temp_MPS.initialize(*this); - vector new_indexes = calc_new_indexes(internalIndexes); - uint_t avg = new_indexes[new_indexes.size()/2]; - vector::iterator it = lower_bound(internalIndexes.begin(), internalIndexes.end(), avg); - int mid = std::distance(internalIndexes.begin(), it); - for(uint_t i = mid; i < internalIndexes.size(); i++) - { - temp_MPS.change_position(internalIndexes[i],new_indexes[i]); - } - for(int i = mid-1; i >= 0; i--) - { - temp_MPS.change_position(internalIndexes[i],new_indexes[i]); - } - MPS_Tensor psi = temp_MPS.state_vec(new_indexes.front(), new_indexes.back()); + uint_t front = 0, back = 0; + MPS_with_new_indices(qubits, temp_MPS, front, back); + MPS_Tensor psi = temp_MPS.state_vec(front, back); + uint_t size = psi.get_dim(); cmatrix_t rho(size,size); #ifdef _WIN32 @@ -398,32 +383,29 @@ cmatrix_t MPS::density_matrix(const reg_t &qubits) const return rho; } -double MPS::expectation_value(const reg_t &qubits, const string &matrices) const -{ +void MPS::MPS_with_new_indices(const reg_t &qubits, + MPS& temp_MPS, + uint_t &front, uint_t &back) const { // ***** Assuming ascending sorted qubits register ***** - cmatrix_t rho = density_matrix(qubits); - string matrices_reverse = matrices; - reverse(matrices_reverse.begin(), matrices_reverse.end()); - cmatrix_t M(1), temp; - M(0,0) = complex_t(1); - for(const char& gate : matrices_reverse) + std::vector internalIndexes; + for (uint_t index : qubits) + internalIndexes.push_back(index); + + temp_MPS.initialize(*this); + std::vector new_indexes = calc_new_indexes(internalIndexes); + uint_t avg = new_indexes[new_indexes.size()/2]; + std::vector::iterator it = lower_bound(internalIndexes.begin(), internalIndexes.end(), avg); + int mid = std::distance(internalIndexes.begin(), it); + for(uint_t i = mid; i < internalIndexes.size(); i++) { - if (gate == 'X') - temp = AER::Utils::Matrix::X; - else if (gate == 'Y') - temp = AER::Utils::Matrix::Y; - else if (gate == 'Z') - temp = AER::Utils::Matrix::Z; - else if (gate == 'I') - temp = AER::Utils::Matrix::I; - M = AER::Utils::tensor_product(M, temp); + temp_MPS.change_position(internalIndexes[i], new_indexes[i]); } - // Trace(rho*M). not using methods for efficiency - complex_t res = 0; - for (uint_t i = 0; i < M.GetRows(); i++) - for (uint_t j = 0; j < M.GetRows(); j++) - res += M(i,j)*rho(j,i); - return real(res); + for(int i = mid-1; i >= 0; i--) + { + temp_MPS.change_position(internalIndexes[i], new_indexes[i]); + } + front = internalIndexes.front(); + back = internalIndexes.back(); } double MPS::expectation_value(const reg_t &qubits, const cmatrix_t &M) const @@ -439,30 +421,151 @@ double MPS::expectation_value(const reg_t &qubits, const cmatrix_t &M) const return real(res); } -ostream& MPS::print(ostream& out) const +//--------------------------------------------------------------- +// Function: expectation_value_pauli +// Algorithm: For more details, see "The density-matrix renormalization group in the age of matrix +// product states" by Ulrich Schollwock. +// For the illustration, assume computing the expectation +// value on qubits numbered q0, q1, q2, q3. There may be additional qubits +// before q0 or after q3 +// Initial state: +// q0 q1 q2 q3 +// -a0-o--a1--o--a2--o--a3--o--- +// | | | | +// -a0-o--a1--o--a2--o--a3--o--- +// +// +// We can actually think of this as q0 q1 q2 q3 +// --o---o---o---o-- +// | | | | | | +// --o---o---o---o-- +// because expectation value on the left and right are 1. + +// After Step 4: +// q1 q2 q3 +// a1/o--a2--o--a3--o-- +// o | | | | +// a1\o--a2--o--a3--o-- +// +// After step 8: +// q1 q2 q3 +// o--a2--o--a3--o-- +// a1||i | | | +// o--a2--o--a3--o-- +// +// After step 9: +// q2 q3 +// a2/o--a3--o-- +// o | | | +// a2\o--a3--o-- +//--------------------------------------------------------------- + +complex_t MPS::expectation_value_pauli(const reg_t &qubits, const std::string &matrices) const +{ + MPS temp_MPS; + uint_t first_index = 0, last_index = 0; + MPS_with_new_indices(qubits, temp_MPS, first_index, last_index); + + // Preliminary step - reverse the order of the matrices because + // they are ordered in reverse to that of the qubits (in the interface) + std::string reversed_matrices = matrices; + reverse(reversed_matrices.begin(), reversed_matrices.end()); + char gate = reversed_matrices[0]; + + // Step 1 - multiply tensor of q0 by its left lambda + MPS_Tensor left_tensor = temp_MPS.q_reg_[first_index]; + if (first_index > 0) { + left_tensor.mul_Gamma_by_left_Lambda(temp_MPS.lambda_reg_[first_index-1]); + } + + // The last gamma must be multiplied also by its right lambda. + // Here we handle the special case that we are calculating exp val + // on a single qubit + // we need to mul every gamma by its right lambda + if (first_index==last_index && first_index < num_qubits_-1) { + left_tensor.mul_Gamma_by_right_Lambda(temp_MPS.lambda_reg_[first_index]); + } + + // Step 2 - prepare the dagger of left_tensor + MPS_Tensor left_tensor_dagger(AER::Utils::dagger(left_tensor.get_data(0)), + AER::Utils::dagger(left_tensor.get_data(1))); + + // Step 3 - Apply the gate to q0 + left_tensor.apply_pauli(gate); + + // Step 4 - contract Gamma0' with Gamma0 over dimensions a0 and i + // Before contraction, Gamma0' has size a1 x a0 x i, Gamma0 has size i x a0 x a1 + // result = left_contract is a matrix of size a1 x a1 + cmatrix_t final_contract; + MPS_Tensor::contract_2_dimensions(left_tensor_dagger, left_tensor, + final_contract); + + for (uint_t qubit_num=first_index+1; qubit_num<=last_index; qubit_num++) { + + // Step 5 - multiply next Gamma by its left lambda (same as Step 1) + // next gamma has dimensions a0 x a1 x i + MPS_Tensor next_gamma = temp_MPS.q_reg_[qubit_num]; + next_gamma.mul_Gamma_by_left_Lambda(temp_MPS.lambda_reg_[qubit_num-1]); + + // Last qubit must be multiplied by rightmost lambda + if (qubit_num==last_index && qubit_num < num_qubits_-1) + next_gamma.mul_Gamma_by_right_Lambda(temp_MPS.lambda_reg_[qubit_num]); + + // Step 6 - prepare the dagger of the next gamma (same as Step 2) + // next_gamma_dagger has dimensions a1' x a0' x i + MPS_Tensor next_gamma_dagger(AER::Utils::dagger(next_gamma.get_data(0)), + AER::Utils::dagger(next_gamma.get_data(1))); + + // Step 7 - apply gate (same as Step 3) + gate = reversed_matrices[qubit_num - first_index]; + next_gamma.apply_pauli(gate); + + // Step 8 - contract final_contract from previous stage with next gamma over a1 + // final_contract has dimensions a1 x a1, Gamma1 has dimensions a1 x a2 x i (where i=2) + // result is a tensor of size a1 x a2 x i + MPS_Tensor next_contract(final_contract * next_gamma.get_data(0), + final_contract * next_gamma.get_data(1)); + + // Step 9 - contract next_contract (a1 x a2 x i) + // with next_gamma_dagger (i x a2 x a1) (same as Step 4) + // here we need to contract across two dimensions: a1 and i + // result is a matrix of size a2 x a2 + MPS_Tensor::contract_2_dimensions(next_gamma_dagger, next_contract, + final_contract); + } + + // Step 10 - contract over final matrix of size aN x aN + // We need to contract the final matrix with itself + // Compute this by taking the trace of final_contract + complex_t result = AER::Utils::trace(final_contract); + + return result; +} + +std::ostream& MPS::print(std::ostream& out) const { for(uint_t i=0; i MPS::get_matrices_sizes() const +std::vector MPS::get_matrices_sizes() const { - vector result; - for(uint_t i=0; i result; + for(uint_t i=0; i left_data = reshape_U_after_SVD(U); + std::vector left_data = reshape_U_after_SVD(U); MPS_Tensor left_gamma(left_data[0], left_data[1]); if (!first_iter) left_gamma.div_Gamma_by_left_Lambda(lambda_reg_.back()); @@ -616,7 +719,7 @@ void MPS::initialize_from_statevector(uint_t num_qubits, const cvector_t state_v } // step 4 - create the rightmost gamma and update q_reg_ - vector right_data = reshape_V_after_SVD(V); + std::vector right_data = reshape_V_after_SVD(V); MPS_Tensor right_gamma(right_data[0], right_data[1]) ; q_reg_.push_back(right_gamma); diff --git a/src/simulators/matrix_product_state/matrix_product_state_internal.hpp b/src/simulators/matrix_product_state/matrix_product_state_internal.hpp index e7806e0e79..132530b2e3 100644 --- a/src/simulators/matrix_product_state/matrix_product_state_internal.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state_internal.hpp @@ -132,21 +132,48 @@ class MPS{ cmatrix_t density_matrix(const reg_t &qubits) const; - // double Expectation_value(const vector &indexes, const string &matrices); - double expectation_value(const reg_t &qubits, const string &matrices) const; + //--------------------------------------------------------------- + // Function: expectation_value + // Description: Computes expectation value of the given qubits on the given matrix. + // Parameters: The qubits for which we compute expectation value. + // M - the matrix + // Returns: The expectation value. + //------------------------------------------------------------------ double expectation_value(const reg_t &qubits, const cmatrix_t &M) const; + //--------------------------------------------------------------- + // Function: expectation_value_pauli + // Description: Computes expectation value of the given qubits on a string of Pauli matrices. + // Parameters: The qubits for which we compute expectation value. + // A string of matrices of the set {X, Y, Z, I}. The matrices are given in + // reverse order relative to the qubits. + // Returns: The expectation value in the form of a complex number. The real part is the + // actual expectation value. + //------------------------------------------------------------------ + complex_t expectation_value_pauli(const reg_t &qubits, const std::string &matrices) const; + + //------------------------------------------------------------------ + // function name: MPS_with_new_indices + // Description: Creates a copy of *this where the indices of the + // selected qubits have been moved for more efficient computation + // of the expectation value + // Parameters: The qubits for which we compute expectation value. + // Returns: new MPS. + //---------------------------------------------------------------- + void MPS_with_new_indices(const reg_t &qubits, MPS& temp_MPS, + uint_t &front, uint_t &back) const; + //---------------------------------------------------------------- // function name: print // Description: prints the MPS //---------------------------------------------------------------- - virtual ostream& print(ostream& out) const; + virtual std::ostream& print(std::ostream& out) const; //---------------------------------------------------------------- // function name: get_matrices_sizes // Description: returns the size of the inner matrices of the MPS //---------------------------------------------------------------- - vector get_matrices_sizes() const; + std::vector get_matrices_sizes() const; //---------------------------------------------------------------- // function name: state_vec @@ -183,7 +210,7 @@ class MPS{ } void enable_gate_opt() { - cout << "enable_gate_opt not supported yet" < q_reg_; - vector lambda_reg_; + std::vector q_reg_; + std::vector lambda_reg_; //----------------------------------------------------------------------- // Config settings //----------------------------------------------------------------------- @@ -238,7 +265,7 @@ class MPS{ // in JSON serialization }; -inline ostream &operator<<(std::ostream &out, const rvector_t &vec) { +inline std::ostream &operator<<(std::ostream &out, const rvector_t &vec) { out << "["; uint_t size = vec.size(); for (uint_t i = 0; i < size-1; ++i) { @@ -249,7 +276,7 @@ inline ostream &operator<<(std::ostream &out, const rvector_t &vec) { return out; } -inline ostream& +inline std::ostream& operator <<(std::ostream& out, const MPS& mps) { return mps.print(out); diff --git a/src/simulators/matrix_product_state/matrix_product_state_tensor.hpp b/src/simulators/matrix_product_state/matrix_product_state_tensor.hpp index e980df6bd3..020164f1a8 100644 --- a/src/simulators/matrix_product_state/matrix_product_state_tensor.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state_tensor.hpp @@ -89,7 +89,7 @@ class MPS_Tensor } return *this; } - virtual ostream& print(ostream& out) const; + virtual std::ostream& print(std::ostream& out) const; reg_t get_size() const; cvector_t get_data(uint_t a1, uint_t a2) const; cmatrix_t get_data(uint_t i) const { @@ -106,6 +106,7 @@ class MPS_Tensor uint_t get_dim() const { return data_.size(); } + void apply_pauli(char gate); void apply_x(); void apply_y(); void apply_z(); @@ -125,15 +126,17 @@ class MPS_Tensor void mul_Gamma_by_right_Lambda(const rvector_t &Lambda); void div_Gamma_by_left_Lambda(const rvector_t &Lambda); void div_Gamma_by_right_Lambda(const rvector_t &Lambda); - static MPS_Tensor contract(const MPS_Tensor &left_gamma, const rvector_t &lambda, const MPS_Tensor &right_gamma); + static MPS_Tensor contract(const MPS_Tensor &left_gamma, const rvector_t &lambda, const MPS_Tensor &right_gamma, bool mul_by_lambda); static void Decompose(MPS_Tensor &temp, MPS_Tensor &left_gamma, rvector_t &lambda, MPS_Tensor &right_gamma); - +static void contract_2_dimensions(const MPS_Tensor &left_gamma, + const MPS_Tensor &right_gamma, + cmatrix_t &result); private: void mul_Gamma_by_Lambda(const rvector_t &Lambda, bool right, /* or left */ bool mul /* or div */); - vector data_; + std::vector data_; }; //========================================================================= @@ -144,10 +147,10 @@ class MPS_Tensor // function name: print // Description: Prints the Tensor. All the submatrices are aligned by rows. //------------------------------------------------------------- -ostream& MPS_Tensor::print(ostream& out) const { +std::ostream& MPS_Tensor::print(std::ostream& out) const { complex_t value; - out << "[" << endl; + out << "[" << std::endl; if (data_.size() > 0){ //Printing the matrices row by row (i.e., not matrix by matrix) @@ -165,10 +168,10 @@ ostream& MPS_Tensor::print(ostream& out) const { } out << "| ,"; } - out << endl; + out << std::endl; } } - out << "]" << endl; + out << "]" << std::endl; return out; } @@ -216,6 +219,24 @@ void MPS_Tensor::insert_data(uint_t a1, uint_t a2, cvector_t data) data_[i](a1,a2) = data[i]; } +void MPS_Tensor::apply_pauli(char gate) { + switch (gate) { + case 'X': + apply_x(); + break; + case 'Y': + apply_y(); + break; + case 'Z': + apply_z(); + break; + case 'I': + break; + default: + throw std::invalid_argument("illegal gate for contract_with_self"); + } + +} //--------------------------------------------------------------- // function name: apply_x,y,z,... // Description: Apply some gate on the tensor. tensor must represent @@ -225,13 +246,13 @@ void MPS_Tensor::insert_data(uint_t a1, uint_t a2, cvector_t data) //--------------------------------------------------------------- void MPS_Tensor::apply_x() { - swap(data_[0],data_[1]); + std::swap(data_[0],data_[1]); } void MPS_Tensor::apply_y() { data_[0] = data_[0] * complex_t(0, 1); data_[1] = data_[1] * complex_t(0, -1); - swap(data_[0],data_[1]); + std::swap(data_[0],data_[1]); } void MPS_Tensor::apply_z() @@ -284,14 +305,14 @@ void MPS_Tensor::apply_matrix(const cmatrix_t &mat, bool swapped) void MPS_Tensor::apply_cnot(bool swapped) { if(!swapped) - swap(data_[2],data_[3]); + std::swap(data_[2],data_[3]); else - swap(data_[1],data_[3]); + std::swap(data_[1],data_[3]); } void MPS_Tensor::apply_swap() { - swap(data_[1],data_[2]); + std::swap(data_[1],data_[2]); } void MPS_Tensor::apply_cz() @@ -356,17 +377,85 @@ void MPS_Tensor::mul_Gamma_by_Lambda(const rvector_t &Lambda, // tensors to contract. // Returns: The result tensor of the contract //--------------------------------------------------------------- -MPS_Tensor MPS_Tensor::contract(const MPS_Tensor &left_gamma, const rvector_t &lambda, const MPS_Tensor &right_gamma) +MPS_Tensor MPS_Tensor::contract(const MPS_Tensor &left_gamma, + const rvector_t &lambda, + const MPS_Tensor &right_gamma, + bool mul_by_lambda=true) { MPS_Tensor Res; MPS_Tensor new_left = left_gamma; - new_left.mul_Gamma_by_right_Lambda(lambda); + if (mul_by_lambda) { + new_left.mul_Gamma_by_right_Lambda(lambda); + } for(uint_t i = 0; i < new_left.data_.size(); i++) - for(uint_t j = 0; j < right_gamma.data_.size(); j++) + for(uint_t j = 0; j < right_gamma.data_.size(); j++) { + Res.data_.push_back(new_left.data_[i] * right_gamma.data_[j]); + } return Res; } +//--------------------------------------------------------------- +// Function name: contract_2_dimensions +// Description: Contract two Gamma tensors across 2 dimensions: left_columns/right_rows and +// left_size/right_size +// Parameters: MPS_Tensor &left_gamma, &right_gamma - the tensors to contract. +// Returns: The result matrix of the contract +// Assumptions: +// 1. We assume lambda was already multiplied into the gammas before this function +// 2. We assume the tensors (t1 and t2) are of the form: +// t1 +// o--a1--o +// || +// o--a2--o +// t2 +// There is a double bond between tensor 1 and 2, and each of them has an additional bond of +// dimension a1 and a2 respectively. The result matrix will be of size a2 x a1 +//--------------------------------------------------------------- +void MPS_Tensor::contract_2_dimensions(const MPS_Tensor &left_gamma, + const MPS_Tensor &right_gamma, + cmatrix_t &result) +{ + int_t left_rows = left_gamma.data_[0].GetRows(); + int_t left_columns = left_gamma.data_[0].GetColumns(); + int_t left_size = left_gamma.get_dim(); + int_t right_rows = right_gamma.data_[0].GetRows(); + int_t right_columns = right_gamma.data_[0].GetColumns(); + int_t right_size = right_gamma.get_dim(); + + // left_columns/right_rows and left_size/right_size + if (left_columns != right_rows) + throw std::runtime_error("left_columns != right_rows"); + + if (left_size != right_size) + throw std::runtime_error("left_size != right_size"); + result.resize(left_rows, right_columns); + + #ifdef _WIN32 + #pragma omp parallel for + #else + #pragma omp parallel for collapse(2) + #endif + for (int_t l_row=0; l_row C; C = reshape_before_SVD(temp.data_); matrix U,V; - rvector_t S(min(C.GetRows(), C.GetColumns())); + rvector_t S(std::min(C.GetRows(), C.GetColumns())); #ifdef DEBUG - cout << "Input matrix before SVD =" << endl << C ; + std::cout << "Input matrix before SVD =" << std::endl << C ; #endif csvd_wrapper(C, U, S, V); reduce_zeros(U, S, V); #ifdef DEBUG - cout << "matrices after SVD:" <= 0 - int i = 0, j = 0, k = 0, k1 = 0, l = 0, l1 = 0; - complex_t q = 0; - // Transpose when m < n - bool transposed = false; - if (m < n) + int m = A.GetRows(), n = A.GetColumns(), size = std::max(m,n); + rvector_t b(size,0.0), c(size,0.0), t(size,0.0); + double cs = 0.0, eps = 0.0, f = 0.0 ,g = 0.0, h = 0.0, sn = 0.0 , w = 0.0, x = 0.0, y = 0.0, z = 0.0; + double eta = 1e-10, tol = 1.5e-34; + // using int and not uint_t because uint_t caused bugs in loops with condition of >= 0 + int i = 0, j = 0, k = 0, k1 = 0, l = 0, l1 = 0; + complex_t q = 0; + // Transpose when m < n + bool transposed = false; + if (m < n) { transposed = true; A = AER::Utils::dagger(A); - swap(m,n); + std::swap(m,n); } cmatrix_t temp_A = A; c[0] = 0; @@ -131,9 +130,9 @@ status csvd(cmatrix_t &A, cmatrix_t &U,rvector_t &S,cmatrix_t &V) b[k] = 0.0; if ( tol < z ) { - z = sqrt( z ); + z = std::sqrt( z ); b[k] = z; - w = abs( A(k,k) ); + w = std::abs( A(k,k) ); if ( w == 0.0 ) { q = complex_t( 1.0, 0.0 ); } @@ -149,7 +148,7 @@ status csvd(cmatrix_t &A, cmatrix_t &U,rvector_t &S,cmatrix_t &V) q = complex_t( 0.0, 0.0 ); for( i = k; i < m; i++){ - q = q + conj( A(i,k) ) * A(i,j); + q = q + std::conj( A(i,k) ) * A(i,j); } q = q / ( z * ( z + w ) ); @@ -161,7 +160,7 @@ status csvd(cmatrix_t &A, cmatrix_t &U,rvector_t &S,cmatrix_t &V) // // Phase transformation. // - q = -conj(A(k,k))/abs(A(k,k)); + q = -std::conj(A(k,k))/std::abs(A(k,k)); for( j = k1; j < n; j++){ A(k,j) = q * A(k,j); @@ -178,9 +177,9 @@ status csvd(cmatrix_t &A, cmatrix_t &U,rvector_t &S,cmatrix_t &V) if ( tol < z ) { - z = sqrt( z ); + z = std::sqrt( z ); c[k1] = z; - w = abs( A(k,k1) ); + w = std::abs( A(k,k1) ); if ( w == 0.0 ){ q = complex_t( 1.0, 0.0 ); @@ -195,7 +194,7 @@ status csvd(cmatrix_t &A, cmatrix_t &U,rvector_t &S,cmatrix_t &V) q = complex_t( 0.0, 0.0 ); for( j = k1; j < n; j++){ - q = q + conj( A(k,j) ) * A(i,j); + q = q + std::conj( A(k,j) ) * A(i,j); } q = q / ( z * ( z + w ) ); @@ -206,7 +205,7 @@ status csvd(cmatrix_t &A, cmatrix_t &U,rvector_t &S,cmatrix_t &V) // // Phase transformation. // - q = -conj(A(k,k1) )/abs(A(k,k1)); + q = -std::conj(A(k,k1) )/std::abs(A(k,k1)); for( i = k1; i < m; i++){ A(i,k1) = A(i,k1) * q; } @@ -219,7 +218,7 @@ status csvd(cmatrix_t &A, cmatrix_t &U,rvector_t &S,cmatrix_t &V) { S[k] = b[k]; t[k] = c[k]; - eps = max( eps, S[k] + t[k] ); + eps = std::max( eps, S[k] + t[k] ); } eps = eps * eta; @@ -254,12 +253,12 @@ status csvd(cmatrix_t &A, cmatrix_t &U,rvector_t &S,cmatrix_t &V) for( l = k; l >= 0; l--) { - if ( abs( t[l] ) < eps ) + if ( std::abs( t[l] ) < eps ) { jump = true; break; } - else if ( abs( S[l-1] ) < eps ) { + else if ( std::abs( S[l-1] ) < eps ) { break; } } @@ -274,19 +273,19 @@ status csvd(cmatrix_t &A, cmatrix_t &U,rvector_t &S,cmatrix_t &V) f = sn * t[i]; t[i] = cs * t[i]; - if ( abs(f) < eps ) { + if ( std::abs(f) < eps ) { break; } h = S[i]; - w = sqrt( f * f + h * h ); + w = std::sqrt( f * f + h * h ); S[i] = w; cs = h / w; sn = - f / w; for( j = 0; j < n; j++) { - x = real( U(j,l1) ); - y = real( U(j,i) ); + x = std::real( U(j,l1) ); + y = std::real( U(j,i) ); U(j,l1) = complex_t( x * cs + y * sn, 0.0 ); U(j,i) = complex_t( y * cs - x * sn, 0.0 ); } @@ -301,7 +300,7 @@ status csvd(cmatrix_t &A, cmatrix_t &U,rvector_t &S,cmatrix_t &V) g = t[k-1]; h = t[k]; f = ( ( y - w ) * ( y + w ) + ( g - h ) * ( g + h ) )/ ( 2.0 * h * y ); - g = sqrt( f * f + 1.0 ); + g = std::sqrt( f * f + 1.0 ); if ( f < -1.0e-13){ //if ( f < 0.0){ //didn't work when f was negative very close to 0 (because of numerical reasons) g = -g; } @@ -315,11 +314,11 @@ status csvd(cmatrix_t &A, cmatrix_t &U,rvector_t &S,cmatrix_t &V) y = S[i]; h = sn * g; g = cs * g; - w = sqrt( h * h + f * f ); + w = std::sqrt( h * h + f * f ); if (w == 0) { #ifdef DEBUG - cout << "ERROR 1: w is exactly 0: h = " << h << " , f = " << f << endl; - cout << " w = " << w << endl; + std::cout << "ERROR 1: w is exactly 0: h = " << h << " , f = " << f << std::endl; + std::cout << " w = " << w << std::endl; #endif } t[i-1] = w; @@ -330,7 +329,7 @@ status csvd(cmatrix_t &A, cmatrix_t &U,rvector_t &S,cmatrix_t &V) long double large_f = 0; if (f==0) { #ifdef DEBUG - cout << "f == 0 because " << "x = " << x << ", cs = " << cs << ", g = " << g << ", sn = " << sn <; - //using complex_t = std::complex; - //using cvector_t = std::vector; - //using rvector_t = std::vector; - //using rmatrix_t = matrix; - //using cmatrix_t = matrix; enum status {SUCCESS, FAILURE}; -cmatrix_t reshape_before_SVD(vector data); -vector reshape_U_after_SVD(cmatrix_t U); + cmatrix_t reshape_before_SVD(std::vector data); +std::vector reshape_U_after_SVD(cmatrix_t U); rvector_t reshape_S_after_SVD(rvector_t S); -vector reshape_V_after_SVD(const cmatrix_t V); +std::vector reshape_V_after_SVD(const cmatrix_t V); uint_t num_of_SV(rvector_t S, double threshold); void reduce_zeros(cmatrix_t &U, rvector_t &S, cmatrix_t &V); status csvd(cmatrix_t &C, cmatrix_t &U,rvector_t &S,cmatrix_t &V); From 43580139161c5b96456ff984fa84a47c5fbcca9a Mon Sep 17 00:00:00 2001 From: "Christopher J. Wood" Date: Fri, 6 Dec 2019 11:27:48 -0500 Subject: [PATCH 09/12] Fix bug in unitary simulator cu3 and add cu3 tests (#483) --- CHANGELOG.md | 1 + src/simulators/unitary/unitary_state.hpp | 4 +- .../qasm_simulator/qasm_noncliffords.py | 144 ++- .../backends/test_statevector_simulator.py | 33 + test/terra/backends/test_unitary_simulator.py | 531 ++++++-- test/terra/reference/ref_non_clifford.py | 1123 +++++++++-------- 6 files changed, 1143 insertions(+), 693 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eeab407ced..e1c8c9ecd2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ Removed Fixed ----- +- Fixes bug where cu3 was being applied as cu1 for unitary_simulator (\#483) [0.3.3](https://github.com/Qiskit/qiskit-aer/compare/0.3.2...0.3.3) - 2019-11-14 ==================================================================================== diff --git a/src/simulators/unitary/unitary_state.hpp b/src/simulators/unitary/unitary_state.hpp index ffc05e8460..16c10ef5c1 100755 --- a/src/simulators/unitary/unitary_state.hpp +++ b/src/simulators/unitary/unitary_state.hpp @@ -192,8 +192,8 @@ const stringmap_t State::gateset_({ {"cy", Gates::mcy}, // Controlled-Z gate {"cz", Gates::mcz}, // Controlled-Z gate {"cu1", Gates::mcu1}, // Controlled-u1 gate - {"cu2", Gates::mcu2}, // Controlled-u2 - {"cu3", Gates::mcu1}, // Controlled-u3 gate + {"cu2", Gates::mcu2}, // Controlled-u2 + {"cu3", Gates::mcu3}, // Controlled-u3 gate {"swap", Gates::mcswap}, // SWAP gate // Three-qubit gates {"ccx", Gates::mcx}, // Controlled-CX gate (Toffoli) diff --git a/test/terra/backends/qasm_simulator/qasm_noncliffords.py b/test/terra/backends/qasm_simulator/qasm_noncliffords.py index 1b4a2f28c0..ef5548a45f 100644 --- a/test/terra/backends/qasm_simulator/qasm_noncliffords.py +++ b/test/terra/backends/qasm_simulator/qasm_noncliffords.py @@ -136,6 +136,20 @@ def test_cu1_gate_nondeterministic_default_basis_gates(self): self.assertTrue(getattr(result, 'success', False)) self.compare_counts(result, circuits, targets, delta=0.05 * shots) + # --------------------------------------------------------------------- + # Test cu3 gate + # --------------------------------------------------------------------- + def test_cu3_gate_deterministic_default_basis_gates(self): + """Test cu3-gate gate circuits compiling to default basis.""" + shots = 100 + circuits = ref_non_clifford.cu3_gate_circuits_deterministic( + final_measure=True) + targets = ref_non_clifford.cu3_gate_counts_deterministic(shots) + job = execute(circuits, self.SIMULATOR, shots=shots) + result = job.result() + self.assertTrue(getattr(result, 'success', False)) + self.compare_counts(result, circuits, targets, delta=0) + class QasmNonCliffordTestsWaltzBasis: """QasmSimulator non-Clifford gate tests in minimal u1,u2,u3,cx basis.""" @@ -152,7 +166,10 @@ def test_t_gate_deterministic_waltz_basis_gates(self): circuits = ref_non_clifford.t_gate_circuits_deterministic( final_measure=True) targets = ref_non_clifford.t_gate_counts_deterministic(shots) - job = execute(circuits, self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + self.SIMULATOR, + shots=shots, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_counts(result, circuits, targets, delta=0) @@ -163,7 +180,10 @@ def test_t_gate_nondeterministic_waltz_basis_gates(self): circuits = ref_non_clifford.t_gate_circuits_nondeterministic( final_measure=True) targets = ref_non_clifford.t_gate_counts_nondeterministic(shots) - job = execute(circuits, self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + self.SIMULATOR, + shots=shots, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -177,7 +197,10 @@ def test_tdg_gate_deterministic_waltz_basis_gates(self): circuits = ref_non_clifford.tdg_gate_circuits_deterministic( final_measure=True) targets = ref_non_clifford.tdg_gate_counts_deterministic(shots) - job = execute(circuits, self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + self.SIMULATOR, + shots=shots, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_counts(result, circuits, targets, delta=0) @@ -188,7 +211,10 @@ def test_tdg_gate_nondeterministic_waltz_basis_gates(self): circuits = ref_non_clifford.tdg_gate_circuits_nondeterministic( final_measure=True) targets = ref_non_clifford.tdg_gate_counts_nondeterministic(shots) - job = execute(circuits, self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + self.SIMULATOR, + shots=shots, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -202,7 +228,10 @@ def test_ccx_gate_deterministic_waltz_basis_gates(self): circuits = ref_non_clifford.ccx_gate_circuits_deterministic( final_measure=True) targets = ref_non_clifford.ccx_gate_counts_deterministic(shots) - job = execute(circuits, self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + self.SIMULATOR, + shots=shots, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_counts(result, circuits, targets, delta=0) @@ -213,7 +242,10 @@ def test_ccx_gate_nondeterministic_waltz_basis_gates(self): circuits = ref_non_clifford.ccx_gate_circuits_nondeterministic( final_measure=True) targets = ref_non_clifford.ccx_gate_counts_nondeterministic(shots) - job = execute(circuits, self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + self.SIMULATOR, + shots=shots, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -227,7 +259,10 @@ def test_cswap_gate_deterministic_waltz_basis_gates(self): circuits = ref_non_clifford.cswap_gate_circuits_deterministic( final_measure=True) targets = ref_non_clifford.cswap_gate_counts_deterministic(shots) - job = execute(circuits, self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + self.SIMULATOR, + shots=shots, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_counts(result, circuits, targets, delta=0) @@ -238,7 +273,10 @@ def test_cswap_gate_nondeterministic_waltz_basis_gates(self): circuits = ref_non_clifford.cswap_gate_circuits_nondeterministic( final_measure=True) targets = ref_non_clifford.cswap_gate_counts_nondeterministic(shots) - job = execute(circuits, self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + self.SIMULATOR, + shots=shots, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -252,11 +290,31 @@ def test_cu1_gate_nondeterministic_waltz_basis_gates(self): circuits = ref_non_clifford.cu1_gate_circuits_nondeterministic( final_measure=True) targets = ref_non_clifford.cu1_gate_counts_nondeterministic(shots) - job = execute(circuits, self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + self.SIMULATOR, + shots=shots, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_counts(result, circuits, targets, delta=0.05 * shots) + # --------------------------------------------------------------------- + # Test cu3 gate + # --------------------------------------------------------------------- + def test_cu3_gate_deterministic_default_basis_gates(self): + """Test cu3-gate gate circuits compiling to u1,u2,u3,cx.""" + shots = 100 + circuits = ref_non_clifford.cu3_gate_circuits_deterministic( + final_measure=True) + targets = ref_non_clifford.cu3_gate_counts_deterministic(shots) + job = execute(circuits, + self.SIMULATOR, + shots=shots, + basis_gates=['u1', 'u2', 'u3', 'cx']) + result = job.result() + self.assertTrue(getattr(result, 'success', False)) + self.compare_counts(result, circuits, targets, delta=0) + class QasmNonCliffordTestsMinimalBasis: """QasmSimulator non-Clifford gate tests in minimal U,CX basis.""" @@ -273,7 +331,10 @@ def test_t_gate_deterministic_minimal_basis_gates(self): circuits = ref_non_clifford.t_gate_circuits_deterministic( final_measure=True) targets = ref_non_clifford.t_gate_counts_deterministic(shots) - job = execute(circuits, self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx']) + job = execute(circuits, + self.SIMULATOR, + shots=shots, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_counts(result, circuits, targets, delta=0) @@ -284,7 +345,10 @@ def test_t_gate_nondeterministic_minimal_basis_gates(self): circuits = ref_non_clifford.t_gate_circuits_nondeterministic( final_measure=True) targets = ref_non_clifford.t_gate_counts_nondeterministic(shots) - job = execute(circuits, self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx']) + job = execute(circuits, + self.SIMULATOR, + shots=shots, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -298,7 +362,10 @@ def test_tdg_gate_deterministic_minimal_basis_gates(self): circuits = ref_non_clifford.tdg_gate_circuits_deterministic( final_measure=True) targets = ref_non_clifford.tdg_gate_counts_deterministic(shots) - job = execute(circuits, self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx']) + job = execute(circuits, + self.SIMULATOR, + shots=shots, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_counts(result, circuits, targets, delta=0) @@ -309,7 +376,10 @@ def test_tdg_gate_nondeterministic_minimal_basis_gates(self): circuits = ref_non_clifford.tdg_gate_circuits_nondeterministic( final_measure=True) targets = ref_non_clifford.tdg_gate_counts_nondeterministic(shots) - job = execute(circuits, self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx']) + job = execute(circuits, + self.SIMULATOR, + shots=shots, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -323,7 +393,10 @@ def test_ccx_gate_deterministic_minimal_basis_gates(self): circuits = ref_non_clifford.ccx_gate_circuits_deterministic( final_measure=True) targets = ref_non_clifford.ccx_gate_counts_deterministic(shots) - job = execute(circuits, self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx']) + job = execute(circuits, + self.SIMULATOR, + shots=shots, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_counts(result, circuits, targets, delta=0) @@ -334,7 +407,10 @@ def test_ccx_gate_nondeterministic_minimal_basis_gates(self): circuits = ref_non_clifford.ccx_gate_circuits_nondeterministic( final_measure=True) targets = ref_non_clifford.ccx_gate_counts_nondeterministic(shots) - job = execute(circuits, self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx']) + job = execute(circuits, + self.SIMULATOR, + shots=shots, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_counts(result, circuits, targets, delta=0.1 * shots) @@ -348,7 +424,10 @@ def test_cu1_gate_nondeterministic_minimal_basis_gates(self): circuits = ref_non_clifford.cu1_gate_circuits_nondeterministic( final_measure=True) targets = ref_non_clifford.cu1_gate_counts_nondeterministic(shots) - job = execute(circuits, self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx']) + job = execute(circuits, + self.SIMULATOR, + shots=shots, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_counts(result, circuits, targets, delta=0.1 * shots) @@ -361,7 +440,8 @@ def test_multiplexer_cxx_gate_deterministic_default_basis_gates(self): shots = 100 circuits = ref_non_clifford.multiplexer_ccx_gate_circuits_deterministic( final_measure=True) - targets = ref_non_clifford.multiplexer_ccx_gate_counts_deterministic(shots) + targets = ref_non_clifford.multiplexer_ccx_gate_counts_deterministic( + shots) job = execute(circuits, self.SIMULATOR, shots=shots) result = job.result() self.assertTrue(getattr(result, 'success', False)) @@ -372,7 +452,8 @@ def test_multiplexer_cxx_gate_nondeterministic_default_basis_gates(self): shots = 2000 circuits = ref_non_clifford.multiplexer_ccx_gate_circuits_nondeterministic( final_measure=True) - targets = ref_non_clifford.multiplexer_ccx_gate_counts_nondeterministic(shots) + targets = ref_non_clifford.multiplexer_ccx_gate_counts_nondeterministic( + shots) job = execute(circuits, self.SIMULATOR, shots=shots) result = job.result() self.assertTrue(getattr(result, 'success', False)) @@ -387,7 +468,10 @@ def test_cswap_gate_deterministic_minimal_basis_gates(self): circuits = ref_non_clifford.cswap_gate_circuits_deterministic( final_measure=True) targets = ref_non_clifford.cswap_gate_counts_deterministic(shots) - job = execute(circuits, self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx']) + job = execute(circuits, + self.SIMULATOR, + shots=shots, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_counts(result, circuits, targets, delta=0) @@ -398,7 +482,27 @@ def test_cswap_gate_nondeterministic_minimal_basis_gates(self): circuits = ref_non_clifford.cswap_gate_circuits_nondeterministic( final_measure=True) targets = ref_non_clifford.cswap_gate_counts_nondeterministic(shots) - job = execute(circuits, self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx']) + job = execute(circuits, + self.SIMULATOR, + shots=shots, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_counts(result, circuits, targets, delta=0.1 * shots) + + # --------------------------------------------------------------------- + # Test cu3 gate + # --------------------------------------------------------------------- + def test_cu3_gate_deterministic_default_basis_gates(self): + """Test cu3-gate gate circuits compiling to u3, cx.""" + shots = 100 + circuits = ref_non_clifford.cu3_gate_circuits_deterministic( + final_measure=True) + targets = ref_non_clifford.cu3_gate_counts_deterministic(shots) + job = execute(circuits, + self.SIMULATOR, + shots=shots, + basis_gates=['u3', 'cx']) + result = job.result() + self.assertTrue(getattr(result, 'success', False)) + self.compare_counts(result, circuits, targets, delta=0) diff --git a/test/terra/backends/test_statevector_simulator.py b/test/terra/backends/test_statevector_simulator.py index bc18de591e..392502d7db 100644 --- a/test/terra/backends/test_statevector_simulator.py +++ b/test/terra/backends/test_statevector_simulator.py @@ -882,6 +882,39 @@ def test_cswap_gate_nondeterministic_waltz_basis_gates(self): self.assertTrue(getattr(result, 'success', False)) self.compare_statevector(result, circuits, targets) + # --------------------------------------------------------------------- + # Test cu3-gate (Fredkin) + # --------------------------------------------------------------------- + + def test_cu3_gate_deterministic_default_basis_gates(self): + """Test cu3-gate circuits compiling to backend default basis_gates.""" + circuits = ref_non_clifford.cu3_gate_circuits_deterministic(final_measure=False) + targets = ref_non_clifford.cu3_gate_statevector_deterministic() + job = execute(circuits, StatevectorSimulator(), shots=1) + result = job.result() + self.assertTrue(getattr(result, 'success', False)) + self.compare_statevector(result, circuits, targets) + + def test_cu3_gate_deterministic_minimal_basis_gates(self): + """Test cu3-gate gate circuits compiling to u3,cx""" + circuits = ref_non_clifford.cu3_gate_circuits_deterministic( + final_measure=True) + targets = ref_non_clifford.cu3_gate_statevector_deterministic() + job = execute(circuits, StatevectorSimulator(), shots=1, basis_gates=['u3', 'cx']) + result = job.result() + self.assertTrue(getattr(result, 'success', False)) + self.compare_statevector(result, circuits, targets) + + def test_cu3_gate_deterministic_waltz_basis_gates(self): + """Test cu3-gate gate circuits compiling to u1,u2,u3,cx""" + circuits = ref_non_clifford.cu3_gate_circuits_deterministic(final_measure=False) + targets = ref_non_clifford.cu3_gate_statevector_deterministic() + job = execute(circuits, StatevectorSimulator(), shots=1, + basis_gates=['u1', 'u2', 'u3', 'cx']) + result = job.result() + self.assertTrue(getattr(result, 'success', False)) + self.compare_statevector(result, circuits, targets) + if __name__ == '__main__': unittest.main() diff --git a/test/terra/backends/test_unitary_simulator.py b/test/terra/backends/test_unitary_simulator.py index a702ddd6a9..a3a0fa1d5b 100644 --- a/test/terra/backends/test_unitary_simulator.py +++ b/test/terra/backends/test_unitary_simulator.py @@ -9,7 +9,6 @@ # Any modifications or derivative works of this code must retain this # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. - """ UnitarySimulator Integration Tests """ @@ -33,7 +32,8 @@ class TestUnitarySimulator(common.QiskitAerTestCase): # --------------------------------------------------------------------- def test_h_gate_deterministic_default_basis_gates(self): """Test h-gate circuits compiling to backend default basis_gates.""" - circuits = ref_1q_clifford.h_gate_circuits_deterministic(final_measure=False) + circuits = ref_1q_clifford.h_gate_circuits_deterministic( + final_measure=False) targets = ref_1q_clifford.h_gate_unitary_deterministic() job = execute(circuits, UnitarySimulator(), shots=1) result = job.result() @@ -42,25 +42,34 @@ def test_h_gate_deterministic_default_basis_gates(self): def test_h_gate_deterministic_waltz_basis_gates(self): """Test h-gate gate circuits compiling to u1,u2,u3,cx""" - circuits = ref_1q_clifford.h_gate_circuits_deterministic(final_measure=False) + circuits = ref_1q_clifford.h_gate_circuits_deterministic( + final_measure=False) targets = ref_1q_clifford.h_gate_unitary_deterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_h_gate_deterministic_minimal_basis_gates(self): """Test h-gate gate circuits compiling to u3,cx""" - circuits = ref_1q_clifford.h_gate_circuits_deterministic(final_measure=False) + circuits = ref_1q_clifford.h_gate_circuits_deterministic( + final_measure=False) targets = ref_1q_clifford.h_gate_unitary_deterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_h_gate_nondeterministic_default_basis_gates(self): """Test h-gate circuits compiling to backend default basis_gates.""" - circuits = ref_1q_clifford.h_gate_circuits_nondeterministic(final_measure=False) + circuits = ref_1q_clifford.h_gate_circuits_nondeterministic( + final_measure=False) targets = ref_1q_clifford.h_gate_unitary_nondeterministic() job = execute(circuits, UnitarySimulator(), shots=1) result = job.result() @@ -69,18 +78,26 @@ def test_h_gate_nondeterministic_default_basis_gates(self): def test_h_gate_nondeterministic_waltz_basis_gates(self): """Test h-gate gate circuits compiling to u1,u2,u3,cx""" - circuits = ref_1q_clifford.h_gate_circuits_nondeterministic(final_measure=False) + circuits = ref_1q_clifford.h_gate_circuits_nondeterministic( + final_measure=False) targets = ref_1q_clifford.h_gate_unitary_nondeterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_h_gate_nondeterministic_minimal_basis_gates(self): """Test h-gate gate circuits compiling to u3,cx""" - circuits = ref_1q_clifford.h_gate_circuits_nondeterministic(final_measure=False) + circuits = ref_1q_clifford.h_gate_circuits_nondeterministic( + final_measure=False) targets = ref_1q_clifford.h_gate_unitary_nondeterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) @@ -90,7 +107,8 @@ def test_h_gate_nondeterministic_minimal_basis_gates(self): # --------------------------------------------------------------------- def test_x_gate_deterministic_default_basis_gates(self): """Test x-gate circuits compiling to backend default basis_gates.""" - circuits = ref_1q_clifford.x_gate_circuits_deterministic(final_measure=False) + circuits = ref_1q_clifford.x_gate_circuits_deterministic( + final_measure=False) targets = ref_1q_clifford.x_gate_unitary_deterministic() job = execute(circuits, UnitarySimulator(), shots=1) result = job.result() @@ -99,18 +117,26 @@ def test_x_gate_deterministic_default_basis_gates(self): def test_x_gate_deterministic_waltz_basis_gates(self): """Test x-gate gate circuits compiling to u1,u2,u3,cx""" - circuits = ref_1q_clifford.x_gate_circuits_deterministic(final_measure=False) + circuits = ref_1q_clifford.x_gate_circuits_deterministic( + final_measure=False) targets = ref_1q_clifford.x_gate_unitary_deterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_x_gate_deterministic_minimal_basis_gates(self): """Test x-gate gate circuits compiling to u3,cx""" - circuits = ref_1q_clifford.x_gate_circuits_deterministic(final_measure=False) + circuits = ref_1q_clifford.x_gate_circuits_deterministic( + final_measure=False) targets = ref_1q_clifford.x_gate_unitary_deterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) @@ -120,7 +146,8 @@ def test_x_gate_deterministic_minimal_basis_gates(self): # --------------------------------------------------------------------- def test_z_gate_deterministic_default_basis_gates(self): """Test z-gate circuits compiling to backend default basis_gates.""" - circuits = ref_1q_clifford.z_gate_circuits_deterministic(final_measure=False) + circuits = ref_1q_clifford.z_gate_circuits_deterministic( + final_measure=False) targets = ref_1q_clifford.z_gate_unitary_deterministic() job = execute(circuits, UnitarySimulator(), shots=1) result = job.result() @@ -129,18 +156,26 @@ def test_z_gate_deterministic_default_basis_gates(self): def test_z_gate_deterministic_waltz_basis_gates(self): """Test z-gate gate circuits compiling to u1,u2,u3,cx""" - circuits = ref_1q_clifford.z_gate_circuits_deterministic(final_measure=False) + circuits = ref_1q_clifford.z_gate_circuits_deterministic( + final_measure=False) targets = ref_1q_clifford.z_gate_unitary_deterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_z_gate_deterministic_minimal_basis_gates(self): """Test z-gate gate circuits compiling to u3,cx""" - circuits = ref_1q_clifford.z_gate_circuits_deterministic(final_measure=False) + circuits = ref_1q_clifford.z_gate_circuits_deterministic( + final_measure=False) targets = ref_1q_clifford.z_gate_unitary_deterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) @@ -150,7 +185,8 @@ def test_z_gate_deterministic_minimal_basis_gates(self): # --------------------------------------------------------------------- def test_y_gate_deterministic_default_basis_gates(self): """Test y-gate circuits compiling to backend default basis_gates.""" - circuits = ref_1q_clifford.y_gate_circuits_deterministic(final_measure=False) + circuits = ref_1q_clifford.y_gate_circuits_deterministic( + final_measure=False) targets = ref_1q_clifford.y_gate_unitary_deterministic() job = execute(circuits, UnitarySimulator(), shots=1) result = job.result() @@ -159,18 +195,26 @@ def test_y_gate_deterministic_default_basis_gates(self): def test_y_gate_deterministic_waltz_basis_gates(self): """Test y-gate gate circuits compiling to u1,u2,u3,cx.""" - circuits = ref_1q_clifford.y_gate_circuits_deterministic(final_measure=False) + circuits = ref_1q_clifford.y_gate_circuits_deterministic( + final_measure=False) targets = ref_1q_clifford.y_gate_unitary_deterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_y_gate_deterministic_minimal_basis_gates(self): """Test y-gate gate circuits compiling to u3, cx.""" - circuits = ref_1q_clifford.y_gate_circuits_deterministic(final_measure=False) + circuits = ref_1q_clifford.y_gate_circuits_deterministic( + final_measure=False) targets = ref_1q_clifford.y_gate_unitary_deterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) @@ -180,7 +224,8 @@ def test_y_gate_deterministic_minimal_basis_gates(self): # --------------------------------------------------------------------- def test_s_gate_deterministic_default_basis_gates(self): """Test s-gate circuits compiling to backend default basis_gates.""" - circuits = ref_1q_clifford.s_gate_circuits_deterministic(final_measure=False) + circuits = ref_1q_clifford.s_gate_circuits_deterministic( + final_measure=False) targets = ref_1q_clifford.s_gate_unitary_deterministic() job = execute(circuits, UnitarySimulator(), shots=1) result = job.result() @@ -189,25 +234,34 @@ def test_s_gate_deterministic_default_basis_gates(self): def test_s_gate_deterministic_waltz_basis_gates(self): """Test s-gate gate circuits compiling to u1,u2,u3,cx""" - circuits = ref_1q_clifford.s_gate_circuits_deterministic(final_measure=False) + circuits = ref_1q_clifford.s_gate_circuits_deterministic( + final_measure=False) targets = ref_1q_clifford.s_gate_unitary_deterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_s_gate_deterministic_minimal_basis_gates(self): """Test s-gate gate circuits compiling to u3,cx""" - circuits = ref_1q_clifford.s_gate_circuits_deterministic(final_measure=False) + circuits = ref_1q_clifford.s_gate_circuits_deterministic( + final_measure=False) targets = ref_1q_clifford.s_gate_unitary_deterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_s_gate_nondeterministic_default_basis_gates(self): """Test s-gate circuits compiling to backend default basis_gates.""" - circuits = ref_1q_clifford.s_gate_circuits_nondeterministic(final_measure=False) + circuits = ref_1q_clifford.s_gate_circuits_nondeterministic( + final_measure=False) targets = ref_1q_clifford.s_gate_unitary_nondeterministic() job = execute(circuits, UnitarySimulator(), shots=1) result = job.result() @@ -216,18 +270,26 @@ def test_s_gate_nondeterministic_default_basis_gates(self): def test_s_gate_nondeterministic_waltz_basis_gates(self): """Test s-gate gate circuits compiling to u1,u2,u3,cx""" - circuits = ref_1q_clifford.s_gate_circuits_nondeterministic(final_measure=False) + circuits = ref_1q_clifford.s_gate_circuits_nondeterministic( + final_measure=False) targets = ref_1q_clifford.s_gate_unitary_nondeterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_s_gate_nondeterministic_minimal_basis_gates(self): """Test s-gate gate circuits compiling to u3,cx""" - circuits = ref_1q_clifford.s_gate_circuits_nondeterministic(final_measure=False) + circuits = ref_1q_clifford.s_gate_circuits_nondeterministic( + final_measure=False) targets = ref_1q_clifford.s_gate_unitary_nondeterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) @@ -237,7 +299,8 @@ def test_s_gate_nondeterministic_minimal_basis_gates(self): # --------------------------------------------------------------------- def test_sdg_gate_deterministic_default_basis_gates(self): """Test sdg-gate circuits compiling to backend default basis_gates.""" - circuits = ref_1q_clifford.sdg_gate_circuits_deterministic(final_measure=False) + circuits = ref_1q_clifford.sdg_gate_circuits_deterministic( + final_measure=False) targets = ref_1q_clifford.sdg_gate_unitary_deterministic() job = execute(circuits, UnitarySimulator(), shots=1) result = job.result() @@ -246,25 +309,34 @@ def test_sdg_gate_deterministic_default_basis_gates(self): def test_sdg_gate_deterministic_waltz_basis_gates(self): """Test sdg-gate gate circuits compiling to u1,u2,u3,cx""" - circuits = ref_1q_clifford.sdg_gate_circuits_deterministic(final_measure=False) + circuits = ref_1q_clifford.sdg_gate_circuits_deterministic( + final_measure=False) targets = ref_1q_clifford.sdg_gate_unitary_deterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_sdg_gate_deterministic_minimal_basis_gates(self): """Test sdg-gate gate circuits compiling to u3,cx""" - circuits = ref_1q_clifford.sdg_gate_circuits_deterministic(final_measure=False) + circuits = ref_1q_clifford.sdg_gate_circuits_deterministic( + final_measure=False) targets = ref_1q_clifford.sdg_gate_unitary_deterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_sdg_gate_nondeterministic_default_basis_gates(self): """Test sdg-gate circuits compiling to backend default basis_gates.""" - circuits = ref_1q_clifford.sdg_gate_circuits_nondeterministic(final_measure=False) + circuits = ref_1q_clifford.sdg_gate_circuits_nondeterministic( + final_measure=False) targets = ref_1q_clifford.sdg_gate_unitary_nondeterministic() job = execute(circuits, UnitarySimulator(), shots=1) result = job.result() @@ -273,18 +345,26 @@ def test_sdg_gate_nondeterministic_default_basis_gates(self): def test_sdg_gate_nondeterministic_waltz_basis_gates(self): """Test sdg-gate gate circuits compiling to u1,u2,u3,cx""" - circuits = ref_1q_clifford.sdg_gate_circuits_nondeterministic(final_measure=False) + circuits = ref_1q_clifford.sdg_gate_circuits_nondeterministic( + final_measure=False) targets = ref_1q_clifford.sdg_gate_unitary_nondeterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_sdg_gate_nondeterministic_minimal_basis_gates(self): """Test sdg-gate gate circuits compiling to u3,cx""" - circuits = ref_1q_clifford.sdg_gate_circuits_nondeterministic(final_measure=False) + circuits = ref_1q_clifford.sdg_gate_circuits_nondeterministic( + final_measure=False) targets = ref_1q_clifford.sdg_gate_unitary_nondeterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) @@ -294,7 +374,8 @@ def test_sdg_gate_nondeterministic_minimal_basis_gates(self): # --------------------------------------------------------------------- def test_cx_gate_deterministic_default_basis_gates(self): """Test cx-gate circuits compiling to backend default basis_gates.""" - circuits = ref_2q_clifford.cx_gate_circuits_deterministic(final_measure=False) + circuits = ref_2q_clifford.cx_gate_circuits_deterministic( + final_measure=False) targets = ref_2q_clifford.cx_gate_unitary_deterministic() job = execute(circuits, UnitarySimulator(), shots=1) result = job.result() @@ -303,25 +384,34 @@ def test_cx_gate_deterministic_default_basis_gates(self): def test_cx_gate_deterministic_waltz_basis_gates(self): """Test cx-gate gate circuits compiling to u1,u2,u3,cx""" - circuits = ref_2q_clifford.cx_gate_circuits_deterministic(final_measure=False) + circuits = ref_2q_clifford.cx_gate_circuits_deterministic( + final_measure=False) targets = ref_2q_clifford.cx_gate_unitary_deterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_cx_gate_deterministic_minimal_basis_gates(self): """Test cx-gate gate circuits compiling to u3,cx""" - circuits = ref_2q_clifford.cx_gate_circuits_deterministic(final_measure=False) + circuits = ref_2q_clifford.cx_gate_circuits_deterministic( + final_measure=False) targets = ref_2q_clifford.cx_gate_unitary_deterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_cx_gate_nondeterministic_default_basis_gates(self): """Test cx-gate circuits compiling to backend default basis_gates.""" - circuits = ref_2q_clifford.cx_gate_circuits_nondeterministic(final_measure=False) + circuits = ref_2q_clifford.cx_gate_circuits_nondeterministic( + final_measure=False) targets = ref_2q_clifford.cx_gate_unitary_nondeterministic() job = execute(circuits, UnitarySimulator(), shots=1) result = job.result() @@ -330,18 +420,26 @@ def test_cx_gate_nondeterministic_default_basis_gates(self): def test_cx_gate_nondeterministic_waltz_basis_gates(self): """Test cx-gate gate circuits compiling to u1,u2,u3,cx""" - circuits = ref_2q_clifford.cx_gate_circuits_nondeterministic(final_measure=False) + circuits = ref_2q_clifford.cx_gate_circuits_nondeterministic( + final_measure=False) targets = ref_2q_clifford.cx_gate_unitary_nondeterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_cx_gate_nondeterministic_minimal_basis_gates(self): """Test cx-gate gate circuits compiling to u3,cx""" - circuits = ref_2q_clifford.cx_gate_circuits_nondeterministic(final_measure=False) + circuits = ref_2q_clifford.cx_gate_circuits_nondeterministic( + final_measure=False) targets = ref_2q_clifford.cx_gate_unitary_nondeterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) @@ -351,7 +449,8 @@ def test_cx_gate_nondeterministic_minimal_basis_gates(self): # --------------------------------------------------------------------- def test_cz_gate_deterministic_default_basis_gates(self): """Test cz-gate circuits compiling to backend default basis_gates.""" - circuits = ref_2q_clifford.cz_gate_circuits_deterministic(final_measure=False) + circuits = ref_2q_clifford.cz_gate_circuits_deterministic( + final_measure=False) targets = ref_2q_clifford.cz_gate_unitary_deterministic() job = execute(circuits, UnitarySimulator(), shots=1) result = job.result() @@ -360,25 +459,34 @@ def test_cz_gate_deterministic_default_basis_gates(self): def test_cz_gate_deterministic_waltz_basis_gates(self): """Test cz-gate gate circuits compiling to u1,u2,u3,cx""" - circuits = ref_2q_clifford.cz_gate_circuits_deterministic(final_measure=False) + circuits = ref_2q_clifford.cz_gate_circuits_deterministic( + final_measure=False) targets = ref_2q_clifford.cz_gate_unitary_deterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_cz_gate_deterministic_minimal_basis_gates(self): """Test cz-gate gate circuits compiling to u3,cx""" - circuits = ref_2q_clifford.cz_gate_circuits_deterministic(final_measure=False) + circuits = ref_2q_clifford.cz_gate_circuits_deterministic( + final_measure=False) targets = ref_2q_clifford.cz_gate_unitary_deterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_cz_gate_nondeterministic_default_basis_gates(self): """Test cz-gate circuits compiling to backend default basis_gates.""" - circuits = ref_2q_clifford.cz_gate_circuits_nondeterministic(final_measure=False) + circuits = ref_2q_clifford.cz_gate_circuits_nondeterministic( + final_measure=False) targets = ref_2q_clifford.cz_gate_unitary_nondeterministic() job = execute(circuits, UnitarySimulator(), shots=1) result = job.result() @@ -387,18 +495,26 @@ def test_cz_gate_nondeterministic_default_basis_gates(self): def test_cz_gate_nondeterministic_waltz_basis_gates(self): """Test cz-gate gate circuits compiling to u1,u2,u3,cx""" - circuits = ref_2q_clifford.cz_gate_circuits_nondeterministic(final_measure=False) + circuits = ref_2q_clifford.cz_gate_circuits_nondeterministic( + final_measure=False) targets = ref_2q_clifford.cz_gate_unitary_nondeterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_cz_gate_nondeterministic_minimal_basis_gates(self): """Test cz-gate gate circuits compiling to u3,cx""" - circuits = ref_2q_clifford.cz_gate_circuits_nondeterministic(final_measure=False) + circuits = ref_2q_clifford.cz_gate_circuits_nondeterministic( + final_measure=False) targets = ref_2q_clifford.cz_gate_unitary_nondeterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) @@ -408,7 +524,8 @@ def test_cz_gate_nondeterministic_minimal_basis_gates(self): # --------------------------------------------------------------------- def test_swap_gate_deterministic_default_basis_gates(self): """Test swap-gate circuits compiling to backend default basis_gates.""" - circuits = ref_2q_clifford.swap_gate_circuits_deterministic(final_measure=False) + circuits = ref_2q_clifford.swap_gate_circuits_deterministic( + final_measure=False) targets = ref_2q_clifford.swap_gate_unitary_deterministic() job = execute(circuits, UnitarySimulator(), shots=1) result = job.result() @@ -417,25 +534,34 @@ def test_swap_gate_deterministic_default_basis_gates(self): def test_swap_gate_deterministic_waltz_basis_gates(self): """Test swap-gate gate circuits compiling to u1,u2,u3,cx""" - circuits = ref_2q_clifford.swap_gate_circuits_deterministic(final_measure=False) + circuits = ref_2q_clifford.swap_gate_circuits_deterministic( + final_measure=False) targets = ref_2q_clifford.swap_gate_unitary_deterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_swap_gate_deterministic_minimal_basis_gates(self): """Test swap-gate gate circuits compiling to u3,cx""" - circuits = ref_2q_clifford.swap_gate_circuits_deterministic(final_measure=False) + circuits = ref_2q_clifford.swap_gate_circuits_deterministic( + final_measure=False) targets = ref_2q_clifford.swap_gate_unitary_deterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_swap_gate_nondeterministic_default_basis_gates(self): """Test swap-gate circuits compiling to backend default basis_gates.""" - circuits = ref_2q_clifford.swap_gate_circuits_nondeterministic(final_measure=False) + circuits = ref_2q_clifford.swap_gate_circuits_nondeterministic( + final_measure=False) targets = ref_2q_clifford.swap_gate_unitary_nondeterministic() job = execute(circuits, UnitarySimulator(), shots=1) result = job.result() @@ -444,18 +570,26 @@ def test_swap_gate_nondeterministic_default_basis_gates(self): def test_swap_gate_nondeterministic_waltz_basis_gates(self): """Test swap-gate gate circuits compiling to u1,u2,u3,cx""" - circuits = ref_2q_clifford.swap_gate_circuits_nondeterministic(final_measure=False) + circuits = ref_2q_clifford.swap_gate_circuits_nondeterministic( + final_measure=False) targets = ref_2q_clifford.swap_gate_unitary_nondeterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_swap_gate_nondeterministic_minimal_basis_gates(self): """Test swap-gate gate circuits compiling to u3,cx""" - circuits = ref_2q_clifford.swap_gate_circuits_nondeterministic(final_measure=False) + circuits = ref_2q_clifford.swap_gate_circuits_nondeterministic( + final_measure=False) targets = ref_2q_clifford.swap_gate_unitary_nondeterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) @@ -465,7 +599,8 @@ def test_swap_gate_nondeterministic_minimal_basis_gates(self): # --------------------------------------------------------------------- def test_t_gate_deterministic_default_basis_gates(self): """Test t-gate circuits compiling to backend default basis_gates.""" - circuits = ref_non_clifford.t_gate_circuits_deterministic(final_measure=False) + circuits = ref_non_clifford.t_gate_circuits_deterministic( + final_measure=False) targets = ref_non_clifford.t_gate_unitary_deterministic() job = execute(circuits, UnitarySimulator(), shots=1) result = job.result() @@ -474,25 +609,34 @@ def test_t_gate_deterministic_default_basis_gates(self): def test_t_gate_deterministic_waltz_basis_gates(self): """Test t-gate gate circuits compiling to u1,u2,u3,cx""" - circuits = ref_non_clifford.t_gate_circuits_deterministic(final_measure=False) + circuits = ref_non_clifford.t_gate_circuits_deterministic( + final_measure=False) targets = ref_non_clifford.t_gate_unitary_deterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_t_gate_deterministic_minimal_basis_gates(self): """Test t-gate gate circuits compiling to u3,cx""" - circuits = ref_non_clifford.t_gate_circuits_deterministic(final_measure=False) + circuits = ref_non_clifford.t_gate_circuits_deterministic( + final_measure=False) targets = ref_non_clifford.t_gate_unitary_deterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_t_gate_nondeterministic_default_basis_gates(self): """Test t-gate circuits compiling to backend default basis_gates.""" - circuits = ref_non_clifford.t_gate_circuits_nondeterministic(final_measure=False) + circuits = ref_non_clifford.t_gate_circuits_nondeterministic( + final_measure=False) targets = ref_non_clifford.t_gate_unitary_nondeterministic() job = execute(circuits, UnitarySimulator(), shots=1) result = job.result() @@ -501,18 +645,26 @@ def test_t_gate_nondeterministic_default_basis_gates(self): def test_t_gate_nondeterministic_waltz_basis_gates(self): """Test t-gate gate circuits compiling to u1,u2,u3,cx""" - circuits = ref_non_clifford.t_gate_circuits_nondeterministic(final_measure=False) + circuits = ref_non_clifford.t_gate_circuits_nondeterministic( + final_measure=False) targets = ref_non_clifford.t_gate_unitary_nondeterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_t_gate_nondeterministic_minimal_basis_gates(self): """Test t-gate gate circuits compiling to u3,cx""" - circuits = ref_non_clifford.t_gate_circuits_nondeterministic(final_measure=False) + circuits = ref_non_clifford.t_gate_circuits_nondeterministic( + final_measure=False) targets = ref_non_clifford.t_gate_unitary_nondeterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) @@ -522,7 +674,8 @@ def test_t_gate_nondeterministic_minimal_basis_gates(self): # --------------------------------------------------------------------- def test_tdg_gate_deterministic_default_basis_gates(self): """Test tdg-gate circuits compiling to backend default basis_gates.""" - circuits = ref_non_clifford.tdg_gate_circuits_deterministic(final_measure=False) + circuits = ref_non_clifford.tdg_gate_circuits_deterministic( + final_measure=False) targets = ref_non_clifford.tdg_gate_unitary_deterministic() job = execute(circuits, UnitarySimulator(), shots=1) result = job.result() @@ -531,25 +684,34 @@ def test_tdg_gate_deterministic_default_basis_gates(self): def test_tdg_gate_deterministic_waltz_basis_gates(self): """Test tdg-gate gate circuits compiling to u1,u2,u3,cx""" - circuits = ref_non_clifford.tdg_gate_circuits_deterministic(final_measure=False) + circuits = ref_non_clifford.tdg_gate_circuits_deterministic( + final_measure=False) targets = ref_non_clifford.tdg_gate_unitary_deterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_tdg_gate_deterministic_minimal_basis_gates(self): """Test tdg-gate gate circuits compiling to u3,cx""" - circuits = ref_non_clifford.tdg_gate_circuits_deterministic(final_measure=False) + circuits = ref_non_clifford.tdg_gate_circuits_deterministic( + final_measure=False) targets = ref_non_clifford.tdg_gate_unitary_deterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_tdg_gate_nondeterministic_default_basis_gates(self): """Test tdg-gate circuits compiling to backend default basis_gates.""" - circuits = ref_non_clifford.tdg_gate_circuits_nondeterministic(final_measure=False) + circuits = ref_non_clifford.tdg_gate_circuits_nondeterministic( + final_measure=False) targets = ref_non_clifford.tdg_gate_unitary_nondeterministic() job = execute(circuits, UnitarySimulator(), shots=1) result = job.result() @@ -558,18 +720,26 @@ def test_tdg_gate_nondeterministic_default_basis_gates(self): def test_tdg_gate_nondeterministic_waltz_basis_gates(self): """Test tdg-gate gate circuits compiling to u1,u2,u3,cx""" - circuits = ref_non_clifford.tdg_gate_circuits_nondeterministic(final_measure=False) + circuits = ref_non_clifford.tdg_gate_circuits_nondeterministic( + final_measure=False) targets = ref_non_clifford.tdg_gate_unitary_nondeterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_tdg_gate_nondeterministic_minimal_basis_gates(self): """Test tdg-gate gate circuits compiling to u3,cx""" - circuits = ref_non_clifford.tdg_gate_circuits_nondeterministic(final_measure=False) + circuits = ref_non_clifford.tdg_gate_circuits_nondeterministic( + final_measure=False) targets = ref_non_clifford.tdg_gate_unitary_nondeterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) @@ -579,7 +749,8 @@ def test_tdg_gate_nondeterministic_minimal_basis_gates(self): # --------------------------------------------------------------------- def test_ccx_gate_deterministic_default_basis_gates(self): """Test ccx-gate circuits compiling to backend default basis_gates.""" - circuits = ref_non_clifford.ccx_gate_circuits_deterministic(final_measure=False) + circuits = ref_non_clifford.ccx_gate_circuits_deterministic( + final_measure=False) targets = ref_non_clifford.ccx_gate_unitary_deterministic() job = execute(circuits, UnitarySimulator(), shots=1) result = job.result() @@ -588,25 +759,34 @@ def test_ccx_gate_deterministic_default_basis_gates(self): def test_ccx_gate_deterministic_waltz_basis_gates(self): """Test ccx-gate gate circuits compiling to u1,u2,u3,cx""" - circuits = ref_non_clifford.ccx_gate_circuits_deterministic(final_measure=False) + circuits = ref_non_clifford.ccx_gate_circuits_deterministic( + final_measure=False) targets = ref_non_clifford.ccx_gate_unitary_deterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_ccx_gate_deterministic_minimal_basis_gates(self): """Test ccx-gate gate circuits compiling to u3,cx""" - circuits = ref_non_clifford.ccx_gate_circuits_deterministic(final_measure=False) + circuits = ref_non_clifford.ccx_gate_circuits_deterministic( + final_measure=False) targets = ref_non_clifford.ccx_gate_unitary_deterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_ccx_gate_nondeterministic_default_basis_gates(self): """Test ccx-gate circuits compiling to backend default basis_gates.""" - circuits = ref_non_clifford.ccx_gate_circuits_nondeterministic(final_measure=False) + circuits = ref_non_clifford.ccx_gate_circuits_nondeterministic( + final_measure=False) targets = ref_non_clifford.ccx_gate_unitary_nondeterministic() job = execute(circuits, UnitarySimulator(), shots=1) result = job.result() @@ -615,18 +795,26 @@ def test_ccx_gate_nondeterministic_default_basis_gates(self): def test_ccx_gate_nondeterministic_waltz_basis_gates(self): """Test ccx-gate gate circuits compiling to u1,u2,u3,cx""" - circuits = ref_non_clifford.ccx_gate_circuits_nondeterministic(final_measure=False) + circuits = ref_non_clifford.ccx_gate_circuits_nondeterministic( + final_measure=False) targets = ref_non_clifford.ccx_gate_unitary_nondeterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_ccx_gate_nondeterministic_minimal_basis_gates(self): """Test ccx-gate gate circuits compiling to u3,cx""" - circuits = ref_non_clifford.ccx_gate_circuits_nondeterministic(final_measure=False) + circuits = ref_non_clifford.ccx_gate_circuits_nondeterministic( + final_measure=False) targets = ref_non_clifford.ccx_gate_unitary_nondeterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) @@ -636,7 +824,8 @@ def test_ccx_gate_nondeterministic_minimal_basis_gates(self): # --------------------------------------------------------------------- def test_unitary_gate(self): """Test simulation with unitary gate circuit instructions.""" - circuits = ref_unitary_gate.unitary_gate_circuits_deterministic(final_measure=False) + circuits = ref_unitary_gate.unitary_gate_circuits_deterministic( + final_measure=False) targets = ref_unitary_gate.unitary_gate_unitary_deterministic() job = execute(circuits, UnitarySimulator(), shots=1) result = job.result() @@ -644,53 +833,117 @@ def test_unitary_gate(self): self.compare_unitary(result, circuits, targets) # --------------------------------------------------------------------- - # Test cswap-gate (Fredkin) + # Test cu1 gate # --------------------------------------------------------------------- - def test_cswap_gate_deterministic_default_basis_gates(self): - """Test cswap-gate circuits compiling to backend default basis_gates.""" - circuits = ref_non_clifford.cswap_gate_circuits_deterministic(final_measure=False) - targets = ref_non_clifford.cswap_gate_unitary_deterministic() + def test_cu1_gate_nondeterministic_default_basis_gates(self): + """Test cu1-gate gate circuits compiling to default basis""" + circuits = ref_non_clifford.cu1_gate_circuits_nondeterministic( + final_measure=False) + targets = ref_non_clifford.cu1_gate_unitary_nondeterministic() job = execute(circuits, UnitarySimulator(), shots=1) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) - # --------------------------------------------------------------------- - # Test cu1 gate - # --------------------------------------------------------------------- def test_cu1_gate_nondeterministic_waltz_basis_gates(self): """Test cu1-gate gate circuits compiling to u1,u2,u3,cx""" - circuits = ref_non_clifford.cu1_gate_circuits_nondeterministic(final_measure=False) + circuits = ref_non_clifford.cu1_gate_circuits_nondeterministic( + final_measure=False) targets = ref_non_clifford.cu1_gate_unitary_nondeterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u1', 'u2', 'u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) - def test_cswap_gate_deterministic_minimal_basis_gates(self): - """Test cswap-gate gate circuits compiling to u3,cx""" + def test_cu1_gate_nondeterministic_minimal_basis_gates(self): + """"Test cu1-gate gate circuits compiling to u3,cx""" + circuits = ref_non_clifford.cu1_gate_circuits_nondeterministic( + final_measure=False) + targets = ref_non_clifford.cu1_gate_unitary_nondeterministic() + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u3', 'cx']) + result = job.result() + self.assertTrue(getattr(result, 'success', False)) + self.compare_unitary(result, circuits, targets) + + # --------------------------------------------------------------------- + # Test cu3 gate + # --------------------------------------------------------------------- + def test_cu3_gate_deterministic_default_basis_gates(self): + """Test cu3-gate gate circuits compiling to default basis""" + circuits = ref_non_clifford.cu3_gate_circuits_deterministic( + final_measure=False) + targets = ref_non_clifford.cu3_gate_unitary_deterministic() + job = execute(circuits, UnitarySimulator(), shots=1) + result = job.result() + self.assertTrue(getattr(result, 'success', False)) + self.compare_unitary(result, circuits, targets) + + def test_cu3_gate_deterministic_waltz_basis_gates(self): + """Test cu3-gate gate circuits compiling to u1,u2,u3,cx""" + circuits = ref_non_clifford.cu3_gate_circuits_deterministic( + final_measure=False) + targets = ref_non_clifford.cu3_gate_unitary_deterministic() + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u1', 'u2', 'u3', 'cx']) + result = job.result() + self.assertTrue(getattr(result, 'success', False)) + self.compare_unitary(result, circuits, targets) + + def test_cu3_gate_deterministic_minimal_basis_gates(self): + """"Test cu3-gate gate circuits compiling to u3,cx""" + circuits = ref_non_clifford.cu3_gate_circuits_deterministic( + final_measure=False) + targets = ref_non_clifford.cu3_gate_unitary_deterministic() + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u3', 'cx']) + result = job.result() + self.assertTrue(getattr(result, 'success', False)) + self.compare_unitary(result, circuits, targets) + + # --------------------------------------------------------------------- + # Test cswap gate + # --------------------------------------------------------------------- + def test_cswap_gate_deterministic_default_basis_gates(self): + """Test cswap-gate circuits compiling to backend default basis_gates.""" circuits = ref_non_clifford.cswap_gate_circuits_deterministic( final_measure=False) targets = ref_non_clifford.cswap_gate_unitary_deterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u3', 'cx']) + job = execute(circuits, UnitarySimulator(), shots=1) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) - def test_cu1_gate_nondeterministic_minimal_basis_gates(self): - """"Test cu1-gate gate circuits compiling to u3,cx""" - circuits = ref_non_clifford.cu1_gate_circuits_nondeterministic(final_measure=False) - targets = ref_non_clifford.cu1_gate_unitary_nondeterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u3', 'cx']) + def test_cswap_gate_deterministic_minimal_basis_gates(self): + """Test cswap-gate gate circuits compiling to u3,cx""" + circuits = ref_non_clifford.cswap_gate_circuits_deterministic( + final_measure=False) + targets = ref_non_clifford.cswap_gate_unitary_deterministic() + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_cswap_gate_deterministic_waltz_basis_gates(self): """Test cswap-gate gate circuits compiling to u1,u2,u3,cx""" - circuits = ref_non_clifford.cswap_gate_circuits_deterministic(final_measure=False) + circuits = ref_non_clifford.cswap_gate_circuits_deterministic( + final_measure=False) targets = ref_non_clifford.cswap_gate_unitary_deterministic() - job = execute(circuits, UnitarySimulator(), shots=1, + job = execute(circuits, + UnitarySimulator(), + shots=1, basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) @@ -698,37 +951,35 @@ def test_cswap_gate_deterministic_waltz_basis_gates(self): def test_cswap_gate_nondeterministic_default_basis_gates(self): """Test cswap-gate circuits compiling to backend default basis_gates.""" - circuits = ref_non_clifford.cswap_gate_circuits_nondeterministic(final_measure=False) + circuits = ref_non_clifford.cswap_gate_circuits_nondeterministic( + final_measure=False) targets = ref_non_clifford.cswap_gate_unitary_nondeterministic() job = execute(circuits, UnitarySimulator(), shots=1) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) - def test_cu1_gate_nondeterministic_default_basis_gates(self): - """Test cu1-gate gate circuits compiling to default basis""" - circuits = ref_non_clifford.cu1_gate_circuits_nondeterministic(final_measure=False) - targets = ref_non_clifford.cu1_gate_unitary_nondeterministic() - job = execute(circuits, UnitarySimulator(), shots=1) - result = job.result() - self.assertTrue(getattr(result, 'success', False)) - self.compare_unitary(result, circuits, targets) - def test_cswap_gate_nondeterministic_minimal_basis_gates(self): """Test cswap-gate gate circuits compiling to u3,cx""" circuits = ref_non_clifford.cswap_gate_circuits_nondeterministic( final_measure=False) targets = ref_non_clifford.cswap_gate_unitary_nondeterministic() - job = execute(circuits, UnitarySimulator(), shots=1, basis_gates=['u3', 'cx']) + job = execute(circuits, + UnitarySimulator(), + shots=1, + basis_gates=['u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) self.compare_unitary(result, circuits, targets) def test_cswap_gate_nondeterministic_waltz_basis_gates(self): """Test cswap-gate gate circuits compiling to u1,u2,u3,cx""" - circuits = ref_non_clifford.cswap_gate_circuits_nondeterministic(final_measure=False) + circuits = ref_non_clifford.cswap_gate_circuits_nondeterministic( + final_measure=False) targets = ref_non_clifford.cswap_gate_unitary_nondeterministic() - job = execute(circuits, UnitarySimulator(), shots=1, + job = execute(circuits, + UnitarySimulator(), + shots=1, basis_gates=['u1', 'u2', 'u3', 'cx']) result = job.result() self.assertTrue(getattr(result, 'success', False)) diff --git a/test/terra/reference/ref_non_clifford.py b/test/terra/reference/ref_non_clifford.py index 4e9c33e489..ce8c5abaa4 100644 --- a/test/terra/reference/ref_non_clifford.py +++ b/test/terra/reference/ref_non_clifford.py @@ -9,23 +9,19 @@ # Any modifications or derivative works of this code must retain this # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. - """ Test circuits and reference outputs for non-Clifford gate instructions. """ import numpy as np from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit -from qiskit.extensions import Cu1Gate -from qiskit.quantum_info.synthesis import two_qubit_cnot_decompose - from test.terra.utils.multiplexer import multiplexer_multi_controlled_x - # ========================================================================== # T-gate # ========================================================================== + def t_gate_circuits_deterministic(final_measure=True): """T-gate test circuits with deterministic counts.""" circuits = [] @@ -221,14 +217,15 @@ def t_gate_unitary_nondeterministic(): """T-gate circuits reference unitaries.""" targets = [] # T.H - targets.append(np.array([[1 / np.sqrt(2), 1 / np.sqrt(2)], - [0.5 + 0.5j, -0.5 - 0.5j]])) + targets.append( + np.array([[1 / np.sqrt(2), 1 / np.sqrt(2)], [0.5 + 0.5j, + -0.5 - 0.5j]])) # X.T.H - targets.append(np.array([[0.5 + 0.5j, -0.5 - 0.5j], - [1 / np.sqrt(2), 1 / np.sqrt(2)]])) + targets.append( + np.array([[0.5 + 0.5j, -0.5 - 0.5j], [1 / np.sqrt(2), + 1 / np.sqrt(2)]])) # H.T.T.H = H.S.H - targets.append(np.array([[1 + 1j, 1 - 1j], - [1 - 1j, 1 + 1j]]) / 2) + targets.append(np.array([[1 + 1j, 1 - 1j], [1 - 1j, 1 + 1j]]) / 2) return targets @@ -236,6 +233,7 @@ def t_gate_unitary_nondeterministic(): # T^dagger-gate # ========================================================================== + def tdg_gate_circuits_deterministic(final_measure=True): """Tdg-gate test circuits with deterministic counts.""" circuits = [] @@ -417,14 +415,15 @@ def tdg_gate_unitary_nondeterministic(): """Tdg-gate circuits reference unitaries.""" targets = [] # Tdg.H - targets.append(np.array([[1 / np.sqrt(2), 1 / np.sqrt(2)], - [0.5 - 0.5j, -0.5 + 0.5j]])) + targets.append( + np.array([[1 / np.sqrt(2), 1 / np.sqrt(2)], [0.5 - 0.5j, + -0.5 + 0.5j]])) # X.Tdg.H - targets.append(np.array([[0.5 - 0.5j, -0.5 + 0.5j], - [1 / np.sqrt(2), 1 / np.sqrt(2)]])) + targets.append( + np.array([[0.5 - 0.5j, -0.5 + 0.5j], [1 / np.sqrt(2), + 1 / np.sqrt(2)]])) # H.Tdg.Tdg.H = H.Sdg.H - targets.append(np.array([[1 - 1j, 1 + 1j], - [1 + 1j, 1 - 1j]]) / 2) + targets.append(np.array([[1 - 1j, 1 + 1j], [1 + 1j, 1 - 1j]]) / 2) return targets @@ -432,6 +431,7 @@ def tdg_gate_unitary_nondeterministic(): # CCX-gate # ========================================================================== + def ccx_gate_circuits_deterministic(final_measure=True): """CCX-gate test circuits with deterministic counts.""" circuits = [] @@ -625,77 +625,53 @@ def ccx_gate_unitary_deterministic(): targets = [] # CCX(0,1,2) - targets.append(np.array([[1, 0, 0, 0, 0, 0, 0, 0], - [0, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 1], - [0, 0, 0, 0, 1, 0, 0, 0], - [0, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 0, 0, 0, 0, 1, 0], - [0, 0, 0, 1, 0, 0, 0, 0]])) + targets.append( + np.array([[1, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1], + [0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0, 0, 0]])) # (I^X^X).CCX(0,1,2).(I^X^X) -> |100> - targets.append(np.array([[0, 0, 0, 0, 1, 0, 0, 0], - [0, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 0], - [0, 0, 0, 1, 0, 0, 0, 0], - [1, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 0, 0, 0, 0, 1, 0], - [0, 0, 0, 0, 0, 0, 0, 1]])) + targets.append( + np.array([[0, 0, 0, 0, 1, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0], + [1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0, 1]])) # (X^I^X).CCX(0,1,2).(X^I^X) -> |000> - targets.append(np.array([[1, 0, 0, 0, 0, 0, 0, 0], - [0, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 1, 0], - [0, 0, 0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 1, 0, 0, 0], - [0, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 1]])) + targets.append( + np.array([[1, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0], + [0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1]])) # (X^X^I).CCX(0,1,2).(X^X^I) -> |000> - targets.append(np.array([[1, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 0], - [0, 0, 0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 1, 0, 0, 0], - [0, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 1, 0], - [0, 0, 0, 0, 0, 0, 0, 1]])) + targets.append( + np.array([[1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0], + [0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0, 1]])) # CCX(2,1,0) - targets.append(np.array([[1, 0, 0, 0, 0, 0, 0, 0], - [0, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 0], - [0, 0, 0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 1, 0, 0, 0], - [0, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 1], - [0, 0, 0, 0, 0, 0, 1, 0]])) + targets.append( + np.array([[1, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 0, 1, 0]])) # (I^X^X).CCX(2,1,0).(I^X^X) -> |000> - targets.append(np.array([[1, 0, 0, 0, 0, 0, 0, 0], - [0, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 0], - [0, 0, 0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 0, 0, 1, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 1, 0], - [0, 0, 0, 0, 0, 0, 0, 1]])) + targets.append( + np.array([[1, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0, 1]])) # (X^I^X).CCX(2,1,0).(X^I^X) -> |000> - targets.append(np.array([[1, 0, 0, 0, 0, 0, 0, 0], - [0, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 1, 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 1, 0, 0, 0], - [0, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 0, 0, 0, 0, 1, 0], - [0, 0, 0, 0, 0, 0, 0, 1]])) + targets.append( + np.array([[1, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0, 1]])) # (X^X^I).CCX(2,1,0).(X^X^I) -> |001> - targets.append(np.array([[0, 1, 0, 0, 0, 0, 0, 0], - [1, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 0], - [0, 0, 0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 1, 0, 0, 0], - [0, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 0, 0, 0, 0, 1, 0], - [0, 0, 0, 0, 0, 0, 0, 1]])) + targets.append( + np.array([[0, 1, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0, 1]])) return targets @@ -810,43 +786,36 @@ def ccx_gate_unitary_nondeterministic(): """CCX-gate circuits reference unitaries.""" targets = [] # (I^X^I).CCX(0,1,2).(I^X^H) -> |000> + |101> - targets.append(np.array([[1, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 1, -1, 0, 0], - [0, 0, 1, 1, 0, 0, 0, 0], - [0, 0, 1, -1, 0, 0, 0, 0], - [0, 0, 0, 0, 1, 1, 0, 0], - [1, -1, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 1, 1], - [0, 0, 0, 0, 0, 0, 1, -1]]) / np.sqrt(2)) + targets.append( + np.array([[1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, -1, 0, 0], + [0, 0, 1, 1, 0, 0, 0, 0], [0, 0, 1, -1, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 1, 0, 0], [1, -1, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 1, 1], [0, 0, 0, 0, 0, 0, 1, -1]]) / + np.sqrt(2)) # (I^I^X).CCX(0,1,2).(I^H^X) -> |000> + |110> - targets.append(np.array([[1, 0, 1, 0, 0, 0, 0, 0], - [0, 1, 0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 1, 0, -1, 0], - [0, 1, 0, -1, 0, 0, 0, 0], - [0, 0, 0, 0, 1, 0, 1, 0], - [0, 0, 0, 0, 0, 1, 0, 1], - [1, 0, -1, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 1, 0, -1]]) / np.sqrt(2)) + targets.append( + np.array([[1, 0, 1, 0, 0, 0, 0, 0], [0, 1, 0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 0, -1, 0], [0, 1, 0, -1, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 0, 1, 0], [0, 0, 0, 0, 0, 1, 0, 1], + [1, 0, -1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, -1]]) / + np.sqrt(2)) # (I^X^I).CCX(2,1,0).(H^X^I) -> |000> + |101> - targets.append(np.array([[1, 0, 0, 0, 1, 0, 0, 0], - [0, 1, 0, 0, 0, 1, 0, 0], - [0, 0, 1, 0, 0, 0, 1, 0], - [0, 0, 0, 1, 0, 0, 0, 1], - [0, 1, 0, 0, 0, -1, 0, 0], - [1, 0, 0, 0, -1, 0, 0, 0], - [0, 0, 1, 0, 0, 0, -1, 0], - [0, 0, 0, 1, 0, 0, 0, -1]]) / np.sqrt(2)) + targets.append( + np.array([[1, 0, 0, 0, 1, 0, 0, 0], [0, 1, 0, 0, 0, 1, 0, 0], + [0, 0, 1, 0, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0, 0, 1], + [0, 1, 0, 0, 0, -1, 0, 0], [1, 0, 0, 0, -1, 0, 0, 0], + [0, 0, 1, 0, 0, 0, -1, 0], [0, 0, 0, 1, 0, 0, 0, -1]]) / + np.sqrt(2)) # (X^I^I).CCX(2,1,0).(X^H^I) -> |000> + |011> - targets.append(np.array([[1, 0, 1, 0, 0, 0, 0, 0], - [0, 1, 0, 1, 0, 0, 0, 0], - [0, 1, 0, -1, 0, 0, 0, 0], - [1, 0, -1, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 1, 0, 1, 0], - [0, 0, 0, 0, 0, 1, 0, 1], - [0, 0, 0, 0, 1, 0, -1, 0], - [0, 0, 0, 0, 0, 1, 0, -1]]) / np.sqrt(2)) + targets.append( + np.array([[1, 0, 1, 0, 0, 0, 0, 0], [0, 1, 0, 1, 0, 0, 0, 0], + [0, 1, 0, -1, 0, 0, 0, 0], [1, 0, -1, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 0, 1, 0], [0, 0, 0, 0, 0, 1, 0, 1], + [0, 0, 0, 0, 1, 0, -1, 0], [0, 0, 0, 0, 0, 1, 0, -1]]) / + np.sqrt(2)) return targets + # ========================================================================== # Multiplexer-gate (CCX-like) # ========================================================================== @@ -866,7 +835,8 @@ def multiplexer_ccx_gate_circuits_deterministic(final_measure=True): # CCX(0,1,2) circuit = QuantumCircuit(*regs) - circuit.append(multiplexer_multi_controlled_x(num_control_qubits), [qr[0], qr[1], qr[2]]) + circuit.append(multiplexer_multi_controlled_x(num_control_qubits), + [qr[0], qr[1], qr[2]]) if final_measure: circuit.barrier(qr) circuit.measure(qr, cr) @@ -878,7 +848,8 @@ def multiplexer_ccx_gate_circuits_deterministic(final_measure=True): circuit.barrier(qr) circuit.x(qr[1]) circuit.barrier(qr) - circuit.append(multiplexer_multi_controlled_x(num_control_qubits), [qr[0], qr[1], qr[2]]) + circuit.append(multiplexer_multi_controlled_x(num_control_qubits), + [qr[0], qr[1], qr[2]]) circuit.barrier(qr) circuit.x(qr[0]) circuit.barrier(qr) @@ -894,7 +865,8 @@ def multiplexer_ccx_gate_circuits_deterministic(final_measure=True): circuit.barrier(qr) circuit.x(qr[2]) circuit.barrier(qr) - circuit.append(multiplexer_multi_controlled_x(num_control_qubits), [qr[0], qr[1], qr[2]]) + circuit.append(multiplexer_multi_controlled_x(num_control_qubits), + [qr[0], qr[1], qr[2]]) circuit.barrier(qr) circuit.x(qr[0]) circuit.barrier(qr) @@ -910,7 +882,8 @@ def multiplexer_ccx_gate_circuits_deterministic(final_measure=True): circuit.barrier(qr) circuit.x(qr[2]) circuit.barrier(qr) - circuit.append(multiplexer_multi_controlled_x(num_control_qubits), [qr[0], qr[1], qr[2]]) + circuit.append(multiplexer_multi_controlled_x(num_control_qubits), + [qr[0], qr[1], qr[2]]) circuit.barrier(qr) circuit.x(qr[1]) circuit.barrier(qr) @@ -922,7 +895,8 @@ def multiplexer_ccx_gate_circuits_deterministic(final_measure=True): # CCX(2,1,0) circuit = QuantumCircuit(*regs) - circuit.append(multiplexer_multi_controlled_x(num_control_qubits), [qr[2], qr[1], qr[0]]) + circuit.append(multiplexer_multi_controlled_x(num_control_qubits), + [qr[2], qr[1], qr[0]]) if final_measure: circuit.barrier(qr) circuit.measure(qr, cr) @@ -934,7 +908,8 @@ def multiplexer_ccx_gate_circuits_deterministic(final_measure=True): circuit.barrier(qr) circuit.x(qr[1]) circuit.barrier(qr) - circuit.append(multiplexer_multi_controlled_x(num_control_qubits), [qr[2], qr[1], qr[0]]) + circuit.append(multiplexer_multi_controlled_x(num_control_qubits), + [qr[2], qr[1], qr[0]]) circuit.barrier(qr) circuit.x(qr[0]) circuit.barrier(qr) @@ -950,7 +925,8 @@ def multiplexer_ccx_gate_circuits_deterministic(final_measure=True): circuit.barrier(qr) circuit.x(qr[2]) circuit.barrier(qr) - circuit.append(multiplexer_multi_controlled_x(num_control_qubits), [qr[2], qr[1], qr[0]]) + circuit.append(multiplexer_multi_controlled_x(num_control_qubits), + [qr[2], qr[1], qr[0]]) circuit.barrier(qr) circuit.x(qr[0]) circuit.barrier(qr) @@ -966,7 +942,8 @@ def multiplexer_ccx_gate_circuits_deterministic(final_measure=True): circuit.barrier(qr) circuit.x(qr[2]) circuit.barrier(qr) - circuit.append(multiplexer_multi_controlled_x(num_control_qubits), [qr[2], qr[1], qr[0]]) + circuit.append(multiplexer_multi_controlled_x(num_control_qubits), + [qr[2], qr[1], qr[0]]) circuit.barrier(qr) circuit.x(qr[1]) circuit.barrier(qr) @@ -978,6 +955,7 @@ def multiplexer_ccx_gate_circuits_deterministic(final_measure=True): return circuits + def multiplexer_ccx_gate_circuits_nondeterministic(final_measure=True): """mukltiplexer CCX-like gate test circuits with non-deterministic counts.""" circuits = [] @@ -997,7 +975,8 @@ def multiplexer_ccx_gate_circuits_nondeterministic(final_measure=True): circuit.barrier(qr) circuit.x(qr[1]) circuit.barrier(qr) - circuit.append(multiplexer_multi_controlled_x(num_control_qubits), [qr[0], qr[1], qr[2]]) + circuit.append(multiplexer_multi_controlled_x(num_control_qubits), + [qr[0], qr[1], qr[2]]) circuit.barrier(qr) circuit.x(qr[1]) if final_measure: @@ -1011,7 +990,8 @@ def multiplexer_ccx_gate_circuits_nondeterministic(final_measure=True): circuit.barrier(qr) circuit.x(qr[0]) circuit.barrier(qr) - circuit.append(multiplexer_multi_controlled_x(num_control_qubits), [qr[0], qr[1], qr[2]]) + circuit.append(multiplexer_multi_controlled_x(num_control_qubits), + [qr[0], qr[1], qr[2]]) circuit.barrier(qr) circuit.x(qr[0]) if final_measure: @@ -1025,7 +1005,8 @@ def multiplexer_ccx_gate_circuits_nondeterministic(final_measure=True): circuit.barrier(qr) circuit.x(qr[1]) circuit.barrier(qr) - circuit.append(multiplexer_multi_controlled_x(num_control_qubits), [qr[2], qr[1], qr[0]]) + circuit.append(multiplexer_multi_controlled_x(num_control_qubits), + [qr[2], qr[1], qr[0]]) circuit.barrier(qr) circuit.x(qr[1]) if final_measure: @@ -1039,7 +1020,8 @@ def multiplexer_ccx_gate_circuits_nondeterministic(final_measure=True): circuit.barrier(qr) circuit.x(qr[2]) circuit.barrier(qr) - circuit.append(multiplexer_multi_controlled_x(num_control_qubits), [qr[2], qr[1], qr[0]]) + circuit.append(multiplexer_multi_controlled_x(num_control_qubits), + [qr[2], qr[1], qr[0]]) circuit.barrier(qr) circuit.x(qr[2]) if final_measure: @@ -1049,15 +1031,17 @@ def multiplexer_ccx_gate_circuits_nondeterministic(final_measure=True): return circuits + def multiplexer_ccx_gate_counts_deterministic(shots, hex_counts=True): """ The counts are exactly the same as the ccx gate """ return ccx_gate_counts_deterministic(shots, hex_counts) + def multiplexer_ccx_gate_counts_nondeterministic(shots, hex_counts=True): """ The counts are exactly the same as the ccx gate """ return ccx_gate_counts_nondeterministic(shots, hex_counts) - + # ========================================================================== # CSWAP-gate (Fredkin) # ========================================================================== @@ -1069,7 +1053,7 @@ def cswap_gate_circuits_deterministic(final_measure): cr = ClassicalRegister(3) regs = (qr, cr) else: - regs = (qr,) + regs = (qr, ) # CSWAP(0,1,2) # -> |000> circuit = QuantumCircuit(*regs) @@ -1100,7 +1084,7 @@ def cswap_gate_circuits_deterministic(final_measure): circuit.barrier(qr) circuit.measure(qr, cr) circuits.append(circuit) - + # CSWAP(0,1,2).(X^X^I) -> |110> circuit = QuantumCircuit(*regs) circuit.x(qr[1]) @@ -1112,7 +1096,7 @@ def cswap_gate_circuits_deterministic(final_measure): circuit.barrier(qr) circuit.measure(qr, cr) circuits.append(circuit) - + # CSWAP(0,1,2).(I^I^X) -> |001> circuit = QuantumCircuit(*regs) circuit.x(qr[0]) @@ -1135,7 +1119,7 @@ def cswap_gate_circuits_deterministic(final_measure): circuit.barrier(qr) circuit.measure(qr, cr) circuits.append(circuit) - + # CSWAP(0,1,2).(X^I^X) -> |011> circuit = QuantumCircuit(*regs) circuit.x(qr[0]) @@ -1160,7 +1144,7 @@ def cswap_gate_circuits_deterministic(final_measure): circuit.barrier(qr) circuit.measure(qr, cr) circuits.append(circuit) - + # CSWAP(1,0,2).(I^X^X) -> |110> circuit = QuantumCircuit(*regs) circuit.x(qr[0]) @@ -1185,118 +1169,6 @@ def cswap_gate_circuits_deterministic(final_measure): circuit.measure(qr, cr) circuits.append(circuit) return circuits - - -# ========================================================================== -# CU1 -# ========================================================================== -def cu1_gate_circuits_nondeterministic(final_measure): - circuits = [] - qr = QuantumRegister(2) - if final_measure: - cr = ClassicalRegister(2) - regs = (qr, cr) - else: - regs = (qr,) - - #H^X.CU1(0,0,1).H^X - circuit = QuantumCircuit(*regs) - circuit.h(qr[1]) - circuit.x(qr[0]) - circuit.cu1(0, qr[0], qr[1]) - circuit.x(qr[0]) - circuit.h(qr[1]) - - if final_measure: - circuit.barrier(qr) - circuit.measure(qr, cr) - circuits.append(circuit) - - #H^I.CU1(pi,0,1).H^I - circuit = QuantumCircuit(*regs) - circuit.h(qr[1]) - circuit.cu1(np.pi, qr[0], qr[1]) - circuit.h(qr[1]) - - if final_measure: - circuit.barrier(qr) - circuit.measure(qr, cr) - circuits.append(circuit) - - #H^X.CU1(pi/4,0,1).H^X - circuit = QuantumCircuit(*regs) - circuit.h(qr[1]) - circuit.x(qr[0]) - circuit.cu1(np.pi/4, qr[0], qr[1]) - circuit.x(qr[0]) - circuit.h(qr[1]) - if final_measure: - circuit.barrier(qr) - circuit.measure(qr, cr) - circuits.append(circuit) - - # H^X.CU1(pi/2,0,1).H^X - circuit = QuantumCircuit(*regs) - circuit.h(qr[1]) - circuit.x(qr[0]) - circuit.cu1(np.pi/2, qr[0], qr[1]) - circuit.x(qr[0]) - circuit.h(qr[1]) - if final_measure: - circuit.barrier(qr) - circuit.measure(qr, cr) - circuits.append(circuit) - - # H^X.CU1(pi,0,1).H^X - circuit = QuantumCircuit(*regs) - circuit.h(qr[1]) - circuit.x(qr[0]) - circuit.cu1(np.pi, qr[0], qr[1]) - circuit.x(qr[0]) - circuit.h(qr[1]) - if final_measure: - circuit.barrier(qr) - circuit.measure(qr, cr) - circuits.append(circuit) - - # H^H.CU1(0,0,1).H^H - circuit = QuantumCircuit(*regs) - circuit.h(qr[1]) - circuit.h(qr[0]) - circuit.cu1(0, qr[0], qr[1]) - circuit.h(qr[0]) - circuit.h(qr[1]) - - if final_measure: - circuit.barrier(qr) - circuit.measure(qr, cr) - circuits.append(circuit) - - # H^H.CU1(pi/2,0,1).H^H - circuit = QuantumCircuit(*regs) - circuit.h(qr[1]) - circuit.h(qr[0]) - circuit.cu1(np.pi/2, qr[0], qr[1]) - circuit.h(qr[0]) - circuit.h(qr[1]) - if final_measure: - circuit.barrier(qr) - circuit.measure(qr, cr) - circuits.append(circuit) - - # H^H.CU1(pi,0,1).H^H - circuit = QuantumCircuit(*regs) - circuit.h(qr[1]) - circuit.h(qr[0]) - circuit.cu1(np.pi, qr[0], qr[1]) - circuit.h(qr[0]) - circuit.h(qr[1]) - if final_measure: - circuit.barrier(qr) - circuit.measure(qr, cr) - circuits.append(circuit) - - return circuits def cswap_gate_counts_deterministic(shots, hex_counts=True): @@ -1368,7 +1240,7 @@ def cswap_gate_circuits_nondeterministic(final_measure=True): circuit.barrier(qr) circuit.measure(qr, cr) circuits.append(circuit) - + # CSWAP(0,1,2).(X^I^H). -> |100> + |011> circuit = QuantumCircuit(*regs) circuit.h(qr[0]) @@ -1397,7 +1269,7 @@ def cswap_gate_circuits_nondeterministic(final_measure=True): circuit.barrier(qr) circuit.measure(qr, cr) circuits.append(circuit) - + # CSWAP(0,1,2).(H^I^I) -> |100>+|000> circuit = QuantumCircuit(*regs) circuit.h(qr[2]) @@ -1414,7 +1286,7 @@ def cswap_gate_circuits_nondeterministic(final_measure=True): circuit.barrier(qr) circuit.measure(qr, cr) circuits.append(circuit) - + # CSWAP(0,1,2).(X^X^H) -> |110> + |111> circuit = QuantumCircuit(*regs) circuit.h(qr[0]) @@ -1424,85 +1296,63 @@ def cswap_gate_circuits_nondeterministic(final_measure=True): if final_measure: circuit.barrier(qr) circuit.measure(qr, cr) - circuits.append(circuit) + circuits.append(circuit) return circuits - + def cswap_gate_counts_nondeterministic(shots, hex_counts=True): targets = [] if hex_counts: # CSWAP(0,1,2).(H^H^H) -> |---> - targets.append({'0x0': shots / 8, - '0x1': shots / 8, - '0x2': shots / 8, - '0x3': shots / 8, - '0x4': shots / 8, - '0x5': shots / 8, - '0x6': shots / 8, - '0x7': shots / 8, - }) + targets.append({ + '0x0': shots / 8, + '0x1': shots / 8, + '0x2': shots / 8, + '0x3': shots / 8, + '0x4': shots / 8, + '0x5': shots / 8, + '0x6': shots / 8, + '0x7': shots / 8, + }) # CSWAP(0,1,2).(X^I^H). -> |100> + |011> - targets.append({'0x3': shots / 2, - '0x4': shots / 2 - }) + targets.append({'0x3': shots / 2, '0x4': shots / 2}) # CSWAP(0,1,2).(I^X^H). -> |010> + |101> - targets.append({'0x2': shots / 2, - '0x5': shots / 2 - }) + targets.append({'0x2': shots / 2, '0x5': shots / 2}) # CSWAP(0,1,2).(I^H^I) -> |0-0> - targets.append({'0x2': shots / 2, - '0x0': shots / 2 - }) + targets.append({'0x2': shots / 2, '0x0': shots / 2}) # CSWAP(0,1,2).(H^I^I) -> |-00> - targets.append({'0x4': shots / 2, - '0x0': shots / 2 - }) + targets.append({'0x4': shots / 2, '0x0': shots / 2}) # CSWAP(0,1,2).(I^I^H) -> |00-> - targets.append({'0x0': shots / 2, - '0x1': shots / 2 - }) + targets.append({'0x0': shots / 2, '0x1': shots / 2}) # CSWAP(0,1,2).(X^X^H) -> |110> + |111> - targets.append({'0x6': shots / 2, - '0x7': shots / 2 - }) + targets.append({'0x6': shots / 2, '0x7': shots / 2}) else: # CSWAP(0,1,2).(H^H^H) -> |---> - targets.append({'000': shots / 8, - '001': shots / 8, - '010': shots / 8, - '011': shots / 8, - '100': shots / 8, - '101': shots / 8, - '110': shots / 8, - '111': shots / 8, - }) + targets.append({ + '000': shots / 8, + '001': shots / 8, + '010': shots / 8, + '011': shots / 8, + '100': shots / 8, + '101': shots / 8, + '110': shots / 8, + '111': shots / 8, + }) # CSWAP(0,1,2).(X^I^H). -> |100> + |011> - targets.append({'011': shots / 2, - '100': shots / 2 - }) + targets.append({'011': shots / 2, '100': shots / 2}) # CSWAP(0,1,2).(I^X^H). -> |010> + |101> - targets.append({'010': shots / 2, - '101': shots / 2 - }) + targets.append({'010': shots / 2, '101': shots / 2}) # CSWAP(0,1,2).(I^H^I) -> |0-0> - targets.append({'010': shots / 2, - '000': shots / 2 - }) + targets.append({'010': shots / 2, '000': shots / 2}) # CSWAP(0,1,2).(H^I^I) -> |-00> - targets.append({'100': shots / 2, - '000': shots / 2 - }) + targets.append({'100': shots / 2, '000': shots / 2}) # CSWAP(0,1,2).(I^I^H) -> |00-> - targets.append({'001': shots / 2, - '000': shots / 2 - }) + targets.append({'001': shots / 2, '000': shots / 2}) # CSWAP(0,1,2).(X^X^H) -> |110> + |111> - targets.append({'110': shots / 2, - '111': shots / 2 - }) + targets.append({'110': shots / 2, '111': shots / 2}) return targets @@ -1556,95 +1406,65 @@ def cswap_gate_unitary_deterministic(): targets = [] # CSWAP(0,1,2) # -> |000> - targets.append(np.array([[1, 0, 0, 0, 0, 0, 0, 0], - [0, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 0, 0, 1, 0, 0, 0], - [0, 0, 0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 1, 0], - [0, 0, 0, 0, 0, 0, 0, 1]])) + targets.append( + np.array([[1, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0], + [0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0, 1]])) # CSWAP(0,1,2).(X^I^I) -> |100> - targets.append(np.array([[0, 0, 0, 0, 1, 0, 0, 0], - [0, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 0, 0, 0, 0, 1, 0], - [0, 1, 0, 0, 0, 0, 0, 0], - [1, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 1], - [0, 0, 1, 0, 0, 0, 0, 0], - [0, 0, 0, 1, 0, 0, 0, 0]])) + targets.append( + np.array([[0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 1, 0], [0, 1, 0, 0, 0, 0, 0, 0], + [1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1], + [0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0]])) # CSWAP(0,1,2).(I^X^I) -> |010> - targets.append(np.array([[0, 0, 1, 0, 0, 0, 0, 0], - [0, 0, 0, 1, 0, 0, 0, 0], - [1, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 1], - [0, 0, 0, 0, 0, 0, 1, 0], - [0, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 1, 0, 0, 0], - [0, 0, 0, 0, 0, 1, 0, 0]])) + targets.append( + np.array([[0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0], + [1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1], + [0, 0, 0, 0, 0, 0, 1, 0], [0, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0]])) # CSWAP(0,1,2).(X^X^I) -> |110> - targets.append(np.array([[0, 0, 0, 0, 0, 0, 1, 0], - [0, 0, 0, 0, 0, 0, 0, 1], - [0, 0, 0, 0, 1, 0, 0, 0], - [0, 0, 0, 1, 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 1, 0, 0], - [1, 0, 0, 0, 0, 0, 0, 0], - [0, 1, 0, 0, 0, 0, 0, 0]])) + targets.append( + np.array([[0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0, 1], + [0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0], + [1, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0]])) # CSWAP(0,1,2).(I^I^X) -> |001> - targets.append(np.array([[0, 1, 0, 0, 0, 0, 0, 0], - [1, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 1, 0, 0, 0], - [0, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 1], - [0, 0, 0, 0, 0, 0, 1, 0]])) + targets.append( + np.array([[0, 1, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0], + [0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 0, 1, 0]])) # CSWAP(0,1,2).(I^X^X) -> |101> - targets.append(np.array([[0, 0, 0, 1, 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 0], - [0, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 1, 0], - [0, 0, 0, 0, 0, 0, 0, 1], - [1, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 0, 0, 1, 0, 0, 0]])) + targets.append( + np.array([[0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0], + [0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0], + [0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0]])) # CSWAP(0,1,2).(X^I^X) -> |011> - targets.append(np.array([[0, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 0, 0, 1, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 1], - [1, 0, 0, 0, 0, 0, 0, 0], - [0, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 1, 0], - [0, 0, 0, 1, 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 0]])) + targets.append( + np.array([[0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0], + [0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0], + [0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0]])) # CSWAP(0,1,2).(X^X^X) -> |111> - targets.append(np.array([[0, 0, 0, 0, 0, 0, 0, 1], - [0, 0, 0, 0, 0, 0, 1, 0], - [0, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 0], - [0, 0, 0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 1, 0, 0, 0], - [0, 1, 0, 0, 0, 0, 0, 0], - [1, 0, 0, 0, 0, 0, 0, 0]])) + targets.append( + np.array([[0, 0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 0, 1, 0], + [0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0], + [0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0], + [0, 1, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0]])) # CSWAP(1,0,2).(I^X^X) -> |110> - targets.append(np.array([[0, 0, 0, 1, 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 0], - [0, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 1], - [0, 0, 0, 0, 0, 0, 1, 0], - [1, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 1, 0, 0, 0]])) + targets.append( + np.array([[0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0], + [0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 0, 1, 0], + [1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0]])) # CSWAP(2,1,0).(X^I^X) -> |110> - targets.append(np.array([[0, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 0, 0, 1, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 1], - [0, 0, 0, 0, 0, 0, 1, 0], - [0, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 1, 0, 0, 0, 0], - [1, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 0]])) + targets.append( + np.array([[0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 0, 1, 0], + [0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0], + [1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0]])) return targets @@ -1652,126 +1472,214 @@ def cswap_gate_unitary_nondeterministic(): """cswap-gate circuits reference unitaries.""" targets = [] - targets.append(np.array([ [0.35355339, 0.35355339, 0.35355339, 0.35355339, - 0.35355339, 0.35355339, 0.35355339, 0.35355339], - [0.35355339, -0.35355339, 0.35355339, -0.35355339, - 0.35355339, -0.35355339, 0.35355339, -0.35355339], - [0.35355339, 0.35355339, -0.35355339, -0.35355339, - 0.35355339, 0.35355339, -0.35355339, -0.35355339], - [0.35355339, -0.35355339, 0.35355339, -0.35355339, - -0.35355339, 0.35355339, -0.35355339, 0.35355339], - [0.35355339, 0.35355339, 0.35355339, 0.35355339, - -0.35355339, -0.35355339, -0.35355339, -0.35355339], - [0.35355339, -0.35355339, -0.35355339, 0.35355339, - 0.35355339, -0.35355339, -0.35355339, 0.35355339], - [0.35355339, 0.35355339, -0.35355339, -0.35355339, - -0.35355339, -0.35355339, 0.35355339, 0.35355339], - [0.35355339, -0.35355339, -0.35355339, 0.35355339, - -0.35355339, 0.35355339, 0.35355339, -0.35355339]])) - - targets.append(np.array([ [0, 0, 0, 0, - 0.70710678, 0.70710678, 0, 0], - [0, 0, 0, 0, - 0.70710678, -0.70710678, 0, 0], - [0, 0, 0, 0, - 0, 0, 0.70710678, 0.70710678], - [0.70710678, -0.70710678, 0, 0, - 0, 0, 0, 0], - [0.70710678, 0.70710678, 0, 0, - 0, 0, 0, 0], - [0, 0, 0, 0, - 0, 0, 0.70710678, -0.70710678], - [0, 0, 0.70710678, 0.70710678, - 0, 0, 0, 0], - [0, 0, 0.70710678, -0.70710678, - 0, 0, 0, 0]])) - - targets.append(np.array([ [0, 0, 0.70710678, 0.70710678, - 0, 0, 0, 0], - [0, 0, 0.70710678, -0.70710678, - 0, 0, 0, 0], - [0.70710678, 0.70710678, 0, 0, - 0, 0, 0, 0], - [0, 0, 0, 0, - 0, 0, 0.70710678, -0.70710678], - [0, 0, 0, 0, - 0, 0, 0.70710678, 0.70710678], - [0.70710678, -0.70710678, 0, 0, - 0, 0, 0, 0], - [0, 0, 0, 0, - 0.70710678, 0.70710678, 0, 0], - [0, 0, 0, 0, - 0.70710678, -0.70710678, 0, 0]])) - - targets.append(np.array([ [0.70710678, 0, 0.70710678, 0, - 0, 0, 0, 0], - [0, 0.70710678, 0, 0.70710678, - 0, 0, 0, 0], - [0.70710678, 0, -0.70710678, 0, - 0, 0, 0, 0], - [0, 0, 0, 0, - 0, 0.70710678, 0, 0.70710678], - [0, 0, 0, 0, - 0.70710678, 0, 0.70710678, 0], - [0, 0.70710678, 0, -0.70710678, - 0, 0, 0, 0], - [0, 0, 0, 0, - 0.70710678, 0, -0.70710678, 0], - [0, 0, 0, 0, - 0, 0.70710678, 0, -0.70710678]])) - - targets.append(np.array([ [0.70710678, 0, 0, 0, - 0.70710678, 0, 0, 0], - [0, 0.70710678, 0, 0, - 0, 0.70710678, 0, 0], - [0, 0, 0.70710678, 0, - 0, 0, 0.70710678, 0], - [0, 0.70710678, 0, 0, - 0, -0.70710678, 0, 0], - [0.70710678, 0, 0, 0, - -0.70710678, 0, 0, 0], - [0, 0, 0, 0.70710678, - 0, 0, 0, 0.70710678], - [0, 0, 0.70710678, 0, - 0, 0, -0.70710678, 0], - [0, 0, 0, 0.70710678, - 0, 0, 0, -0.70710678]])) - - targets.append(np.array([ [0.70710678, 0.70710678, 0, 0, - 0, 0, 0, 0], - [0.70710678, -0.70710678, 0, 0, - 0, 0, 0, 0], - [0, 0, 0.70710678, 0.70710678, - 0, 0, 0, 0], - [0, 0, 0, 0, - 0.70710678, -0.70710678, 0, 0], - [0, 0, 0, 0, - 0.70710678, 0.70710678, 0, 0], - [0, 0, 0.70710678, -0.70710678, - 0, 0, 0, 0], - [0, 0, 0, 0, - 0, 0, 0.70710678, 0.70710678], - [0, 0, 0, 0, - 0, 0, 0.70710678, -0.70710678]])) - - targets.append(np.array([ [0, 0, 0, 0, - 0, 0, 0.70710678, 0.70710678], - [0, 0, 0, 0, - 0, 0, 0.70710678, -0.70710678], - [0, 0, 0, 0, - 0.70710678, 0.70710678, 0, 0], - [0, 0, 0.70710678, -0.70710678, - 0, 0, 0, 0], - [0, 0, 0.70710678, 0.70710678, - 0, 0, 0, 0], - [0, 0, 0, 0, - 0.70710678, -0.70710678, 0, 0], - [0.70710678, 0.70710678, 0, 0, - 0, 0, 0, 0], - [0.70710678, -0.70710678, 0, 0, - 0, 0, 0, 0]])) + targets.append( + np.array([[ + 0.35355339, 0.35355339, 0.35355339, 0.35355339, 0.35355339, + 0.35355339, 0.35355339, 0.35355339 + ], + [ + 0.35355339, -0.35355339, 0.35355339, -0.35355339, + 0.35355339, -0.35355339, 0.35355339, -0.35355339 + ], + [ + 0.35355339, 0.35355339, -0.35355339, -0.35355339, + 0.35355339, 0.35355339, -0.35355339, -0.35355339 + ], + [ + 0.35355339, -0.35355339, 0.35355339, -0.35355339, + -0.35355339, 0.35355339, -0.35355339, 0.35355339 + ], + [ + 0.35355339, 0.35355339, 0.35355339, 0.35355339, + -0.35355339, -0.35355339, -0.35355339, -0.35355339 + ], + [ + 0.35355339, -0.35355339, -0.35355339, 0.35355339, + 0.35355339, -0.35355339, -0.35355339, 0.35355339 + ], + [ + 0.35355339, 0.35355339, -0.35355339, -0.35355339, + -0.35355339, -0.35355339, 0.35355339, 0.35355339 + ], + [ + 0.35355339, -0.35355339, -0.35355339, 0.35355339, + -0.35355339, 0.35355339, 0.35355339, -0.35355339 + ]])) + + targets.append( + np.array([[0, 0, 0, 0, 0.70710678, 0.70710678, 0, 0], + [0, 0, 0, 0, 0.70710678, -0.70710678, 0, 0], + [0, 0, 0, 0, 0, 0, 0.70710678, 0.70710678], + [0.70710678, -0.70710678, 0, 0, 0, 0, 0, 0], + [0.70710678, 0.70710678, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0.70710678, -0.70710678], + [0, 0, 0.70710678, 0.70710678, 0, 0, 0, 0], + [0, 0, 0.70710678, -0.70710678, 0, 0, 0, 0]])) + + targets.append( + np.array([[0, 0, 0.70710678, 0.70710678, 0, 0, 0, 0], + [0, 0, 0.70710678, -0.70710678, 0, 0, 0, 0], + [0.70710678, 0.70710678, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0.70710678, -0.70710678], + [0, 0, 0, 0, 0, 0, 0.70710678, 0.70710678], + [0.70710678, -0.70710678, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0.70710678, 0.70710678, 0, 0], + [0, 0, 0, 0, 0.70710678, -0.70710678, 0, 0]])) + + targets.append( + np.array([[0.70710678, 0, 0.70710678, 0, 0, 0, 0, 0], + [0, 0.70710678, 0, 0.70710678, 0, 0, 0, 0], + [0.70710678, 0, -0.70710678, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0.70710678, 0, 0.70710678], + [0, 0, 0, 0, 0.70710678, 0, 0.70710678, 0], + [0, 0.70710678, 0, -0.70710678, 0, 0, 0, 0], + [0, 0, 0, 0, 0.70710678, 0, -0.70710678, 0], + [0, 0, 0, 0, 0, 0.70710678, 0, -0.70710678]])) + + targets.append( + np.array([[0.70710678, 0, 0, 0, 0.70710678, 0, 0, 0], + [0, 0.70710678, 0, 0, 0, 0.70710678, 0, 0], + [0, 0, 0.70710678, 0, 0, 0, 0.70710678, 0], + [0, 0.70710678, 0, 0, 0, -0.70710678, 0, 0], + [0.70710678, 0, 0, 0, -0.70710678, 0, 0, 0], + [0, 0, 0, 0.70710678, 0, 0, 0, 0.70710678], + [0, 0, 0.70710678, 0, 0, 0, -0.70710678, 0], + [0, 0, 0, 0.70710678, 0, 0, 0, -0.70710678]])) + + targets.append( + np.array([[0.70710678, 0.70710678, 0, 0, 0, 0, 0, 0], + [0.70710678, -0.70710678, 0, 0, 0, 0, 0, 0], + [0, 0, 0.70710678, 0.70710678, 0, 0, 0, 0], + [0, 0, 0, 0, 0.70710678, -0.70710678, 0, 0], + [0, 0, 0, 0, 0.70710678, 0.70710678, 0, 0], + [0, 0, 0.70710678, -0.70710678, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0.70710678, 0.70710678], + [0, 0, 0, 0, 0, 0, 0.70710678, -0.70710678]])) + + targets.append( + np.array([[0, 0, 0, 0, 0, 0, 0.70710678, 0.70710678], + [0, 0, 0, 0, 0, 0, 0.70710678, -0.70710678], + [0, 0, 0, 0, 0.70710678, 0.70710678, 0, 0], + [0, 0, 0.70710678, -0.70710678, 0, 0, 0, 0], + [0, 0, 0.70710678, 0.70710678, 0, 0, 0, 0], + [0, 0, 0, 0, 0.70710678, -0.70710678, 0, 0], + [0.70710678, 0.70710678, 0, 0, 0, 0, 0, 0], + [0.70710678, -0.70710678, 0, 0, 0, 0, 0, 0]])) return targets - + + +# ========================================================================== +# CU1 +# ========================================================================== +def cu1_gate_circuits_nondeterministic(final_measure): + circuits = [] + qr = QuantumRegister(2) + if final_measure: + cr = ClassicalRegister(2) + regs = (qr, cr) + else: + regs = (qr, ) + + # H^X.CU1(0,0,1).H^X + circuit = QuantumCircuit(*regs) + circuit.h(qr[1]) + circuit.x(qr[0]) + circuit.cu1(0, qr[0], qr[1]) + circuit.x(qr[0]) + circuit.h(qr[1]) + + if final_measure: + circuit.barrier(qr) + circuit.measure(qr, cr) + circuits.append(circuit) + + # H^I.CU1(pi,0,1).H^I + circuit = QuantumCircuit(*regs) + circuit.h(qr[1]) + circuit.cu1(np.pi, qr[0], qr[1]) + circuit.h(qr[1]) + + if final_measure: + circuit.barrier(qr) + circuit.measure(qr, cr) + circuits.append(circuit) + + # H^X.CU1(pi/4,0,1).H^X + circuit = QuantumCircuit(*regs) + circuit.h(qr[1]) + circuit.x(qr[0]) + circuit.cu1(np.pi / 4, qr[0], qr[1]) + circuit.x(qr[0]) + circuit.h(qr[1]) + if final_measure: + circuit.barrier(qr) + circuit.measure(qr, cr) + circuits.append(circuit) + + # H^X.CU1(pi/2,0,1).H^X + circuit = QuantumCircuit(*regs) + circuit.h(qr[1]) + circuit.x(qr[0]) + circuit.cu1(np.pi / 2, qr[0], qr[1]) + circuit.x(qr[0]) + circuit.h(qr[1]) + if final_measure: + circuit.barrier(qr) + circuit.measure(qr, cr) + circuits.append(circuit) + + # H^X.CU1(pi,0,1).H^X + circuit = QuantumCircuit(*regs) + circuit.h(qr[1]) + circuit.x(qr[0]) + circuit.cu1(np.pi, qr[0], qr[1]) + circuit.x(qr[0]) + circuit.h(qr[1]) + if final_measure: + circuit.barrier(qr) + circuit.measure(qr, cr) + circuits.append(circuit) + + # H^H.CU1(0,0,1).H^H + circuit = QuantumCircuit(*regs) + circuit.h(qr[1]) + circuit.h(qr[0]) + circuit.cu1(0, qr[0], qr[1]) + circuit.h(qr[0]) + circuit.h(qr[1]) + + if final_measure: + circuit.barrier(qr) + circuit.measure(qr, cr) + circuits.append(circuit) + + # H^H.CU1(pi/2,0,1).H^H + circuit = QuantumCircuit(*regs) + circuit.h(qr[1]) + circuit.h(qr[0]) + circuit.cu1(np.pi / 2, qr[0], qr[1]) + circuit.h(qr[0]) + circuit.h(qr[1]) + if final_measure: + circuit.barrier(qr) + circuit.measure(qr, cr) + circuits.append(circuit) + + # H^H.CU1(pi,0,1).H^H + circuit = QuantumCircuit(*regs) + circuit.h(qr[1]) + circuit.h(qr[0]) + circuit.cu1(np.pi, qr[0], qr[1]) + circuit.h(qr[0]) + circuit.h(qr[1]) + if final_measure: + circuit.barrier(qr) + circuit.measure(qr, cr) + circuits.append(circuit) + + return circuits + + def cu1_gate_counts_nondeterministic(shots, hex_counts=True): """CU1-gate circuits reference counts.""" targets = [] @@ -1781,7 +1689,10 @@ def cu1_gate_counts_nondeterministic(shots, hex_counts=True): # H^I.CU1(pi,0,1).H^I targets.append({'0x0': shots}) # H^X.CU1(pi/4,0,1).H^X - targets.append({'0x0': shots * (0.25 * (2 + np.sqrt(2))), '0x2': shots * (0.25 * (2 - np.sqrt(2)))}) + targets.append({ + '0x0': shots * (0.25 * (2 + np.sqrt(2))), + '0x2': shots * (0.25 * (2 - np.sqrt(2))) + }) # H^X.CU1(pi/2,0,1).H^X targets.append({'0x0': shots * 0.5, '0x2': shots * 0.5}) # H^X.CU1(pi,0,1).H^X @@ -1789,9 +1700,19 @@ def cu1_gate_counts_nondeterministic(shots, hex_counts=True): # H^H.CU1(0,0,1).H^H targets.append({'0x0': shots}) # H^H.CU1(pi/2,0,1).H^H - targets.append({'0x0': shots * 0.625, '0x1': shots * 0.125, '0x2': shots * 0.125, '0x3': shots * 0.125}) + targets.append({ + '0x0': shots * 0.625, + '0x1': shots * 0.125, + '0x2': shots * 0.125, + '0x3': shots * 0.125 + }) # H^H.CU1(pi,0,1).H^H - targets.append({'0x0': shots * 0.25, '0x1': shots * 0.25, '0x2': shots * 0.25, '0x3': shots * 0.25}) + targets.append({ + '0x0': shots * 0.25, + '0x1': shots * 0.25, + '0x2': shots * 0.25, + '0x3': shots * 0.25 + }) else: # H^X.CU1(0,0,1).H^X targets.append({'00': shots}) @@ -1806,9 +1727,19 @@ def cu1_gate_counts_nondeterministic(shots, hex_counts=True): # H^H.CU1(0,0,1).H^H targets.append({'00': shots}) # H^H.CU1(pi/2,0,1).H^H - targets.append({'00': shots * 0.5125, '01': shots * 0.125, '10': shots * 0.125, '11': shots * 0.125}) + targets.append({ + '00': shots * 0.5125, + '01': shots * 0.125, + '10': shots * 0.125, + '11': shots * 0.125 + }) # H^H.CU1(pi,0,1).H^H - targets.append({'00': shots * 0.25, '01': shots * 0.25, '10': shots * 0.25, '11': shots * 0.25}) + targets.append({ + '00': shots * 0.25, + '01': shots * 0.25, + '10': shots * 0.25, + '11': shots * 0.25 + }) return targets @@ -1819,16 +1750,18 @@ def cu1_gate_statevector_nondeterministic(): # H^I.CU1(pi,0,1).H^I targets.append(np.array([1, 0, 0, 0])) # H^X.CU1(pi/4,0,1).H^X - targets.append(np.array( - [(0.25 * (2 + np.sqrt(2))) + (1 / (2 * np.sqrt(2)))*1j, 0, (0.25 * (2 - np.sqrt(2))) - (1 / (2 * np.sqrt(2)))*1j, 0])) + targets.append( + np.array([(0.25 * (2 + np.sqrt(2))) + (1 / (2 * np.sqrt(2))) * 1j, 0, + (0.25 * (2 - np.sqrt(2))) - (1 / (2 * np.sqrt(2))) * 1j, 0])) # H^X.CU1(pi/2,0,1).H^X - targets.append(np.array([0.5+0.5j, 0, 0.5-0.5j, 0])) + targets.append(np.array([0.5 + 0.5j, 0, 0.5 - 0.5j, 0])) # H^X.CU1(pi,0,1).H^X targets.append(np.array([0, 0, 1, 0])) # H^H.CU1(0,0,1).H^H targets.append(np.array([1, 0, 0, 0])) # H^H.CU1(pi/2,0,1).H^H - targets.append(np.array([0.75+0.25j, 0.25-0.25j, 0.25-0.25j, -0.25+0.25j])) + targets.append( + np.array([0.75 + 0.25j, 0.25 - 0.25j, 0.25 - 0.25j, -0.25 + 0.25j])) # H^H.CU1(pi,0,1).H^H targets.append(np.array([0.5, 0.5, 0.5, -0.5])) return targets @@ -1839,32 +1772,160 @@ def cu1_gate_unitary_nondeterministic(): # H^X.CU1(0,0,1).H^X targets.append(np.eye(4)) # H^I.CU1(pi,0,1).H^I - targets.append(np.array([[1, 0, 0, 0], - [0, 0, 0, 1], - [0, 0, 1, 0], - [0, 1, 0, 0]])) + targets.append( + np.array([[1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0]])) # H^X.CU1(pi/4,0,1).H^X - targets.append(np.array([[(0.25 * (2 + np.sqrt(2))) + (1 / (2 * np.sqrt(2)))*1j, 0, - (0.25 * (2 - np.sqrt(2))) - (1 / (2 * np.sqrt(2)))*1j, 0], - [0, 1, 0, 0], - [(0.25 * (2 - np.sqrt(2))) - (1 / (2 * np.sqrt(2)))*1j, 0, - (0.25 * (2 + np.sqrt(2))) + (1 / (2 * np.sqrt(2)))*1j, 0], - [0, 0, 0, 1]])) + targets.append( + np.array([[(0.25 * (2 + np.sqrt(2))) + (1 / (2 * np.sqrt(2))) * 1j, 0, + (0.25 * (2 - np.sqrt(2))) - (1 / (2 * np.sqrt(2))) * 1j, 0], + [0, 1, 0, 0], + [(0.25 * (2 - np.sqrt(2))) - (1 / (2 * np.sqrt(2))) * 1j, 0, + (0.25 * (2 + np.sqrt(2))) + (1 / (2 * np.sqrt(2))) * 1j, 0], + [0, 0, 0, 1]])) # H^X.CU1(pi/2,0,1).H^X - targets.append(np.array([[0.5+0.5j, 0, 0.5-0.5j, 0], - [0, 1, 0, 0], - [0.5-0.5j, 0, 0.5+0.5j, 0], - [0, 0, 0, 1]])) + targets.append( + np.array([[0.5 + 0.5j, 0, 0.5 - 0.5j, 0], [0, 1, 0, 0], + [0.5 - 0.5j, 0, 0.5 + 0.5j, 0], [0, 0, 0, 1]])) # H^X.CU1(pi,0,1).H^X - targets.append(np.array([[0, 0, 1, 0], - [0, 1, 0, 0], - [1, 0, 0, 0], - [0, 0, 0, 1]])) + targets.append( + np.array([[0, 0, 1, 0], [0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1]])) # H^H.CU1(0,0,1).H^H targets.append(np.eye(4)) # H^H.CU1(pi/2,0,1).H^H - targets.append((0.75 + 0.25j) * np.eye(4) + (0.25 - 0.25j) * np.array( - [[0, 1, 1, -1], [1, 0, -1, 1], [1, -1, 0, 1], [-1, 1, 1, 0]])) + targets.append( + (0.75 + 0.25j) * np.eye(4) + (0.25 - 0.25j) * + np.array([[0, 1, 1, -1], [1, 0, -1, 1], [1, -1, 0, 1], [-1, 1, 1, 0]])) # H^H.CU1(pi,0,1).H^H - targets.append(0.5 * np.array([[1, 1, 1, -1], [1, 1, -1, 1], [1, -1, 1, 1], [-1, 1, 1, 1]])) + targets.append( + 0.5 * + np.array([[1, 1, 1, -1], [1, 1, -1, 1], [1, -1, 1, 1], [-1, 1, 1, 1]])) + return targets + + +# ========================================================================== +# CU3 +# ========================================================================== +def cu3_gate_circuits_deterministic(final_measure): + circuits = [] + qr = QuantumRegister(2) + if final_measure: + cr = ClassicalRegister(2) + regs = (qr, cr) + else: + regs = (qr, ) + + # I^X.CI.I^X + circuit = QuantumCircuit(*regs) + circuit.x(qr[0]) + circuit.cu3(0, 0, 0, qr[0], qr[1]) + circuit.x(qr[0]) + if final_measure: + circuit.barrier(qr) + circuit.measure(qr, cr) + circuits.append(circuit) + + # CX + circuit = QuantumCircuit(*regs) + circuit.cu3(np.pi, 0, np.pi, qr[0], qr[1]) + if final_measure: + circuit.barrier(qr) + circuit.measure(qr, cr) + circuits.append(circuit) + + # I^X.CX.I^X + circuit = QuantumCircuit(*regs) + circuit.x(qr[0]) + circuit.cu3(np.pi, 0, np.pi, qr[0], qr[1]) + circuit.x(qr[0]) + if final_measure: + circuit.barrier(qr) + circuit.measure(qr, cr) + circuits.append(circuit) + + # H^X.CH.I^X + circuit = QuantumCircuit(*regs) + circuit.x(qr[0]) + circuit.cu3(np.pi / 2, 0, np.pi, qr[0], qr[1]) + circuit.x(qr[0]) + circuit.h(qr[1]) + if final_measure: + circuit.barrier(qr) + circuit.measure(qr, cr) + circuits.append(circuit) + + # I^X.CRX(pi).I^X + circuit = QuantumCircuit(*regs) + circuit.x(qr[0]) + circuit.cu3(np.pi, -np.pi / 2, np.pi / 2, qr[0], qr[1]) + circuit.x(qr[0]) + if final_measure: + circuit.barrier(qr) + circuit.measure(qr, cr) + circuits.append(circuit) + + # I^X.CRY(pi).I^X + circuit = QuantumCircuit(*regs) + circuit.x(qr[0]) + circuit.cu3(np.pi, 0, 0, qr[0], qr[1]) + circuit.x(qr[0]) + if final_measure: + circuit.barrier(qr) + circuit.measure(qr, cr) + circuits.append(circuit) + + return circuits + + +def cu3_gate_unitary_deterministic(): + targets = [] + + # I^X.CI.I^X + targets.append(np.eye(4)) + + # CX + targets.append( + np.array([[1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0]])) + + # I^X.CX.I^X + targets.append( + np.array([[0, 0, 1, 0], [0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1]])) + + # H^X.CH.I^X + targets.append( + np.array([[1, 0, 0, 0], [0, 1 / np.sqrt(2), 0, 1 / np.sqrt(2)], + [0, 0, 1, 0], [0, 1 / np.sqrt(2), 0, -1 / np.sqrt(2)]])) + + # I^X.CRX(pi).I^X + targets.append( + np.array([[0, 0, -1j, 0], [0, 1, 0, 0], [-1j, 0, 0, 0], [0, 0, 0, 1]])) + + # I^X.CRY(pi).I^X + targets.append( + np.array([[0, 0, -1, 0], [0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1]])) + + return targets + + +def cu3_gate_statevector_deterministic(): + + init_state = np.array([1, 0, 0, 0]) + targets = [mat.dot(init_state) for mat in cu3_gate_unitary_deterministic()] + + return targets + + +def cu3_gate_counts_deterministic(shots, hex_counts=True): + """CU2-gate circuits reference counts.""" + probs = [np.abs(vec)**2 for vec in cu3_gate_statevector_deterministic()] + targets = [] + for prob in probs: + if hex_counts: + targets.append({hex(i): shots * p for i, p in enumerate(prob)}) + else: + counts = {} + for i, p in enumerate(prob): + key = bin(i)[2:] + key = (2 - len(key)) * '0' + key + counts[key] = shots * p + targets.append(counts) return targets From ebc70542b35e90c5ed5368681a48d3efc91cbbbe Mon Sep 17 00:00:00 2001 From: Juan Gomez Date: Fri, 6 Dec 2019 21:49:53 +0000 Subject: [PATCH 10/12] Remove unused benchmarks directory --- test/benchmarks/parallelization_test.py | 51 ------------------------- 1 file changed, 51 deletions(-) delete mode 100644 test/benchmarks/parallelization_test.py diff --git a/test/benchmarks/parallelization_test.py b/test/benchmarks/parallelization_test.py deleted file mode 100644 index e837af259c..0000000000 --- a/test/benchmarks/parallelization_test.py +++ /dev/null @@ -1,51 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2018, 2019. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -import sys -import qiskit -from qiskit.compiler import assemble -from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister -from qiskit.providers.aer import QasmSimulator - -#import python tools -import numpy as np -import copy -import timeit -import matplotlib.pyplot as plt -import math - -from quantumvolume import quantum_volume_circuit - -qubit = 10 -depth = 10 -measure = True -seed = 0 -shots = 1024 - -simulator = QasmSimulator() - -parallel_shots_list = {1, 5, 10, 20, 30, 40, 50, 60, 70, 80} - -circuit = quantum_volume_circuit(qubit, depth, measure, seed) -qobj = assemble(circuit, simulator, shots=shots) - -for parallel_shots in parallel_shots_list: - backend_opts = { - 'max_parallel_threads': 80, - 'max_parallel_shots': parallel_shots, - 'parallel_state_update': 80 / parallel_shots - } - - result = simulator.run(qobj, backend_options=backend_opts).result() - - print(80, parallel_shots, 80 / parallel_shots, - result.metadata['time_taken']) From 036f534463204e0bdf29c75674fad3204299243d Mon Sep 17 00:00:00 2001 From: merav-aharoni <46567124+merav-aharoni@users.noreply.github.com> Date: Mon, 9 Dec 2019 18:55:59 +0200 Subject: [PATCH 11/12] Fix snapshot_probabilities in mps (#424) * added support for shapshot_probabilities in MPS * added support to reset in MPS * fixed bug in initialize for MPS --- CHANGELOG.md | 3 + .../matrix_product_state.hpp | 29 ++- .../matrix_product_state_internal.cpp | 193 ++++++++++++++++-- .../matrix_product_state_internal.hpp | 59 +++--- .../terra/backends/test_qasm_mps_simulator.py | 4 +- 5 files changed, 235 insertions(+), 53 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1c8c9ecd2..6c612a1374 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,8 +30,11 @@ Removed Fixed ----- +- MPS simulation method: fixed computation of snapshot_probabilities + on subsets of the qubits, in any ordering (\#424) - Fixes bug where cu3 was being applied as cu1 for unitary_simulator (\#483) + [0.3.3](https://github.com/Qiskit/qiskit-aer/compare/0.3.2...0.3.3) - 2019-11-14 ==================================================================================== diff --git a/src/simulators/matrix_product_state/matrix_product_state.hpp b/src/simulators/matrix_product_state/matrix_product_state.hpp index 4b8e4853c1..42e4d47e4a 100644 --- a/src/simulators/matrix_product_state/matrix_product_state.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state.hpp @@ -48,6 +48,8 @@ enum class Snapshots { expval_matrix//, //expval_matrix_var }; +// Enum class for different types of expectation values +enum class SnapshotDataType {average, average_var, pershot}; //========================================================================= // Matrix Product State subclass @@ -110,7 +112,7 @@ class State : public Base::State { // Return the set of qobj snapshot types supported by the State virtual stringset_t allowed_snapshots() const override { //TODO: Review this - return {"statevector", "memory", "register", + return {"statevector", "memory", "register", "probabilities", "expectation_value_pauli", //"expectation_value_pauli_with_variance", "expectation_value_matrix"//, //"expectation_value_matrix_with_variance" }; @@ -237,7 +239,7 @@ class State : public Base::State { // Snapshot current qubit probabilities for a measurement (average) void snapshot_probabilities(const Operations::Op &op, ExperimentData &data, - bool variance); + SnapshotDataType type); // Snapshot the expectation value of a Pauli operator void snapshot_pauli_expval(const Operations::Op &op, @@ -507,17 +509,19 @@ void State::snapshot_state(const Operations::Op &op, std::string name) { cvector_t statevector; qreg_.full_state_vector(statevector); - data.add_pershot_snapshot("statevector", op.string_params[0], statevector); } void State::snapshot_probabilities(const Operations::Op &op, ExperimentData &data, - bool variance) { - MatrixProductState::MPS_Tensor full_tensor = qreg_.state_vec(0, qreg_.num_qubits()-1); + SnapshotDataType type) { rvector_t prob_vector; - qreg_.probabilities_vector(prob_vector); - data.add_pershot_snapshot("probabilities", op.string_params[0], prob_vector); + qreg_.get_probabilities_vector(prob_vector, op.qubits); + auto probs = Utils::vec2ket(prob_vector, json_chop_threshold_, 16); + bool variance = type == SnapshotDataType::average_var; + data.add_average_snapshot("probabilities", op.string_params[0], + BaseState::creg_.memory_hex(), probs, variance); + } void State::apply_gate(const Operations::Op &op) { @@ -645,7 +649,9 @@ void State::apply_measure(const reg_t &qubits, } rvector_t State::measure_probs(const reg_t &qubits) const { - return qreg_.probabilities(qubits); + rvector_t probvector; + qreg_.get_probabilities_vector(probvector, qubits); + return probvector; } std::vector State::sample_measure(const reg_t &qubits, @@ -668,7 +674,6 @@ std::vector State::sample_measure(const reg_t &qubits, void State::apply_snapshot(const Operations::Op &op, ExperimentData &data) { // Look for snapshot type in snapshotset - auto it = snapshotset_.find(op.name); if (it == snapshotset_.end()) throw std::invalid_argument("MatrixProductState::invalid snapshot instruction \'" + @@ -678,6 +683,11 @@ void State::apply_snapshot(const Operations::Op &op, ExperimentData &data) { snapshot_state(op, data, "statevector"); break; } + case Snapshots::probs: { + // get probs as hexadecimal + snapshot_probabilities(op, data, SnapshotDataType::average); + break; + } case Snapshots::expval_pauli: { snapshot_pauli_expval(op, data, false); break; @@ -721,6 +731,7 @@ State::sample_measure_with_prob(const reg_t &qubits, return std::make_pair(outcome, probs[outcome]); } + //------------------------------------------------------------------------- } // end namespace MatrixProductState //------------------------------------------------------------------------- diff --git a/src/simulators/matrix_product_state/matrix_product_state_internal.cpp b/src/simulators/matrix_product_state/matrix_product_state_internal.cpp index b04913c296..67d584e30f 100644 --- a/src/simulators/matrix_product_state/matrix_product_state_internal.cpp +++ b/src/simulators/matrix_product_state/matrix_product_state_internal.cpp @@ -41,6 +41,27 @@ static const cmatrix_t one_measure = //------------------------------------------------------------------------ // local function declarations //------------------------------------------------------------------------ +//------------------------------------------------------------------------ +// Function name: reorder_all_qubits +// Description: The ordering of the amplitudes in the statevector in this module is +// [n, (n-1),.., 2, 1, 0], i.e., msb is leftmost and lsb is rightmost. +// Sometimes, we need to provide a different ordering of the amplitudes, such as +// in snapshot_probabilities. For example, instead of [2, 1, 0] the user requests +// the probabilities of [1, 0, 2]. +// Note that the ordering in the qubits vector is the same as that of the mps solver, +// i.e., qubits are numbered from left to right, e.g., 210 +// Input: orig_probvector - the ordered vector of probabilities +// qubits - a list containing the new ordering +// Returns: new_probvector - the vector in the new ordering +// e.g., 011->101 (for the ordering [1, 0, 2] +// +//------------------------------------------------------------------------ +template +void reorder_all_qubits(const std::vector& orig_probvector, + reg_t qubits, + std::vector& new_probvector); +uint_t reorder_qubits(const reg_t qubits, uint_t index); + //-------------------------------------------------------------------------- // Function name: reverse_all_bits // Description: The ordering of the amplitudes in the statevector in this module is @@ -48,12 +69,14 @@ static const cmatrix_t one_measure = // The ordering of the amplitudes in the statevector in Qasm in general is // 000, 100, 010, 110, 001, 101, 011, 111. // This function converts the statevector from one representation to the other. +// This is a special case of reorder_qubits // Input: the input statevector and the number of qubits // Returns: the statevector in reverse order //---------------------------------------------------------------- -cvector_t reverse_all_bits(const cvector_t& statevector, uint_t num_qubits); +template +std::vector reverse_all_bits(const std::vector& statevector, uint_t num_qubits); uint_t reverse_bits(uint_t num, uint_t len); - std::vector calc_new_indexes(std::vector indexes); + std::vector calc_new_indexes(std::vector indexes); // The following two functions are helper functions used by // initialize_from_statevector @@ -61,9 +84,62 @@ cmatrix_t reshape_matrix(cmatrix_t input_matrix); cmatrix_t mul_matrix_by_lambda(const cmatrix_t &mat, const rvector_t &lambda); + //------------------------------------------------------------------------ // local function implementations //------------------------------------------------------------------------ +template +void reorder_all_qubits(const std::vector& orig_probvector, + reg_t qubits, + std::vector& new_probvector) { + uint_t new_index; + uint_t length = 1ULL << qubits.size(); // length = pow(2, num_qubits) + // if qubits are [k0, k1,...,kn], move them to [0, 1, .. , n], but preserve relative + // ordering + reg_t squeezed_qubits(qubits.size()); + std::vector sorted_qubits; + for (uint_t index : qubits) { + sorted_qubits.push_back(index); + } + sort(sorted_qubits.begin(), sorted_qubits.end()); + for (uint_t i=0; i 0) { + new_index += current_val << shift; + } else if (shift < 0) { + new_index += current_val >> -shift; + } else { + new_index += current_val; + } + + } + } + return new_index; +} uint_t reverse_bits(uint_t num, uint_t len) { uint_t sum = 0; @@ -80,10 +156,11 @@ uint_t reverse_bits(uint_t num, uint_t len) { return sum; } -cvector_t reverse_all_bits(const cvector_t& statevector, uint_t num_qubits) +template +std::vector reverse_all_bits(const std::vector& statevector, uint_t num_qubits) { uint_t length = statevector.size(); // length = pow(2, num_qubits_) - cvector_t output_vector(length); + std::vector output_vector(length); #pragma omp parallel for for (int_t i = 0; i < static_cast(length); i++) { output_vector[i] = statevector[reverse_bits(i, num_qubits)]; @@ -128,6 +205,7 @@ cmatrix_t reshape_matrix(cmatrix_t input_matrix) { return reshaped_matrix; } + //------------------------------------------------------------------------ // implementation of MPS methods //------------------------------------------------------------------------ @@ -349,6 +427,47 @@ void MPS::apply_diagonal_matrix(const AER::reg_t &qubits, const cvector_t &vmat) apply_matrix(qubits, diag_mat); } +void MPS::centralize_qubits(MPS & new_MPS, const reg_t &qubits, + uint_t &new_first, uint_t &new_last) const { + new_MPS.initialize(*this); + bool ordered = true; + + if (qubits.size() == 1) { + new_first = qubits[0]; + new_last = qubits[0]; + return; + } + std::vector internalIndexes; + for (uint_t index : qubits) { + internalIndexes.push_back(index); + } + + for (uint_t index=0; index < qubits.size()-1; index++) { + if (qubits[index] > qubits[index+1]){ + ordered = false; + break; + } + } + if (!ordered) + sort(internalIndexes.begin(), internalIndexes.end()); + + std::vector new_indexes = calc_new_indexes(internalIndexes); + + uint_t avg = new_indexes[new_indexes.size()/2]; + auto it = lower_bound(internalIndexes.begin(), internalIndexes.end(), avg); + int mid = std::distance(internalIndexes.begin(), it); + for(uint_t i = mid; i < internalIndexes.size(); i++) + { + new_MPS.change_position(internalIndexes[i], new_indexes[i]); + } + for(int i = mid-1; i >= 0; i--) + { + new_MPS.change_position(internalIndexes[i], new_indexes[i]); + } + new_first = new_indexes[0]; + new_last = new_indexes[new_indexes.size()-1]; +} + void MPS::change_position(uint_t src, uint_t dst) { if(src == dst) @@ -364,10 +483,10 @@ void MPS::change_position(uint_t src, uint_t dst) cmatrix_t MPS::density_matrix(const reg_t &qubits) const { MPS temp_MPS; - uint_t front = 0, back = 0; - MPS_with_new_indices(qubits, temp_MPS, front, back); - MPS_Tensor psi = temp_MPS.state_vec(front, back); + uint_t new_first=0, new_last=0; + centralize_qubits(temp_MPS, qubits, new_first, new_last); + MPS_Tensor psi = temp_MPS.state_vec_as_MPS(new_first, new_last); uint_t size = psi.get_dim(); cmatrix_t rho(size,size); #ifdef _WIN32 @@ -383,6 +502,23 @@ cmatrix_t MPS::density_matrix(const reg_t &qubits) const return rho; } + +rvector_t MPS::trace_of_density_matrix(const reg_t &qubits) const +{ + MPS temp_MPS; + uint_t new_first=0, new_last=0; + centralize_qubits(temp_MPS, qubits, new_first, new_last); + + MPS_Tensor psi = temp_MPS.state_vec_as_MPS(new_first, new_last); + uint_t size = psi.get_dim(); + rvector_t trace_rho(size); + + for(int_t i = 0; i < static_cast(size); i++) { + trace_rho[i] = real(AER::Utils::sum( AER::Utils::elementwise_multiplication(psi.get_data(i), AER::Utils::conjugate(psi.get_data(i))) )); + } + return trace_rho; +} + void MPS::MPS_with_new_indices(const reg_t &qubits, MPS& temp_MPS, uint_t &front, uint_t &back) const { @@ -410,7 +546,6 @@ void MPS::MPS_with_new_indices(const reg_t &qubits, double MPS::expectation_value(const reg_t &qubits, const cmatrix_t &M) const { - // ***** Assuming ascending sorted qubits register ***** cmatrix_t rho = density_matrix(qubits); // Trace(rho*M). not using methods for efficiency @@ -568,7 +703,14 @@ std::vector MPS::get_matrices_sizes() const return result; } -MPS_Tensor MPS::state_vec(uint_t first_index, uint_t last_index) const +MPS_Tensor MPS::state_vec_as_MPS(const reg_t &qubits) const { + MPS temp_MPS; + uint_t new_first=0, new_last=0; + centralize_qubits(temp_MPS, qubits, new_first, new_last); + return temp_MPS.state_vec_as_MPS(new_first, new_last); +} + +MPS_Tensor MPS::state_vec_as_MPS(uint_t first_index, uint_t last_index) const { MPS_Tensor temp = q_reg_[first_index]; rvector_t left_lambda, right_lambda; @@ -576,17 +718,24 @@ MPS_Tensor MPS::state_vec(uint_t first_index, uint_t last_index) const right_lambda = (last_index != num_qubits_-1) ? lambda_reg_[last_index] : rvector_t {1.0}; temp.mul_Gamma_by_left_Lambda(left_lambda); + // special case of a single qubit + if (first_index == last_index) { + temp.mul_Gamma_by_right_Lambda(right_lambda); + return temp; + } + for(uint_t i = first_index+1; i < last_index+1; i++) { temp = MPS_Tensor::contract(temp, lambda_reg_[i-1], q_reg_[i]); } // now temp is a tensor of 2^n matrices of size 1X1 temp.mul_Gamma_by_right_Lambda(right_lambda); + return temp; } void MPS::full_state_vector(cvector_t& statevector) const { - MPS_Tensor mps_vec = state_vec(0, num_qubits_-1); + MPS_Tensor mps_vec = state_vec_as_MPS(0, num_qubits_-1); uint_t length = 1ULL << num_qubits_; // length = pow(2, num_qubits_) statevector.resize(length); #pragma omp parallel for @@ -598,15 +747,23 @@ void MPS::full_state_vector(cvector_t& statevector) const #endif } -void MPS::probabilities_vector(rvector_t& probvector) const +void MPS::get_probabilities_vector(rvector_t& probvector, + const reg_t &qubits) const { - MPS_Tensor mps_vec = state_vec(0, num_qubits_-1); - uint_t length = 1ULL << num_qubits_; // length = pow(2, num_qubits_) + cvector_t state_vec; + uint_t num_qubits = qubits.size(); + uint_t length = 1ULL << num_qubits; // length = pow(2, num_qubits) probvector.resize(length); - #pragma omp parallel for - for (int_t i = 0; i < static_cast(length); i++) { - probvector[i] = std::norm(mps_vec.get_data(reverse_bits(i, num_qubits_))(0,0)); - } + + // compute the probability vector assuming the qubits are in ascending order + rvector_t ordered_probvector = trace_of_density_matrix(qubits); + + // reorder the probabilities according to the specification in 'qubits' + rvector_t temp_probvector(ordered_probvector.size()); + reorder_all_qubits(ordered_probvector, qubits, temp_probvector); + + // reverse to be consistent with qasm ordering + probvector = reverse_all_bits(temp_probvector, num_qubits); } reg_t MPS::apply_measure(const reg_t &qubits, @@ -675,7 +832,7 @@ void MPS::initialize_from_statevector(uint_t num_qubits, const cvector_t state_v cmatrix_t statevector_as_matrix(1, state_vector.size()); #pragma omp parallel for - for (int_t i=0; i<(int_t)state_vector.size(); i++) { + for (int_t i=0; i(state_vector.size()); i++) { statevector_as_matrix(0, i) = state_vector[i]; } diff --git a/src/simulators/matrix_product_state/matrix_product_state_internal.hpp b/src/simulators/matrix_product_state/matrix_product_state_internal.hpp index 132530b2e3..cf06c4f575 100644 --- a/src/simulators/matrix_product_state/matrix_product_state_internal.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state_internal.hpp @@ -118,19 +118,8 @@ class MPS{ void apply_diagonal_matrix(const AER::reg_t &qubits, const cvector_t &vmat); - //---------------------------------------------------------------- - // function name: change_position - // Description: Move qubit from src to dst in the MPS. Used only - // for expectation value calculations. Similar to swap, but doesn't - // move qubit in dst back to src, therefore being used only on the temp MPS - // in Expectation_value function. - // Parameters: uint_t src, source of the qubit. - // uint_t dst, destination of the qubit. - // Returns: none. - //---------------------------------------------------------------- - void change_position(uint_t src, uint_t dst); - cmatrix_t density_matrix(const reg_t &qubits) const; + rvector_t trace_of_density_matrix(const reg_t &qubits) const; //--------------------------------------------------------------- // Function: expectation_value @@ -176,19 +165,23 @@ class MPS{ std::vector get_matrices_sizes() const; //---------------------------------------------------------------- - // function name: state_vec + // function name: state_vec_as_MPS // Description: Computes the state vector of a subset of qubits. // The regular use is with for all qubits. in this case the output is // MPS_Tensor with a 2^n vector of 1X1 matrices. // If not used for all qubits, the result tensor will contain a // 2^(distance between edges) vector of matrices of some size. This - // method is being used for computing expectation value of subset of qubits. + // method is used for computing expectation value of a subset of qubits. // Parameters: none. // Returns: none. //---------------------------------------------------------------- - MPS_Tensor state_vec(uint_t first_index, uint_t last_index) const; + MPS_Tensor state_vec_as_MPS(const reg_t &qubits) const; + + // This function computes the state vector for all the consecutive qubits + // between first_index and last_index + MPS_Tensor state_vec_as_MPS(uint_t first_index, uint_t last_index) const; void full_state_vector(cvector_t &state_vector) const; - void probabilities_vector(rvector_t& probvector) const; + void get_probabilities_vector(rvector_t& probvector, const reg_t &qubits) const; //methods from qasm_controller that are not supported yet void set_omp_threads(int threads) { @@ -213,13 +206,6 @@ class MPS{ std::cout << "enable_gate_opt not supported yet" < q_reg_; std::vector lambda_reg_; @@ -261,7 +272,7 @@ class MPS{ uint_t omp_threads_ = 1; // Disable multithreading by default uint_t omp_threshold_ = 14; // Qubit threshold for multithreading when enabled int sample_measure_index_size_ = 10; // Sample measure indexing qubit size - double json_chop_threshold_ = 0; // Threshold for choping small values + double json_chop_threshold_ = 1E-8; // Threshold for choping small values // in JSON serialization }; diff --git a/test/terra/backends/test_qasm_mps_simulator.py b/test/terra/backends/test_qasm_mps_simulator.py index 0c22ad02ce..f80f475830 100644 --- a/test/terra/backends/test_qasm_mps_simulator.py +++ b/test/terra/backends/test_qasm_mps_simulator.py @@ -72,8 +72,8 @@ class TestQasmMatrixProductStateSimulator( QasmReadoutNoiseTests, QasmPauliNoiseTests, QasmResetNoiseTests, - #QasmSnapshotStatevectorTests, - #QasmSnapshotProbabilitiesTests, # CRASHES: seg-fault + QasmSnapshotStatevectorTests, + QasmSnapshotProbabilitiesTests, QasmSnapshotStabilizerTests ): """QasmSimulator matrix product state method tests.""" From deaa41066a4ccfb48fed8e4010c2c674487b56b2 Mon Sep 17 00:00:00 2001 From: Juan Gomez Date: Mon, 9 Dec 2019 22:00:18 +0000 Subject: [PATCH 12/12] pip release: 0.3.4 --- qiskit/providers/aer/VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/providers/aer/VERSION.txt b/qiskit/providers/aer/VERSION.txt index 1c09c74e22..42045acae2 100644 --- a/qiskit/providers/aer/VERSION.txt +++ b/qiskit/providers/aer/VERSION.txt @@ -1 +1 @@ -0.3.3 +0.3.4