From e045a2bb54374b57c544c17d651c7c36855cae11 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Mon, 28 Sep 2020 11:28:15 -0400 Subject: [PATCH 001/126] Turn off gentle timeout and use common test class everywhere (#957) This commit fixes a few issues in #955 in the hopes of further debugging our test job timeouts in CI. The first change made is the timeout fixture is changed from gentle=True to gentle=False. The true case is generally preferable because it sets the signal handler to raise an exception which doesn't interrupt test execution however, if a runner process is stuck it might not work because the signal handling never gets invoked. gentle=false will just have the sigalarm kill the process. Additionally, in #955 one test class was missed and was using unittest.TestCase instead of QiskitAerTestCase, which meant that the tests in those classes could still get stuck since the fixture was not initialized for that class. --- test/terra/common.py | 2 +- test/terra/extensions/test_wrappers.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/test/terra/common.py b/test/terra/common.py index 2a353248ff..6ac7109c64 100644 --- a/test/terra/common.py +++ b/test/terra/common.py @@ -47,7 +47,7 @@ class QiskitAerTestCase(QiskitTestCase): def setUp(self): super().setUp() - self.useFixture(fixtures.Timeout(120, gentle=True)) + self.useFixture(fixtures.Timeout(120, gentle=False)) @classmethod def setUpClass(cls): diff --git a/test/terra/extensions/test_wrappers.py b/test/terra/extensions/test_wrappers.py index 4b2dfa41f9..4d38a977f4 100644 --- a/test/terra/extensions/test_wrappers.py +++ b/test/terra/extensions/test_wrappers.py @@ -23,9 +23,10 @@ statevector_controller_execute, unitary_controller_execute) from test.terra.reference import ref_algorithms, ref_measure, ref_1q_clifford +from test.terra.common import QiskitAerTestCase -class TestControllerExecuteWrappers(unittest.TestCase): +class TestControllerExecuteWrappers(QiskitAerTestCase): """Basic functionality tests for pybind-generated wrappers""" CFUNCS = [qasm_controller_execute(), statevector_controller_execute(), unitary_controller_execute()] From 5469925df09b79ef460d74efdb4def70d07629c1 Mon Sep 17 00:00:00 2001 From: "Christopher J. Wood" Date: Mon, 28 Sep 2020 14:06:05 -0400 Subject: [PATCH 002/126] Fix test performance (#958) --- .../qasm_simulator/qasm_delay_measure.py | 3 +- .../backends/qasm_simulator/qasm_fusion.py | 35 +-- .../qasm_simulator/qasm_initialize.py | 18 +- .../backends/qasm_simulator/qasm_noise.py | 10 +- .../qasm_simulator/qasm_thread_management.py | 58 +++-- .../backends/qasm_simulator/qasm_truncate.py | 1 - .../statevector_basics.py | 15 +- test/terra/backends/test_qasm_simulator.py | 3 +- .../test_qasm_simulator_density_matrix.py | 15 +- ...est_qasm_simulator_matrix_product_state.py | 2 + .../test_qasm_simulator_stabilizer.py | 3 +- .../test_qasm_simulator_statevector.py | 18 +- .../unitary_simulator/unitary_basics.py | 5 +- test/terra/reference/ref_multiplexer.py | 98 -------- test/terra/reference/ref_non_clifford.py | 235 ------------------ 15 files changed, 114 insertions(+), 405 deletions(-) diff --git a/test/terra/backends/qasm_simulator/qasm_delay_measure.py b/test/terra/backends/qasm_simulator/qasm_delay_measure.py index d9fcaee02a..17e7be1c7b 100644 --- a/test/terra/backends/qasm_simulator/qasm_delay_measure.py +++ b/test/terra/backends/qasm_simulator/qasm_delay_measure.py @@ -15,11 +15,12 @@ """ from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit +from qiskit.circuit.library import QFT, QuantumVolume from qiskit.compiler import assemble, transpile from qiskit.providers.aer import QasmSimulator from qiskit.providers.aer.noise import NoiseModel from qiskit.providers.aer.noise.errors import ReadoutError, depolarizing_error -from test.benchmark.tools import quantum_volume_circuit, qft_circuit + class QasmDelayMeasureTests: """QasmSimulator delay measure sampling optimization tests.""" diff --git a/test/terra/backends/qasm_simulator/qasm_fusion.py b/test/terra/backends/qasm_simulator/qasm_fusion.py index d54f1741cd..0dfa0c94e7 100644 --- a/test/terra/backends/qasm_simulator/qasm_fusion.py +++ b/test/terra/backends/qasm_simulator/qasm_fusion.py @@ -14,9 +14,8 @@ """ # pylint: disable=no-member -from test.benchmark.tools import quantum_volume_circuit, qft_circuit - from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit +from qiskit.circuit.library import QuantumVolume, QFT from qiskit.compiler import assemble, transpile from qiskit.providers.aer import QasmSimulator from qiskit.providers.aer.noise import NoiseModel @@ -93,13 +92,14 @@ def fusion_metadata(self, result): def test_fusion_theshold(self): """Test fusion threhsold""" shots = 100 - threshold = 10 + threshold = 6 backend_options = self.fusion_options(enabled=True, threshold=threshold) with self.subTest(msg='below fusion threshold'): - circuit = transpile(qft_circuit(threshold - 1, measure=True), + circuit = transpile(QFT(threshold - 1), self.SIMULATOR, basis_gates=['u1', 'u2', 'u3', 'cx', 'cz'], optimization_level=0) + circuit.measure_all() qobj = assemble(circuit, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( qobj, backend_options=backend_options).result() @@ -108,9 +108,10 @@ def test_fusion_theshold(self): self.assertFalse(meta.get('applied', False)) with self.subTest(msg='at fusion threshold'): - circuit = transpile(qft_circuit(threshold, measure=True), + circuit = transpile(QFT(threshold), self.SIMULATOR, basis_gates=['u1', 'u2', 'u3', 'cx', 'cz'], optimization_level=0) + circuit.measure_all() qobj = assemble(circuit, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( qobj, backend_options=backend_options).result() @@ -119,9 +120,10 @@ def test_fusion_theshold(self): self.assertTrue(meta.get('applied', False)) with self.subTest(msg='above fusion threshold'): - circuit = transpile(qft_circuit(threshold + 1, measure=True), + circuit = transpile(QFT(threshold + 1), self.SIMULATOR, basis_gates=['u1', 'u2', 'u3', 'cx', 'cz'], optimization_level=0) + circuit.measure_all() qobj = assemble(circuit, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( qobj, backend_options=backend_options).result() @@ -275,14 +277,14 @@ def test_control_fusion(self): def test_fusion_operations(self): """Test Fusion enable/disable option""" shots = 100 + num_qubits = 8 - qr = QuantumRegister(10) - cr = ClassicalRegister(10) + qr = QuantumRegister(num_qubits) + cr = ClassicalRegister(num_qubits) circuit = QuantumCircuit(qr, cr) - for i in range(10): - circuit.h(qr[i]) - circuit.barrier(qr) + circuit.h(qr) + circuit.barrier(qr) circuit.u3(0.1, 0.1, 0.1, qr[0]) circuit.barrier(qr) @@ -359,10 +361,12 @@ def test_fusion_operations(self): def test_fusion_qv(self): """Test Fusion with quantum volume""" shots = 100 - - circuit = transpile(quantum_volume_circuit(10, 2, measure=True, seed=0), + num_qubits = 8 + depth = 2 + circuit = transpile(QuantumVolume(num_qubits, depth, seed=0), backend=self.SIMULATOR, optimization_level=0) + circuit.measure_all() qobj = assemble([circuit], self.SIMULATOR, shots=shots, @@ -390,11 +394,12 @@ def test_fusion_qv(self): def test_fusion_qft(self): """Test Fusion with qft""" shots = 100 - - circuit = transpile(qft_circuit(10, measure=True), + num_qubits = 8 + circuit = transpile(QFT(num_qubits), backend=self.SIMULATOR, basis_gates=['u1', 'u2', 'u3', 'cx', 'cz'], optimization_level=0) + circuit.measure_all() qobj = assemble([circuit], self.SIMULATOR, shots=shots, diff --git a/test/terra/backends/qasm_simulator/qasm_initialize.py b/test/terra/backends/qasm_simulator/qasm_initialize.py index 3898a3ca2b..6bb2353f89 100644 --- a/test/terra/backends/qasm_simulator/qasm_initialize.py +++ b/test/terra/backends/qasm_simulator/qasm_initialize.py @@ -72,12 +72,12 @@ def test_initialize_1(self): """Test QasmSimulator initialize""" # For statevector output we can combine deterministic and non-deterministic # count output circuits - shots = 4000 + shots = 1000 circuits = ref_initialize.initialize_circuits_1(final_measure=True) targets = ref_initialize.initialize_counts_1(shots) qobj = assemble(circuits, self.SIMULATOR, shots=shots) - result = self.SIMULATOR.run( - qobj, backend_options=self.BACKEND_OPTS).result() + opts = self.BACKEND_OPTS.copy() + result = self.SIMULATOR.run(qobj, backend_options=opts).result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -85,22 +85,22 @@ def test_initialize_2(self): """Test QasmSimulator initializes""" # For statevector output we can combine deterministic and non-deterministic # count output circuits - shots = 4000 + shots = 1000 circuits = ref_initialize.initialize_circuits_2(final_measure=True) targets = ref_initialize.initialize_counts_2(shots) qobj = assemble(circuits, self.SIMULATOR, shots=shots) - result = self.SIMULATOR.run( - qobj, backend_options=self.BACKEND_OPTS).result() + opts = self.BACKEND_OPTS.copy() + result = self.SIMULATOR.run(qobj, backend_options=opts).result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) def test_initialize_sampling_opt(self): """Test sampling optimization""" - shots = 4000 + shots = 1000 circuits = ref_initialize.initialize_sampling_optimization() targets = ref_initialize.initialize_counts_sampling_optimization(shots) qobj = assemble(circuits, self.SIMULATOR, shots=shots) - result = self.SIMULATOR.run( - qobj, backend_options=self.BACKEND_OPTS).result() + opts = self.BACKEND_OPTS.copy() + result = self.SIMULATOR.run(qobj, backend_options=opts).result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) diff --git a/test/terra/backends/qasm_simulator/qasm_noise.py b/test/terra/backends/qasm_simulator/qasm_noise.py index f9c87e8e13..ebd6ef5221 100644 --- a/test/terra/backends/qasm_simulator/qasm_noise.py +++ b/test/terra/backends/qasm_simulator/qasm_noise.py @@ -56,7 +56,7 @@ class QasmPauliNoiseTests: def test_pauli_gate_noise(self): """Test simulation with Pauli gate error noise model.""" - shots = 4000 + shots = 1000 circuits = ref_pauli_noise.pauli_gate_error_circuits() noise_models = ref_pauli_noise.pauli_gate_error_noise_models() targets = ref_pauli_noise.pauli_gate_error_counts(shots) @@ -73,7 +73,7 @@ def test_pauli_gate_noise(self): def test_pauli_reset_noise(self): """Test simulation with Pauli reset error noise model.""" - shots = 4000 + shots = 1000 circuits = ref_pauli_noise.pauli_reset_error_circuits() noise_models = ref_pauli_noise.pauli_reset_error_noise_models() targets = ref_pauli_noise.pauli_reset_error_counts(shots) @@ -90,7 +90,7 @@ def test_pauli_reset_noise(self): def test_pauli_measure_noise(self): """Test simulation with Pauli measure error noise model.""" - shots = 4000 + shots = 1000 circuits = ref_pauli_noise.pauli_measure_error_circuits() noise_models = ref_pauli_noise.pauli_measure_error_noise_models() targets = ref_pauli_noise.pauli_measure_error_counts(shots) @@ -114,7 +114,7 @@ class QasmResetNoiseTests: def test_reset_gate_noise(self): """Test simulation with reset gate error noise model.""" - shots = 4000 + shots = 1000 circuits = ref_reset_noise.reset_gate_error_circuits() noise_models = ref_reset_noise.reset_gate_error_noise_models() targets = ref_reset_noise.reset_gate_error_counts(shots) @@ -138,7 +138,7 @@ class QasmKrausNoiseTests: def test_kraus_gate_noise(self): """Test simulation with Kraus gate error noise model.""" - shots = 4000 + shots = 1000 circuits = ref_kraus_noise.kraus_gate_error_circuits() noise_models = ref_kraus_noise.kraus_gate_error_noise_models() targets = ref_kraus_noise.kraus_gate_error_counts(shots) diff --git a/test/terra/backends/qasm_simulator/qasm_thread_management.py b/test/terra/backends/qasm_simulator/qasm_thread_management.py index af5e201829..861f1e1023 100644 --- a/test/terra/backends/qasm_simulator/qasm_thread_management.py +++ b/test/terra/backends/qasm_simulator/qasm_thread_management.py @@ -17,13 +17,14 @@ import multiprocessing import psutil -from test.benchmark.tools import quantum_volume_circuit from qiskit import execute, QuantumCircuit +from qiskit.circuit.library import QuantumVolume from qiskit.providers.aer import QasmSimulator from qiskit.providers.aer.noise import NoiseModel from qiskit.providers.aer.noise.errors.standard_errors import pauli_error from test.terra.decorators import requires_omp, requires_multiprocessing + # pylint: disable=no-member class QasmThreadManagementTests: """QasmSimulator thread tests.""" @@ -31,6 +32,25 @@ class QasmThreadManagementTests: SIMULATOR = QasmSimulator() BACKEND_OPTS = {} + def backend_options_parallel(self, + total_threads=None, + state_threads=None, + shot_threads=None, + exp_threads=None): + """Backend options with thread manangement.""" + opts = self.BACKEND_OPTS.copy() + if total_threads: + opts['max_parallel_threads'] = total_threads + else: + opts['max_parallel_threads'] = 0 + if shot_threads: + opts['max_parallel_shots'] = shot_threads + if state_threads: + opts['max_parallel_state_update'] = state_threads + if exp_threads: + opts['max_parallel_experiments'] = exp_threads + return opts + def dummy_noise_model(self): """Return dummy noise model for dummy circuit""" noise_model = NoiseModel() @@ -72,13 +92,14 @@ def threads_used(self, result): def test_max_memory_settings(self): """test max memory configuration""" - # 4-qubit quantum volume test circuit + # 4-qubit quantum circuit shots = 100 - circuit = quantum_volume_circuit(4, 1, measure=True, seed=0) + circuit = QuantumVolume(4, 1, seed=0) + circuit.measure_all() system_memory = int(psutil.virtual_memory().total / 1024 / 1024) # Test defaults - opts = self.BACKEND_OPTS.copy() + opts = self.backend_options_parallel() result = execute(circuit, self.SIMULATOR, shots=shots, backend_options=opts).result() max_mem_result = result.metadata.get('max_memory_mb') @@ -89,6 +110,7 @@ def test_max_memory_settings(self): # Test custom value max_mem_target = 128 + opts = self.backend_options_parallel() opts['max_memory_mb'] = max_mem_target result = execute(circuit, self.SIMULATOR, shots=shots, backend_options=opts).result() @@ -98,10 +120,11 @@ def test_max_memory_settings(self): def available_threads(self): """"Return the threads reported by the simulator""" + opts = self.backend_options_parallel() result = execute(self.dummy_circuit(1), self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS).result() + backend_options=opts).result() return self.threads_used(result)[0]['total'] @requires_omp @@ -109,7 +132,7 @@ def available_threads(self): def test_parallel_thread_defaults(self): """Test parallel thread assignment defaults""" - opts = self.BACKEND_OPTS + opts = self.backend_options_parallel() max_threads = self.available_threads() # Test single circuit, no noise @@ -219,7 +242,7 @@ def test_parallel_thread_assignment_priority(self): # We intentionally set the max shot and experiment threads to # twice the max threads to check they are limited correctly for custom_max_threads in [0, 1, 2, 4]: - opts = self.BACKEND_OPTS.copy() + opts = self.backend_options_parallel() opts['max_parallel_threads'] = custom_max_threads opts['max_parallel_experiments'] = 2 * custom_max_threads opts['max_parallel_shots'] = 2 * custom_max_threads @@ -333,8 +356,7 @@ def test_parallel_experiment_thread_assignment(self): """Test parallel experiment thread assignment""" max_threads = self.available_threads() - opts = self.BACKEND_OPTS.copy() - opts['max_parallel_experiments'] = max_threads + opts = self.backend_options_parallel(exp_threads=max_threads) # Test single circuit # Parallel experiments and shots should always be 1 @@ -402,7 +424,9 @@ def test_parallel_experiment_thread_assignment(self): # NOTE: this assumes execution on statevector simulator # which required approx 2 MB for 16 qubit circuit. opts['max_memory_mb'] = 1 - result = execute(2 * [quantum_volume_circuit(16, 1, measure=True, seed=0)], + circuit = QuantumVolume(16, 1, seed=0) + circuit.measure_all() + result = execute(2 * [circuit], self.SIMULATOR, shots=10*max_threads, backend_options=opts).result() @@ -421,8 +445,7 @@ def test_parallel_shot_thread_assignment(self): """Test parallel shot thread assignment""" max_threads = self.available_threads() - opts = self.BACKEND_OPTS.copy() - opts['max_parallel_shots'] = max_threads + opts = self.backend_options_parallel(shot_threads=max_threads) # Test single circuit # Parallel experiments and shots should always be 1 @@ -490,7 +513,9 @@ def test_parallel_shot_thread_assignment(self): # NOTE: this assumes execution on statevector simulator # which required approx 2 MB for 16 qubit circuit. opts['max_memory_mb'] = 1 - result = execute(2 * [quantum_volume_circuit(16, 1, measure=True, seed=0)], + circuit = QuantumVolume(16, 1, seed=0) + circuit.measure_all() + result = execute(2 * [circuit], self.SIMULATOR, shots=10*max_threads, backend_options=opts).result() @@ -509,11 +534,10 @@ def _test_qasm_explicit_parallelization(self): """test disabling parallel shots because max_parallel_shots is 1""" # Test circuit shots = multiprocessing.cpu_count() - circuit = quantum_volume_circuit(16, 1, measure=True, seed=0) + circuit = QuantumVolume(16, 1, seed=0) + circuit.measure_all() - backend_opts = self.BACKEND_OPTS.copy() - backend_opts['max_parallel_shots'] = 1 - backend_opts['max_parallel_experiments'] = 1 + backend_opts = self.backend_options_parallel(shot_threads=1, exp_threads=1) backend_opts['noise_model'] = self.dummy_noise_model() backend_opts['_parallel_experiments'] = 2 backend_opts['_parallel_shots'] = 3 diff --git a/test/terra/backends/qasm_simulator/qasm_truncate.py b/test/terra/backends/qasm_simulator/qasm_truncate.py index f13a881f50..e128f21bf0 100644 --- a/test/terra/backends/qasm_simulator/qasm_truncate.py +++ b/test/terra/backends/qasm_simulator/qasm_truncate.py @@ -9,7 +9,6 @@ QasmSimulator Integration Tests """ import json -from test.benchmark.tools import quantum_volume_circuit from qiskit import execute, QuantumRegister, ClassicalRegister, QuantumCircuit, Aer from qiskit.providers.aer import QasmSimulator from qiskit.providers.aer import noise diff --git a/test/terra/backends/statevector_simulator/statevector_basics.py b/test/terra/backends/statevector_simulator/statevector_basics.py index f74fb3c5dd..be2c403274 100644 --- a/test/terra/backends/statevector_simulator/statevector_basics.py +++ b/test/terra/backends/statevector_simulator/statevector_basics.py @@ -133,10 +133,7 @@ def test_conditional_unitary_1bit(self): backend_options=self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) - # TODO: check phase when terra fixes global phase bug - # See Terra issue #5125 for details - # https://github.com/Qiskit/qiskit-terra/issues/5125 - self.compare_statevector(result, circuits, targets, ignore_phase=True) + self.compare_statevector(result, circuits, targets) def test_conditional_gate_2bit(self): """Test conditional gates on 2-bit conditional register.""" @@ -163,10 +160,7 @@ def test_conditional_unitary_2bit(self): backend_options=self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) - # TODO: check phase when terra fixes global phase bug - # See Terra issue #5125 for details - # https://github.com/Qiskit/qiskit-terra/issues/5125 - self.compare_statevector(result, circuits, targets, ignore_phase=True) + self.compare_statevector(result, circuits, targets) # --------------------------------------------------------------------- # Test h-gate @@ -1079,10 +1073,7 @@ def test_unitary_gate(self): backend_options=self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) - # TODO: check phase when terra fixes global phase bug - # See Terra issue #5125 for details - # https://github.com/Qiskit/qiskit-terra/issues/5125 - self.compare_statevector(result, circuits, targets, ignore_phase=True) + self.compare_statevector(result, circuits, targets) def test_diagonal_gate(self): """Test simulation with diagonal gate circuit instructions.""" diff --git a/test/terra/backends/test_qasm_simulator.py b/test/terra/backends/test_qasm_simulator.py index 2515eed472..bd6aa2f6bb 100644 --- a/test/terra/backends/test_qasm_simulator.py +++ b/test/terra/backends/test_qasm_simulator.py @@ -110,7 +110,8 @@ class TestQasmSimulator(common.QiskitAerTestCase, """QasmSimulator automatic method tests.""" BACKEND_OPTS = { - "seed_simulator": 2113 + "seed_simulator": 2113, + "max_parallel_threads": 1 } diff --git a/test/terra/backends/test_qasm_simulator_density_matrix.py b/test/terra/backends/test_qasm_simulator_density_matrix.py index 15e0a60538..176746af5f 100644 --- a/test/terra/backends/test_qasm_simulator_density_matrix.py +++ b/test/terra/backends/test_qasm_simulator_density_matrix.py @@ -81,14 +81,22 @@ class DensityMatrixTests( class TestQasmSimulatorDensityMatrix(common.QiskitAerTestCase, DensityMatrixTests): """QasmSimulator density_matrix method tests.""" - BACKEND_OPTS = {"seed_simulator": 314159, "method": "density_matrix"} + BACKEND_OPTS = { + "seed_simulator": 314159, + "method": "density_matrix", + "max_parallel_threads": 1 + } @requires_method("qasm_simulator", "density_matrix_gpu") class TestQasmSimulatorDensityMatrixThrustGPU(common.QiskitAerTestCase, DensityMatrixTests): """QasmSimulator density_matrix_gpu method tests.""" - BACKEND_OPTS = {"seed_simulator": 314159, "method": "density_matrix_gpu"} + BACKEND_OPTS = { + "seed_simulator": 314159, + "method": "density_matrix_gpu", + "max_parallel_threads": 1 + } @requires_method("qasm_simulator", "density_matrix_thrust") @@ -97,7 +105,8 @@ class TestQasmSimulatorDensityMatrixThrustCPU(common.QiskitAerTestCase, """QasmSimulator density_matrix_thrust method tests.""" BACKEND_OPTS = { "seed_simulator": 314159, - "method": "density_matrix_thrust" + "method": "density_matrix_thrust", + "max_parallel_threads": 1 } diff --git a/test/terra/backends/test_qasm_simulator_matrix_product_state.py b/test/terra/backends/test_qasm_simulator_matrix_product_state.py index 1e6aeacdf4..94f557c6fd 100644 --- a/test/terra/backends/test_qasm_simulator_matrix_product_state.py +++ b/test/terra/backends/test_qasm_simulator_matrix_product_state.py @@ -51,6 +51,7 @@ from test.terra.backends.qasm_simulator.qasm_snapshot import QasmSnapshotExpValPauliNCTests from test.terra.backends.qasm_simulator.qasm_snapshot import QasmSnapshotExpValMatrixTests + class TestQasmMatrixProductStateSimulator( common.QiskitAerTestCase, QasmMeasureTests, @@ -90,5 +91,6 @@ class TestQasmMatrixProductStateSimulator( "max_parallel_threads": 1 } + if __name__ == '__main__': unittest.main() diff --git a/test/terra/backends/test_qasm_simulator_stabilizer.py b/test/terra/backends/test_qasm_simulator_stabilizer.py index 045c306306..a9fd8940a8 100644 --- a/test/terra/backends/test_qasm_simulator_stabilizer.py +++ b/test/terra/backends/test_qasm_simulator_stabilizer.py @@ -61,7 +61,8 @@ class TestQasmStabilizerSimulator(common.QiskitAerTestCase, BACKEND_OPTS = { "seed_simulator": 1337, - "method": "stabilizer" + "method": "stabilizer", + "max_parallel_threads": 1 } diff --git a/test/terra/backends/test_qasm_simulator_statevector.py b/test/terra/backends/test_qasm_simulator_statevector.py index f2c8e11cf6..38f62ec9f8 100644 --- a/test/terra/backends/test_qasm_simulator_statevector.py +++ b/test/terra/backends/test_qasm_simulator_statevector.py @@ -89,7 +89,11 @@ class StatevectorTests( class TestQasmSimulatorStatevector(common.QiskitAerTestCase, StatevectorTests): """QasmSimulator statevector method tests.""" - BACKEND_OPTS = {"seed_simulator": 271828, "method": "statevector"} + BACKEND_OPTS = { + "seed_simulator": 271828, + "method": "statevector", + "max_parallel_threads": 1 + } @requires_method("qasm_simulator", "statevector_gpu") @@ -97,7 +101,11 @@ class TestQasmSimulatorStatevectorThrustGPU(common.QiskitAerTestCase, StatevectorTests): """QasmSimulator statevector_gpu method tests.""" - BACKEND_OPTS = {"seed_simulator": 271828, "method": "statevector_gpu"} + BACKEND_OPTS = { + "seed_simulator": 271828, + "method": "statevector_gpu", + "max_parallel_threads": 1 + } @requires_method("qasm_simulator", "statevector_thrust") @@ -105,7 +113,11 @@ class TestQasmSimulatorStatevectorThrustCPU(common.QiskitAerTestCase, StatevectorTests): """QasmSimulator statevector_thrust method tests.""" - BACKEND_OPTS = {"seed_simulator": 271828, "method": "statevector_thrust"} + BACKEND_OPTS = { + "seed_simulator": 271828, + "method": "statevector_thrust", + "max_parallel_threads": 1 + } if __name__ == '__main__': diff --git a/test/terra/backends/unitary_simulator/unitary_basics.py b/test/terra/backends/unitary_simulator/unitary_basics.py index d16a4ff6e0..187e84bc7c 100644 --- a/test/terra/backends/unitary_simulator/unitary_basics.py +++ b/test/terra/backends/unitary_simulator/unitary_basics.py @@ -1048,10 +1048,7 @@ def test_unitary_gate(self): backend_options=self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) - # TODO: check phase when terra fixes global phase bug - # See Terra issue #5125 for details - # https://github.com/Qiskit/qiskit-terra/issues/5125 - self.compare_unitary(result, circuits, targets, ignore_phase=True) + self.compare_unitary(result, circuits, targets) def test_diagonal_gate(self): """Test simulation with diagonal gate circuit instructions.""" diff --git a/test/terra/reference/ref_multiplexer.py b/test/terra/reference/ref_multiplexer.py index a061126a13..8814925482 100644 --- a/test/terra/reference/ref_multiplexer.py +++ b/test/terra/reference/ref_multiplexer.py @@ -200,40 +200,6 @@ def multiplexer_ccx_gate_circuits_deterministic(final_measure=True): circuit.measure(qr, cr) circuits.append(circuit) - # (X^I^X).CCX(0,1,2).(X^I^X) -> |000> - circuit = QuantumCircuit(*regs) - circuit.x(qr[0]) - 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.barrier(qr) - circuit.x(qr[0]) - circuit.barrier(qr) - circuit.x(qr[2]) - if final_measure: - circuit.barrier(qr) - circuit.measure(qr, cr) - circuits.append(circuit) - - # (X^X^I).CCX(0,1,2).(X^X^I) -> |000> - circuit = QuantumCircuit(*regs) - circuit.x(qr[1]) - 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.barrier(qr) - circuit.x(qr[1]) - circuit.barrier(qr) - circuit.x(qr[2]) - if final_measure: - circuit.barrier(qr) - circuit.measure(qr, cr) - circuits.append(circuit) - # CCX(2,1,0) circuit = QuantumCircuit(*regs) circuit.append(multiplexer_multi_controlled_x(num_control_qubits), @@ -243,40 +209,6 @@ def multiplexer_ccx_gate_circuits_deterministic(final_measure=True): circuit.measure(qr, cr) circuits.append(circuit) - # (I^X^X).CCX(2,1,0).(I^X^X) -> |000> - circuit = QuantumCircuit(*regs) - circuit.x(qr[0]) - 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.barrier(qr) - circuit.x(qr[0]) - circuit.barrier(qr) - circuit.x(qr[1]) - if final_measure: - circuit.barrier(qr) - circuit.measure(qr, cr) - circuits.append(circuit) - - # (X^I^X).CCX(2,1,0).(X^I^X) -> |000> - circuit = QuantumCircuit(*regs) - circuit.x(qr[0]) - 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.barrier(qr) - circuit.x(qr[0]) - circuit.barrier(qr) - circuit.x(qr[2]) - if final_measure: - circuit.barrier(qr) - circuit.measure(qr, cr) - circuits.append(circuit) - # (X^X^I).CCX(2,1,0).(X^X^I) -> |001> circuit = QuantumCircuit(*regs) circuit.x(qr[1]) @@ -325,36 +257,6 @@ def multiplexer_ccx_gate_circuits_nondeterministic(final_measure=True): circuit.measure(qr, cr) circuits.append(circuit) - # (I^I^X).CCX(0,1,2).(I^H^X) -> |000> + |110> - circuit = QuantumCircuit(*regs) - circuit.h(qr[1]) - 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.barrier(qr) - circuit.x(qr[0]) - if final_measure: - circuit.barrier(qr) - circuit.measure(qr, cr) - circuits.append(circuit) - - # (I^X^I).CCX(2,1,0).(H^X^I) -> |000> + |101> - circuit = QuantumCircuit(*regs) - circuit.h(qr[2]) - 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.barrier(qr) - circuit.x(qr[1]) - if final_measure: - circuit.barrier(qr) - circuit.measure(qr, cr) - circuits.append(circuit) - # (X^I^I).CCX(2,1,0).(X^H^I) -> |000> + |011> circuit = QuantumCircuit(*regs) circuit.h(qr[1]) diff --git a/test/terra/reference/ref_non_clifford.py b/test/terra/reference/ref_non_clifford.py index 795d9a312f..d11ab0a218 100644 --- a/test/terra/reference/ref_non_clifford.py +++ b/test/terra/reference/ref_non_clifford.py @@ -39,16 +39,6 @@ def t_gate_circuits_deterministic(final_measure=True): circuit.measure(qr, cr) circuits.append(circuit) - # T.T = S - circuit = QuantumCircuit(*regs) - circuit.t(qr) - circuit.barrier(qr) - circuit.t(qr) - if final_measure: - circuit.barrier(qr) - circuit.measure(qr, cr) - circuits.append(circuit) - # T.X circuit = QuantumCircuit(*regs) circuit.x(qr) @@ -59,24 +49,6 @@ def t_gate_circuits_deterministic(final_measure=True): circuit.measure(qr, cr) circuits.append(circuit) - # H.T.T.T.T.H = H.Z.H = X - circuit = QuantumCircuit(*regs) - circuit.h(qr) - circuit.barrier(qr) - circuit.t(qr) - circuit.barrier(qr) - circuit.t(qr) - circuit.barrier(qr) - circuit.t(qr) - circuit.barrier(qr) - circuit.t(qr) - circuit.barrier(qr) - circuit.h(qr) - if final_measure: - circuit.barrier(qr) - circuit.measure(qr, cr) - circuits.append(circuit) - return circuits @@ -86,21 +58,13 @@ def t_gate_counts_deterministic(shots, hex_counts=True): if hex_counts: # T targets.append({'0x0': shots}) - # T.T = S - targets.append({'0x0': shots}) # T.X targets.append({'0x1': shots}) - # H.T.T.T.TH = H.Z.H = X - targets.append({'0x1': shots}) else: # T targets.append({'0': shots}) - # T.T = S - targets.append({'0': shots}) # T.X targets.append({'1': shots}) - # H.T.T.T.TH = H.Z.H = X - targets.append({'1': shots}) return targets @@ -109,12 +73,8 @@ def t_gate_statevector_deterministic(): targets = [] # T targets.append(np.array([1, 0])) - # T.T = S - targets.append(np.array([1, 0])) # T.X targets.append(np.array([0, 1 + 1j]) / np.sqrt(2)) - # H.T.T.T.T.H = H.Z.H = X - targets.append(np.array([0, 1])) return targets @@ -123,12 +83,8 @@ def t_gate_unitary_deterministic(): targets = [] # T targets.append(np.diag([1, (1 + 1j) / np.sqrt(2)])) - # T.T = S - targets.append(np.diag([1, 1j])) # T.X targets.append(np.array([[0, 1], [(1 + 1j) / np.sqrt(2), 0]])) - # H.T.T.T.TH = H.Z.H = X - targets.append(np.array([[0, 1], [1, 0]])) return targets @@ -265,23 +221,6 @@ def tdg_gate_circuits_deterministic(final_measure=True): circuit.measure(qr, cr) circuits.append(circuit) - # H.Tdg.Tdg.Tdg.Tdg.H = H.Z.H = X - circuit = QuantumCircuit(*regs) - circuit.h(qr) - circuit.barrier(qr) - circuit.tdg(qr) - circuit.barrier(qr) - circuit.tdg(qr) - circuit.barrier(qr) - circuit.tdg(qr) - circuit.barrier(qr) - circuit.tdg(qr) - circuit.barrier(qr) - circuit.h(qr) - if final_measure: - circuit.barrier(qr) - circuit.measure(qr, cr) - circuits.append(circuit) return circuits @@ -293,15 +232,11 @@ def tdg_gate_counts_deterministic(shots, hex_counts=True): targets.append({'0x0': shots}) # H.Tdg.T.H = I targets.append({'0x0': shots}) - # H.Tdg.Tdg.Tdg.Tdg.H = H.Z.H = X - targets.append({'0x1': shots}) else: # Tdg targets.append({'0': shots}) # H.Tdg.T.H = I targets.append({'0': shots}) - # H.Tdg.Tdg.Tdg.Tdg.H = H.Z.H = X - targets.append({'1': shots}) return targets @@ -312,8 +247,6 @@ def tdg_gate_statevector_deterministic(): targets.append(np.array([1, 0])) # H.Tdg.T.H = I targets.append(np.array([1, 0])) - # H.Tdg.Tdg.Tdg.Tdg.H = H.Z.H = X - targets.append(np.array([0, 1])) return targets @@ -324,8 +257,6 @@ def tdg_gate_unitary_deterministic(): targets.append(np.diag([1, (1 - 1j) / np.sqrt(2)])) # H.Tdg.T.H = I targets.append(np.eye(2)) - # H.Tdg.Tdg.Tdg.Tdg.H = H.Z.H = X - targets.append(np.array([[0, 1], [1, 0]])) return targets @@ -465,38 +396,6 @@ def ccx_gate_circuits_deterministic(final_measure=True): circuit.measure(qr, cr) circuits.append(circuit) - # (X^I^X).CCX(0,1,2).(X^I^X) -> |000> - circuit = QuantumCircuit(*regs) - circuit.x(qr[0]) - circuit.barrier(qr) - circuit.x(qr[2]) - circuit.barrier(qr) - circuit.ccx(qr[0], qr[1], qr[2]) - circuit.barrier(qr) - circuit.x(qr[0]) - circuit.barrier(qr) - circuit.x(qr[2]) - if final_measure: - circuit.barrier(qr) - circuit.measure(qr, cr) - circuits.append(circuit) - - # (X^X^I).CCX(0,1,2).(X^X^I) -> |000> - circuit = QuantumCircuit(*regs) - circuit.x(qr[1]) - circuit.barrier(qr) - circuit.x(qr[2]) - circuit.barrier(qr) - circuit.ccx(qr[0], qr[1], qr[2]) - circuit.barrier(qr) - circuit.x(qr[1]) - circuit.barrier(qr) - circuit.x(qr[2]) - if final_measure: - circuit.barrier(qr) - circuit.measure(qr, cr) - circuits.append(circuit) - # CCX(2,1,0) circuit = QuantumCircuit(*regs) circuit.ccx(qr[2], qr[1], qr[0]) @@ -505,38 +404,6 @@ def ccx_gate_circuits_deterministic(final_measure=True): circuit.measure(qr, cr) circuits.append(circuit) - # (I^X^X).CCX(2,1,0).(I^X^X) -> |000> - circuit = QuantumCircuit(*regs) - circuit.x(qr[0]) - circuit.barrier(qr) - circuit.x(qr[1]) - circuit.barrier(qr) - circuit.ccx(qr[2], qr[1], qr[0]) - circuit.barrier(qr) - circuit.x(qr[0]) - circuit.barrier(qr) - circuit.x(qr[1]) - if final_measure: - circuit.barrier(qr) - circuit.measure(qr, cr) - circuits.append(circuit) - - # (X^I^X).CCX(2,1,0).(X^I^X) -> |000> - circuit = QuantumCircuit(*regs) - circuit.x(qr[0]) - circuit.barrier(qr) - circuit.x(qr[2]) - circuit.barrier(qr) - circuit.ccx(qr[2], qr[1], qr[0]) - circuit.barrier(qr) - circuit.x(qr[0]) - circuit.barrier(qr) - circuit.x(qr[2]) - if final_measure: - circuit.barrier(qr) - circuit.measure(qr, cr) - circuits.append(circuit) - # (X^X^I).CCX(2,1,0).(X^X^I) -> |001> circuit = QuantumCircuit(*regs) circuit.x(qr[1]) @@ -564,33 +431,17 @@ def ccx_gate_counts_deterministic(shots, hex_counts=True): targets.append({'0x0': shots}) # (I^X^X).CCX(0,1,2).(I^X^X) -> |100> targets.append({'0x4': shots}) - # (X^I^X).CCX(0,1,2).(X^I^X) -> |000> - targets.append({'0x0': shots}) - # (X^X^I).CCX(0,1,2).(X^X^I) -> |000> - targets.append({'0x0': shots}) # CCX(2,1,0) targets.append({'0x0': shots}) - # (I^X^X).CCX(2,1,0).(I^X^X) -> |000> - targets.append({'0x0': shots}) - # (X^I^X).CCX(2,1,0).(X^I^X) -> |000> - targets.append({'0x0': shots}) # (X^X^I).CCX(2,1,0).(X^X^I) -> |001> targets.append({'0x1': shots}) else: # CCX(0,1,2) targets.append({'000': shots}) # (I^X^X).CCX(0,1,2).(I^X^X) -> |100> - targets.append({'100': shots}) - # (X^I^X).CCX(0,1,2).(X^I^X) -> |000> - targets.append({'000': shots}) - # (X^X^I).CCX(0,1,2).(X^X^I) -> |000> targets.append({'000': shots}) # CCX(2,1,0) targets.append({'000': shots}) - # (I^X^X).CCX(2,1,0).(I^X^X) -> |000> - targets.append({'000': shots}) - # (X^I^X).CCX(2,1,0).(X^I^X) -> |000> - targets.append({'000': shots}) # (X^X^I).CCX(2,1,0).(X^X^I) -> |001> targets.append({'001': shots}) return targets @@ -604,16 +455,8 @@ def ccx_gate_statevector_deterministic(): targets.append(zero_state) # (I^X^X).CCX(0,1,2).(I^X^X) -> |100> targets.append(np.array([0, 0, 0, 0, 1, 0, 0, 0])) - # (X^I^X).CCX(0,1,2).(X^I^X) -> |000> - targets.append(zero_state) - # (X^X^I).CCX(0,1,2).(X^X^I) -> |000> - targets.append(zero_state) # CCX(2,1,0) targets.append(zero_state) - # (I^X^X).CCX(2,1,0).(I^X^X) -> |000> - targets.append(zero_state) - # (X^I^X).CCX(2,1,0).(X^I^X) -> |000> - targets.append(zero_state) # (X^X^I).CCX(2,1,0).(X^X^I) -> |001> targets.append(np.array([0, 1, 0, 0, 0, 0, 0, 0])) return targets @@ -635,36 +478,12 @@ def ccx_gate_unitary_deterministic(): [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]])) - # (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]])) # 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]])) - # (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]])) - # (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]])) # (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], @@ -698,34 +517,6 @@ def ccx_gate_circuits_nondeterministic(final_measure=True): circuit.measure(qr, cr) circuits.append(circuit) - # (I^I^X).CCX(0,1,2).(I^H^X) -> |000> + |110> - circuit = QuantumCircuit(*regs) - circuit.h(qr[1]) - circuit.barrier(qr) - circuit.x(qr[0]) - circuit.barrier(qr) - circuit.ccx(qr[0], qr[1], qr[2]) - circuit.barrier(qr) - circuit.x(qr[0]) - if final_measure: - circuit.barrier(qr) - circuit.measure(qr, cr) - circuits.append(circuit) - - # (I^X^I).CCX(2,1,0).(H^X^I) -> |000> + |101> - circuit = QuantumCircuit(*regs) - circuit.h(qr[2]) - circuit.barrier(qr) - circuit.x(qr[1]) - circuit.barrier(qr) - circuit.ccx(qr[2], qr[1], qr[0]) - circuit.barrier(qr) - circuit.x(qr[1]) - if final_measure: - circuit.barrier(qr) - circuit.measure(qr, cr) - circuits.append(circuit) - # (X^I^I).CCX(2,1,0).(X^H^I) -> |000> + |011> circuit = QuantumCircuit(*regs) circuit.h(qr[1]) @@ -749,19 +540,11 @@ def ccx_gate_counts_nondeterministic(shots, hex_counts=True): if hex_counts: # (I^X^I).CCX(0,1,2).(I^X^H) -> |000> + |101> targets.append({'0x0': shots / 2, '0x5': shots / 2}) - # (I^I^X).CCX(0,1,2).(I^H^X) -> |000> + |110> - targets.append({'0x0': shots / 2, '0x6': shots / 2}) - # (I^X^I).CCX(2,1,0).(H^X^I) -> |000> + |101> - targets.append({'0x0': shots / 2, '0x5': shots / 2}) # (X^I^I).CCX(2,1,0).(X^H^I) -> |000> + |011> targets.append({'0x0': shots / 2, '0x3': shots / 2}) else: # (I^X^I).CCX(0,1,2).(I^X^H) -> |000> + |101> targets.append({'000': shots / 2, '101': shots / 2}) - # (I^I^X).CCX(0,1,2).(I^H^X) -> |000> + |110> - targets.append({'000': shots / 2, '110': shots / 2}) - # (I^X^I).CCX(2,1,0).(H^X^I) -> |000> + |101> - targets.append({'000': shots / 2, '101': shots / 2}) # (X^I^I).CCX(2,1,0).(X^H^I) -> |000> + |011> targets.append({'000': shots / 2, '011': shots / 2}) return targets @@ -772,10 +555,6 @@ def ccx_gate_statevector_nondeterministic(): targets = [] # (I^X^I).CCX(0,1,2).(I^X^H) -> |000> + |101> targets.append(np.array([1, 0, 0, 0, 0, 1, 0, 0]) / np.sqrt(2)) - # (I^I^X).CCX(0,1,2).(I^H^X) -> |000> + |110> - targets.append(np.array([1, 0, 0, 0, 0, 0, 1, 0]) / np.sqrt(2)) - # (I^X^I).CCX(2,1,0).(H^X^I) -> |000> + |101> - targets.append(np.array([1, 0, 0, 0, 0, 1, 0, 0]) / np.sqrt(2)) # (X^I^I).CCX(2,1,0).(X^H^I) -> |000> + |011> targets.append(np.array([1, 0, 0, 1, 0, 0, 0, 0]) / np.sqrt(2)) return targets @@ -791,20 +570,6 @@ def ccx_gate_unitary_nondeterministic(): [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)) - # (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)) # (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], From 0721a40f218f0620d75951d80edd48b3f63b38b8 Mon Sep 17 00:00:00 2001 From: "Christopher J. Wood" Date: Mon, 28 Sep 2020 18:49:29 -0400 Subject: [PATCH 003/126] Refactor GHA config and attempt to fix pickle tests (#959) * Change test order for GHA * Add timeout to GHA tests * Fix multiprocessing Pool test This test seemed to be causing the CI instances to hang as they only have 2 CPU threads. * Cache pip in GHA jobs This commit adds support for caching pip downloads between runs in github actions CI. Right now there is no caching of packages so we go out to pypi every time we need to download a dependency. This commit adds a caching step to all the CI jobs so we can rely on a local cache instead of downloading all the python packages every run. Co-authored-by: Matthew Treinish --- .github/workflows/main.yml | 71 +++++++++++++++++++++++--- test/terra/extensions/test_wrappers.py | 32 ++++++------ 2 files changed, 81 insertions(+), 22 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1aba0493d6..cefb3130d6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,10 +13,19 @@ jobs: uses: actions/setup-python@v2 with: python-version: 3.8 + - name: Pip cache + uses: actions/cache@v1 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-lint-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} + restore-keys: | + ${{ runner.os }}-pip-lint- + ${{ runner.os }}-pip- + ${{ runner.os }}- - name: Install deps run: | set -e - pip install -U pip + pip install -U pip wheel pip install -U -c constraints.txt git+https://github.com/Qiskit/qiskit-terra pip install -U -c constraints.txt -r requirements-dev.txt shell: bash @@ -36,10 +45,19 @@ jobs: uses: actions/setup-python@v2 with: python-version: 3.7 + - name: Pip cache + uses: actions/cache@v1 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-docs-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} + restore-keys: | + ${{ runner.os }}-pip-docs- + ${{ runner.os }}-pip- + ${{ runner.os }}- - name: Install Deps run: | set -e - pip install -U pip virtualenv + pip install -U pip virtualenv wheel pip install -U tox sudo apt-get update sudo apt-get install -y build-essential libopenblas-dev @@ -91,6 +109,7 @@ jobs: sdist: name: compile-sdist-python${{ matrix.python-version }}-${{ matrix.platform.os }} runs-on: ${{ matrix.platform.os }} + needs: ["lint"] strategy: matrix: python-version: [3.6, 3.7, 3.8] @@ -104,6 +123,15 @@ jobs: uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} + - name: Pip cache + uses: actions/cache@v1 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-sdist-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} + restore-keys: | + ${{ runner.os }}-pip-sdist- + ${{ runner.os }}-pip- + ${{ runner.os }}- - name: Install Deps run: python -m pip install -U setuptools wheel virtualenv - name: Install openblas @@ -127,6 +155,7 @@ jobs: wheel: name: compile-wheel-${{ matrix.os }} runs-on: ${{ matrix.os }} + needs: ["lint"] strategy: matrix: os: ["macOS-latest", "ubuntu-latest"] @@ -154,7 +183,8 @@ jobs: tests: name: tests-python${{ matrix.python-version }}-${{ matrix.os }} runs-on: ${{ matrix.os }} - needs: [standalone, wheel, sdist, lint, docs] + needs: [standalone, sdist, lint, docs] + timeout-minutes: 25 strategy: matrix: python-version: [3.6, 3.7, 3.8] @@ -168,11 +198,31 @@ jobs: uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} + - name: Pip cache + uses: actions/cache@v1 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-test-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} + restore-keys: | + ${{ runner.os }}-pip-test- + ${{ runner.os }}-pip- + ${{ runner.os }}- + if: runner.os != 'Windows' + - name: Pip cache + uses: actions/cache@v1 + with: + path: ~\AppData\Local\pip\Cache + key: ${{ runner.os }}-pip-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} + restore-keys: | + ${{ runner.os }}-pip-test- + ${{ runner.os }}-pip- + ${{ runner.os }}- + if: runner.os == 'Windows' - name: Add msbuild to PATH uses: microsoft/setup-msbuild@v1.0.1 if: runner.os == 'Windows' - name: Install Deps - run: python -m pip install -U -r requirements-dev.txt git+https://github.com/Qiskit/qiskit-terra + run: python -m pip install -U -r requirements-dev.txt wheel git+https://github.com/Qiskit/qiskit-terra - name: Install openblas run: | set -e @@ -212,18 +262,27 @@ jobs: tutorials: name: Tutorials runs-on: ubuntu-latest - needs: [standalone, wheel, sdist, lint, docs] + needs: [standalone, sdist, lint, docs] steps: - uses: actions/checkout@v2 - name: Set up Python 3.7 uses: actions/setup-python@v2 with: python-version: 3.7 + - name: Pip cache + uses: actions/cache@v1 + with: + path: ~\AppData\Local\pip\Cache + key: ${{ runner.os }}-pip-tutorials-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} + restore-keys: | + ${{ runner.os }}-pip-tutorials- + ${{ runner.os }}-pip- + ${{ runner.os }}- - name: Setup tutorials job run: | set -e git clone https://github.com/Qiskit/qiskit-tutorials --depth=1 - python -m pip install --upgrade pip + python -m pip install --upgrade pip wheel pip install -U -r requirements-dev.txt -c constraints.txt pip install -c constraints.txt git+https://github.com/Qiskit/qiskit-terra pip install -c constraints.txt . diff --git a/test/terra/extensions/test_wrappers.py b/test/terra/extensions/test_wrappers.py index 4d38a977f4..fd068125b7 100644 --- a/test/terra/extensions/test_wrappers.py +++ b/test/terra/extensions/test_wrappers.py @@ -14,10 +14,9 @@ import unittest import copy import pickle -import os from multiprocessing import Pool -from qiskit import assemble, transpile +from qiskit import assemble, transpile, QuantumCircuit from qiskit.providers.aer.backends import QasmSimulator, StatevectorSimulator, UnitarySimulator from qiskit.providers.aer.backends.controller_wrappers import (qasm_controller_execute, statevector_controller_execute, @@ -29,7 +28,9 @@ class TestControllerExecuteWrappers(QiskitAerTestCase): """Basic functionality tests for pybind-generated wrappers""" - CFUNCS = [qasm_controller_execute(), statevector_controller_execute(), unitary_controller_execute()] + CFUNCS = [qasm_controller_execute(), + statevector_controller_execute(), + unitary_controller_execute()] def test_deepcopy(self): """Test that the functors are deepcopy-able.""" @@ -42,15 +43,18 @@ def test_pickleable(self): bites = pickle.dumps(cfunc) cahpy = pickle.loads(bites) - def _create_qobj(self, circs, backend, backend_options=None, noise_model=None): - circs = transpile(circs, backend) - qobj = assemble(circs, backend) - fqobj = backend._format_qobj(qobj, backend_options=backend_options, noise_model=noise_model) + def _create_qobj(self, backend, noise_model=None): + num_qubits = 2 + circuit = QuantumCircuit(num_qubits) + circuit.x(list(range(num_qubits))) + qobj = assemble(transpile(circuit, backend), backend) + opts = {'max_parallel_threads': 1} + fqobj = backend._format_qobj(qobj, backend_options=opts, noise_model=noise_model) return fqobj def _map_and_test(self, cfunc, qobj): - n = max(os.cpu_count(), 2) - with Pool(processes=n) as p: + n = 2 + with Pool(processes=1) as p: rs = p.map(cfunc, [copy.deepcopy(qobj) for _ in range(n)]) self.assertEqual(len(rs), n) @@ -61,25 +65,21 @@ def test_mappable_qasm(self): """Test that the qasm controller can be mapped.""" cfunc = qasm_controller_execute() sim = QasmSimulator() - circs = ref_algorithms.teleport_circuit() - fqobj = self._create_qobj(circs, sim) + fqobj = self._create_qobj(sim) self._map_and_test(cfunc, fqobj) def test_mappable_statevector(self): """Test that the statevector controller can be mapped.""" cfunc = statevector_controller_execute() sim = StatevectorSimulator() - circs = ref_measure.measure_circuits_deterministic() - fqobj = self._create_qobj(circs, sim) + fqobj = self._create_qobj(sim) self._map_and_test(cfunc, fqobj) def test_mappable_unitary(self): """Test that the unitary controller can be mapped.""" cfunc = unitary_controller_execute() sim = UnitarySimulator() - circs = ref_1q_clifford.h_gate_circuits_deterministic( - final_measure=False) - fqobj = self._create_qobj(circs, sim) + fqobj = self._create_qobj(sim) self._map_and_test(cfunc, fqobj) From 5258ce66a1c88535a6cc423ac030bbd7ee5bacd7 Mon Sep 17 00:00:00 2001 From: merav-aharoni <46567124+merav-aharoni@users.noreply.github.com> Date: Tue, 29 Sep 2020 07:54:34 +0300 Subject: [PATCH 004/126] MPS: Apply kraus (#915) --- .../mps-apply-kraus-3cc8de65a66385ab.yaml | 8 +++ .../mps-density-matrix-51f7d5b1ef51e746.yaml | 7 +++ .../matrix_product_state.hpp | 60 +++++++++++++++++-- .../matrix_product_state_internal.cpp | 10 ++++ .../matrix_product_state_internal.hpp | 21 ++++--- src/simulators/matrix_product_state/svd.cpp | 4 +- ...est_qasm_simulator_matrix_product_state.py | 4 ++ 7 files changed, 95 insertions(+), 19 deletions(-) create mode 100644 releasenotes/notes/mps-apply-kraus-3cc8de65a66385ab.yaml create mode 100644 releasenotes/notes/mps-density-matrix-51f7d5b1ef51e746.yaml diff --git a/releasenotes/notes/mps-apply-kraus-3cc8de65a66385ab.yaml b/releasenotes/notes/mps-apply-kraus-3cc8de65a66385ab.yaml new file mode 100644 index 0000000000..d24a9fc18c --- /dev/null +++ b/releasenotes/notes/mps-apply-kraus-3cc8de65a66385ab.yaml @@ -0,0 +1,8 @@ +--- + +features: + - | + Added support for ``apply_kraus``in ``matrix_product_state.hpp``. This + enables running the ``matrix_product_state`` simulation method with all + types of Kraus noise. + diff --git a/releasenotes/notes/mps-density-matrix-51f7d5b1ef51e746.yaml b/releasenotes/notes/mps-density-matrix-51f7d5b1ef51e746.yaml new file mode 100644 index 0000000000..037898c262 --- /dev/null +++ b/releasenotes/notes/mps-density-matrix-51f7d5b1ef51e746.yaml @@ -0,0 +1,7 @@ +--- + +features: + - | + Adds support for ``snapshot_density_matrix`` in the ``matrix_product_state + simulation method``. + diff --git a/src/simulators/matrix_product_state/matrix_product_state.hpp b/src/simulators/matrix_product_state/matrix_product_state.hpp index 42a0f9b8fa..a6e1c39f12 100644 --- a/src/simulators/matrix_product_state/matrix_product_state.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state.hpp @@ -32,6 +32,7 @@ #include #include "framework/json.hpp" +#include "framework/utils.hpp" #include "simulators/state.hpp" #include "matrix_product_state_internal.hpp" #include "matrix_product_state_internal.cpp" @@ -46,7 +47,7 @@ const Operations::OpSet StateOpSet( Operations::OpType::reset, Operations::OpType::initialize, Operations::OpType::snapshot, Operations::OpType::barrier, Operations::OpType::bfunc, Operations::OpType::roerror, - Operations::OpType::matrix}, + Operations::OpType::matrix, Operations::OpType::kraus}, // Gates {"id", "x", "y", "z", "s", "sdg", "h", "t", "tdg", "u1", "u2", "u3", "U", "CX", "cx", "cz", "cu1", "swap", "ccx"}, @@ -197,9 +198,9 @@ class State : public Base::State { void apply_matrix(const reg_t &qubits, const cvector_t & vmat); // Apply a Kraus error operation - //void apply_kraus(const reg_t &qubits, - // const std::vector &krausops, - // RngEngine &rng); + void apply_kraus(const reg_t &qubits, + const std::vector &kmats, + RngEngine &rng); //----------------------------------------------------------------------- // Measurement Helpers @@ -475,6 +476,9 @@ void State::apply_ops(const std::vector &ops, case Operations::OpType::matrix: apply_matrix(op.qubits, op.mats[0]); break; + case Operations::OpType::kraus: + apply_kraus(op.qubits, op.mats, rng); + break; default: throw std::invalid_argument("MatrixProductState::State::invalid instruction \'" + op.name + "\'."); @@ -688,7 +692,7 @@ void State::apply_gate(const Operations::Op &op) { } } - void State::apply_matrix(const reg_t &qubits, const cvector_t &vmat) { +void State::apply_matrix(const reg_t &qubits, const cvector_t &vmat) { // Check if diagonal matrix if (vmat.size() == 1ULL << qubits.size()) { qreg_.apply_diagonal_matrix(qubits, vmat); @@ -697,6 +701,52 @@ void State::apply_gate(const Operations::Op &op) { } } +void State::apply_kraus(const reg_t &qubits, + const std::vector &kmats, + RngEngine &rng) { + // Check edge case for empty Kraus set (this shouldn't happen) + if (kmats.empty()) + return; // end function early + // Choose a real in [0, 1) to choose the applied kraus operator once + // the accumulated probability is greater than r. + // We know that the Kraus noise must be normalized + // So we only compute probabilities for the first N-1 kraus operators + // and infer the probability of the last one from 1 - sum of the previous + + double r = rng.rand(0., 1.); + double accum = 0.; + bool complete = false; + + cmatrix_t rho = qreg_.density_matrix(qubits); + + cmatrix_t sq_kmat; + double p = 0; + + // Loop through N-1 kraus operators + for (size_t j=0; j < kmats.size() - 1; j++) { + sq_kmat = AER::Utils::dagger(kmats[j]) * kmats[j]; + // Calculate probability + p = real(AER::Utils::trace(rho * sq_kmat)); + accum += p; + + // check if we need to apply this operator + if (accum > r) { + // rescale mat so projection is normalized + cmatrix_t temp_mat = kmats[j] * (1 / std::sqrt(p)); + apply_matrix(qubits, temp_mat); + complete = true; + break; + } + } + // check if we haven't applied a kraus operator yet + if (!complete) { + // Compute probability from accumulated + double renorm = 1 / std::sqrt(1. - accum); + cmatrix_t temp_mat = kmats.back()* renorm; + apply_matrix(qubits, temp_mat); + } +} + //========================================================================= // Implementation: Reset and Measurement Sampling //========================================================================= 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 1166d2db8d..e387792da4 100644 --- a/src/simulators/matrix_product_state/matrix_product_state_internal.cpp +++ b/src/simulators/matrix_product_state/matrix_product_state_internal.cpp @@ -1161,6 +1161,16 @@ double MPS::norm() { trace += vec[i]; return trace; } + +double MPS::norm(const reg_t &qubits, const cvector_t &vmat) const { + return norm(qubits, AER::Utils::devectorize_matrix(vmat)); +} + +double MPS::norm(const reg_t &qubits, const cmatrix_t &mat) const { + cmatrix_t norm_mat = AER::Utils::dagger(mat) * mat; + return expectation_value(qubits, norm_mat); +} + //------------------------------------------------------------------------------ // Sample measure outcomes - this method is similar to QubitVector::sample_measure, // with 2 differences: 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 f1dc75e72b..f458d2cae3 100644 --- a/src/simulators/matrix_product_state/matrix_product_state_internal.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state_internal.hpp @@ -230,18 +230,16 @@ class MPS{ return enable_gate_opt_; } - double norm(); - - double norm(const uint_t qubit, const cvector_t &vmat) const { - cmatrix_t mat = AER::Utils::devectorize_matrix(vmat); - reg_t qubits = {qubit}; - return expectation_value(qubits, mat); - } + //---------------------------------------------------------------- + // Function name: norm + // Description: the norm is defined as . + // It is equivalent to returning the expectation value of A^\dagger A, + // Returns: double (the norm) + //---------------------------------------------------------------- - double norm(const reg_t &qubits, const cvector_t &vmat) const { - cmatrix_t mat = AER::Utils::devectorize_matrix(vmat); - return expectation_value(qubits, mat); - } + double norm(); + double norm(const reg_t &qubits, const cvector_t &vmat) const; + double norm(const reg_t &qubits, const cmatrix_t &mat) const; reg_t sample_measure_using_probabilities(const rvector_t &rnds, const reg_t &qubits) const; @@ -260,6 +258,7 @@ class MPS{ void initialize_from_statevector(uint_t num_qubits, cvector_t state_vector); + private: MPS_Tensor& get_qubit(uint_t index) { diff --git a/src/simulators/matrix_product_state/svd.cpp b/src/simulators/matrix_product_state/svd.cpp index b9d5f8e089..73ab95d5e0 100644 --- a/src/simulators/matrix_product_state/svd.cpp +++ b/src/simulators/matrix_product_state/svd.cpp @@ -29,7 +29,6 @@ #include "framework/linalg/almost_equal.hpp" namespace AER { - // default values constexpr auto mul_factor = 1e2; constexpr long double tiny_factor = 1e30; @@ -149,8 +148,7 @@ void validate_SVD_result(cmatrix_t &A, cmatrix_t &U, rvector_t &S, cmatrix_t &V) } // added cut-off at the end -status csvd(cmatrix_t &A, cmatrix_t &U, rvector_t &S, cmatrix_t &V) -{ +status csvd(cmatrix_t &A, cmatrix_t &U, rvector_t &S, cmatrix_t &V) { 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; diff --git a/test/terra/backends/test_qasm_simulator_matrix_product_state.py b/test/terra/backends/test_qasm_simulator_matrix_product_state.py index 94f557c6fd..6f67c9b870 100644 --- a/test/terra/backends/test_qasm_simulator_matrix_product_state.py +++ b/test/terra/backends/test_qasm_simulator_matrix_product_state.py @@ -34,6 +34,7 @@ # Conditional instruction tests from test.terra.backends.qasm_simulator.qasm_conditional import QasmConditionalGateTests from test.terra.backends.qasm_simulator.qasm_conditional import QasmConditionalUnitaryTests +from test.terra.backends.qasm_simulator.qasm_conditional import QasmConditionalKrausTests # Algorithm circuit tests from test.terra.backends.qasm_simulator.qasm_algorithms import QasmAlgorithmTests from test.terra.backends.qasm_simulator.qasm_algorithms import QasmAlgorithmTestsWaltzBasis @@ -42,6 +43,7 @@ from test.terra.backends.qasm_simulator.qasm_noise import QasmReadoutNoiseTests from test.terra.backends.qasm_simulator.qasm_noise import QasmPauliNoiseTests from test.terra.backends.qasm_simulator.qasm_noise import QasmResetNoiseTests +from test.terra.backends.qasm_simulator.qasm_noise import QasmKrausNoiseTests # Snapshot tests from test.terra.backends.qasm_simulator.qasm_snapshot import QasmSnapshotStatevectorTests from test.terra.backends.qasm_simulator.qasm_snapshot import QasmSnapshotDensityMatrixTests @@ -59,6 +61,7 @@ class TestQasmMatrixProductStateSimulator( QasmResetTests, QasmConditionalGateTests, QasmConditionalUnitaryTests, + QasmConditionalKrausTests, QasmCliffordTests, QasmCliffordTestsWaltzBasis, QasmCliffordTestsMinimalBasis, @@ -74,6 +77,7 @@ class TestQasmMatrixProductStateSimulator( QasmReadoutNoiseTests, QasmPauliNoiseTests, QasmResetNoiseTests, + QasmKrausNoiseTests, QasmSnapshotStatevectorTests, QasmSnapshotDensityMatrixTests, QasmSnapshotProbabilitiesTests, From 3c5a81988962f3f984a2690bd7adbcbe9e3921a2 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Wed, 30 Sep 2020 14:41:34 -0400 Subject: [PATCH 005/126] Add python version to GHA pip cache key (#965) In #960/#959 we added caching for the local pip cache in the GHA CI jobs. However it was treating all instances of a job in a matrix as having a shared cache. This was causing a lower cache hit rate on wheels because they're often python version specific. This commit attempts to fix this by adding the python version to the cache key, meaning for jobs that run on multiple python versions it will only use the cache if its for the job on the same python version. --- .github/workflows/main.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index cefb3130d6..32dcfdf68e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -127,11 +127,11 @@ jobs: uses: actions/cache@v1 with: path: ~/.cache/pip - key: ${{ runner.os }}-pip-sdist-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} + key: ${{ runner.os }}-${{ matrix.python-version}}-pip-sdist-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} restore-keys: | - ${{ runner.os }}-pip-sdist- - ${{ runner.os }}-pip- - ${{ runner.os }}- + ${{ runner.os }}-${{ matrix.python-version}}-pip-sdist- + ${{ runner.os }}-${{ matrix.python-version}}-pip- + ${{ runner.os }}-${{ matrix.python-version}}- - name: Install Deps run: python -m pip install -U setuptools wheel virtualenv - name: Install openblas @@ -202,21 +202,21 @@ jobs: uses: actions/cache@v1 with: path: ~/.cache/pip - key: ${{ runner.os }}-pip-test-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} + key: ${{ runner.os }}-${{ matrix.python-version}}-pip-test-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} restore-keys: | - ${{ runner.os }}-pip-test- - ${{ runner.os }}-pip- - ${{ runner.os }}- + ${{ runner.os }}-${{ matrix.python-version}}-pip-test- + ${{ runner.os }}-${{ matrix.python-version}}-pip- + ${{ runner.os }}-${{ matrix.python-version}}- if: runner.os != 'Windows' - name: Pip cache uses: actions/cache@v1 with: path: ~\AppData\Local\pip\Cache - key: ${{ runner.os }}-pip-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} + key: ${{ runner.os }}-${{ matrix.python-version}}-pip-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} restore-keys: | - ${{ runner.os }}-pip-test- - ${{ runner.os }}-pip- - ${{ runner.os }}- + ${{ runner.os }}-${{ matrix.python-version}}-pip-test- + ${{ runner.os }}-${{ matrix.python-version}}-pip- + ${{ runner.os }}-${{ matrix.python-version}}- if: runner.os == 'Windows' - name: Add msbuild to PATH uses: microsoft/setup-msbuild@v1.0.1 From 2d502fc6db68cb193ebc6378003c53e1f528a5ea Mon Sep 17 00:00:00 2001 From: Manoel Marques Date: Thu, 1 Oct 2020 09:29:16 -0400 Subject: [PATCH 006/126] Update github actions cache to v2 (#967) --- .github/workflows/main.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 32dcfdf68e..5111b9e875 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,7 +14,7 @@ jobs: with: python-version: 3.8 - name: Pip cache - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-lint-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} @@ -46,7 +46,7 @@ jobs: with: python-version: 3.7 - name: Pip cache - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-docs-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} @@ -124,7 +124,7 @@ jobs: with: python-version: ${{ matrix.python-version }} - name: Pip cache - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ~/.cache/pip key: ${{ runner.os }}-${{ matrix.python-version}}-pip-sdist-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} @@ -199,7 +199,7 @@ jobs: with: python-version: ${{ matrix.python-version }} - name: Pip cache - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ~/.cache/pip key: ${{ runner.os }}-${{ matrix.python-version}}-pip-test-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} @@ -209,7 +209,7 @@ jobs: ${{ runner.os }}-${{ matrix.python-version}}- if: runner.os != 'Windows' - name: Pip cache - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ~\AppData\Local\pip\Cache key: ${{ runner.os }}-${{ matrix.python-version}}-pip-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} @@ -270,7 +270,7 @@ jobs: with: python-version: 3.7 - name: Pip cache - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ~\AppData\Local\pip\Cache key: ${{ runner.os }}-pip-tutorials-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} From 96224e9d7f444bfb9d8ecb9c23eb291328e79ea1 Mon Sep 17 00:00:00 2001 From: "Christopher J. Wood" Date: Fri, 2 Oct 2020 02:56:26 -0400 Subject: [PATCH 007/126] Add available memory checks for Statevector and Unitary simulators (#969) Add missing available memory checks for the StatevectorController and UnitaryController. These throw an exception if the memory required to simulate the number of qubits in a circuit exceeds the available memory of the system. --- .../validate-memory-statevector-d1b4fc48b002856f.yaml | 8 ++++++++ src/controllers/statevector_controller.hpp | 3 +++ src/controllers/unitary_controller.hpp | 3 +++ 3 files changed, 14 insertions(+) create mode 100644 releasenotes/notes/validate-memory-statevector-d1b4fc48b002856f.yaml diff --git a/releasenotes/notes/validate-memory-statevector-d1b4fc48b002856f.yaml b/releasenotes/notes/validate-memory-statevector-d1b4fc48b002856f.yaml new file mode 100644 index 0000000000..e4d80eaeb9 --- /dev/null +++ b/releasenotes/notes/validate-memory-statevector-d1b4fc48b002856f.yaml @@ -0,0 +1,8 @@ +--- +fixes: + - | + Add missing available memory checks for the + :class:`~qiskit.providers.aer.StatevectorSimulator` and + :class:`~qiskit.providers.aer.UnitarySimulator`. This throws an exception if + the memory required to simulate the number of qubits in a circuit exceeds the + available memory of the system. diff --git a/src/controllers/statevector_controller.hpp b/src/controllers/statevector_controller.hpp index 1632f4e67d..d4bdc0ab6f 100755 --- a/src/controllers/statevector_controller.hpp +++ b/src/controllers/statevector_controller.hpp @@ -280,6 +280,9 @@ void StatevectorController::run_circuit_helper( // Validate circuit and throw exception if invalid operations exist validate_state(state, circ, noise, true); + // Validate memory requirements and throw exception if not enough memory + validate_memory_requirements(state, circ, true); + // Check for custom initial state, and if so check it matches num qubits if (!initial_state_.empty()) { if (initial_state_.size() != 1ULL << circ.num_qubits) { diff --git a/src/controllers/unitary_controller.hpp b/src/controllers/unitary_controller.hpp index 74f143a71e..a38f06e4db 100755 --- a/src/controllers/unitary_controller.hpp +++ b/src/controllers/unitary_controller.hpp @@ -261,6 +261,9 @@ void UnitaryController::run_circuit_helper( // Validate circuit and throw exception if invalid operations exist validate_state(state, circ, noise, true); + // Validate memory requirements and throw exception if not enough memory + validate_memory_requirements(state, circ, true); + // Check for custom initial state, and if so check it matches num qubits if (!initial_unitary_.empty()) { auto nrows = initial_unitary_.GetRows(); From 77e40c8d99fd0490d85285e96f87e4905017b646 Mon Sep 17 00:00:00 2001 From: "Christopher J. Wood" Date: Fri, 2 Oct 2020 16:17:33 -0400 Subject: [PATCH 008/126] Move AVX2 logic into Transformer class and enable SIMD on Unitary, DensityMatrix, SuperOp (#961) Co-authored-by: Victor Villar <59838221+vvilpas@users.noreply.github.com> --- .../notes/simd-support-c2352ca3d639770f.yaml | 9 + src/controllers/qasm_controller.hpp | 17 - src/controllers/statevector_controller.hpp | 10 - src/simulators/statevector/indexes.hpp | 12 +- src/simulators/statevector/qubitvector.hpp | 554 +++++------------- .../statevector/qubitvector_avx2.hpp | 156 ----- .../statevector/statevector_state.hpp | 2 +- src/simulators/statevector/transformer.hpp | 378 ++++++++++++ .../statevector/transformer_avx2.hpp | 79 +++ 9 files changed, 614 insertions(+), 603 deletions(-) create mode 100644 releasenotes/notes/simd-support-c2352ca3d639770f.yaml delete mode 100755 src/simulators/statevector/qubitvector_avx2.hpp create mode 100755 src/simulators/statevector/transformer.hpp create mode 100755 src/simulators/statevector/transformer_avx2.hpp diff --git a/releasenotes/notes/simd-support-c2352ca3d639770f.yaml b/releasenotes/notes/simd-support-c2352ca3d639770f.yaml new file mode 100644 index 0000000000..b0cd4938f6 --- /dev/null +++ b/releasenotes/notes/simd-support-c2352ca3d639770f.yaml @@ -0,0 +1,9 @@ +--- +features: + - | + Extends the SIMD vectorization of the statevector simulation method to the + unitary matrix, superoperator matrix, and density matrix simulation methods. + This gives roughtly a 2x performance increase general simulation using the + :class:`~qiskit.providers.aer.UnitarySimulator`, the ``"density_matrix"`` + method of the :class:`~qiskit.providers.aer.QasmSimulator`, gate + fusion, and noise simulation. diff --git a/src/controllers/qasm_controller.hpp b/src/controllers/qasm_controller.hpp index 2ff6ff719e..a9669ab14b 100755 --- a/src/controllers/qasm_controller.hpp +++ b/src/controllers/qasm_controller.hpp @@ -16,13 +16,11 @@ #define _aer_qasm_controller_hpp_ #include "controller.hpp" -#include "framework/avx2_detect.hpp" #include "simulators/density_matrix/densitymatrix_state.hpp" #include "simulators/extended_stabilizer/extended_stabilizer_state.hpp" #include "simulators/matrix_product_state/matrix_product_state.hpp" #include "simulators/stabilizer/stabilizer_state.hpp" #include "simulators/statevector/qubitvector.hpp" -#include "simulators/statevector/qubitvector_avx2.hpp" #include "simulators/statevector/statevector_state.hpp" #include "simulators/superoperator/superoperator_state.hpp" #include "transpile/delay_measure.hpp" @@ -395,27 +393,12 @@ void QasmController::run_circuit(const Circuit& circ, // Validate circuit for simulation method switch (simulation_method(circ, noise, true)) { case Method::statevector: { - bool avx2_enabled = is_avx2_supported(); - if (simulation_precision_ == Precision::double_precision) { - if (avx2_enabled) { - return run_circuit_helper< - Statevector::State>>( - circ, noise, config, shots, rng_seed, initial_statevector_, - Method::statevector, data); - } // Double-precision Statevector simulation return run_circuit_helper>>( circ, noise, config, shots, rng_seed, initial_statevector_, Method::statevector, data); } else { - if (avx2_enabled) { - // Single-precision Statevector simulation - return run_circuit_helper< - Statevector::State>>( - circ, noise, config, shots, rng_seed, initial_statevector_, - Method::statevector, data); - } // Single-precision Statevector simulation return run_circuit_helper>>( circ, noise, config, shots, rng_seed, initial_statevector_, diff --git a/src/controllers/statevector_controller.hpp b/src/controllers/statevector_controller.hpp index d4bdc0ab6f..f98a185810 100755 --- a/src/controllers/statevector_controller.hpp +++ b/src/controllers/statevector_controller.hpp @@ -17,7 +17,6 @@ #include "controller.hpp" #include "simulators/statevector/statevector_state.hpp" -#include "simulators/statevector/qubitvector_avx2.hpp" #include "transpile/fusion.hpp" namespace AER { @@ -205,21 +204,12 @@ void StatevectorController::run_circuit( switch (method_) { case Method::automatic: case Method::statevector_cpu: { - bool avx2_enabled = is_avx2_supported(); if (precision_ == Precision::double_precision) { - if(avx2_enabled){ - return run_circuit_helper>>( - circ, noise, config, shots, rng_seed, data); - } // Double-precision Statevector simulation return run_circuit_helper>>( circ, noise, config, shots, rng_seed, data); } else { // Single-precision Statevector simulation - if(avx2_enabled){ - return run_circuit_helper>>( - circ, noise, config, shots, rng_seed, data); - } return run_circuit_helper>>( circ, noise, config, shots, rng_seed, data); } diff --git a/src/simulators/statevector/indexes.hpp b/src/simulators/statevector/indexes.hpp index db675e0751..0df6a69ce9 100644 --- a/src/simulators/statevector/indexes.hpp +++ b/src/simulators/statevector/indexes.hpp @@ -177,7 +177,7 @@ inline void apply_lambda(const size_t start, const uint_t omp_threads, Lambda&& func) { -#pragma omp parallel if (omp_threads > 0) num_threads(omp_threads) +#pragma omp parallel if (omp_threads > 1) num_threads(omp_threads) { #pragma omp for for (int_t k = int_t(start); k < int_t(stop); k++) { @@ -197,7 +197,7 @@ inline void apply_lambda(const size_t start, const int_t END = stop >> NUM_QUBITS; auto qubits_sorted = qubits; std::sort(qubits_sorted.begin(), qubits_sorted.end()); -#pragma omp parallel if (omp_threads > 0) num_threads(omp_threads) +#pragma omp parallel if (omp_threads > 1) num_threads(omp_threads) { #pragma omp for for (int_t k = int_t(start); k < END; k++) { @@ -222,7 +222,7 @@ inline void apply_lambda(const size_t start, auto qubits_sorted = qubits; std::sort(qubits_sorted.begin(), qubits_sorted.end()); -#pragma omp parallel if (omp_threads > 0) num_threads(omp_threads) +#pragma omp parallel if (omp_threads > 1) num_threads(omp_threads) { #pragma omp for for (int_t k = int_t(start); k < END; k+=gap) { @@ -254,7 +254,7 @@ inline std::complex apply_reduction_lambda(const size_t start, // Reduction variables double val_re = 0.; double val_im = 0.; -#pragma omp parallel reduction(+:val_re, val_im) if (omp_threads > 0) num_threads(omp_threads) +#pragma omp parallel reduction(+:val_re, val_im) if (omp_threads > 1) num_threads(omp_threads) { #pragma omp for for (int_t k = int_t(start); k < int_t(stop); k++) { @@ -279,7 +279,7 @@ std::complex apply_reduction_lambda(const size_t start, // Reduction variables double val_re = 0.; double val_im = 0.; -#pragma omp parallel reduction(+:val_re, val_im) if (omp_threads > 0) num_threads(omp_threads) +#pragma omp parallel reduction(+:val_re, val_im) if (omp_threads > 1) num_threads(omp_threads) { #pragma omp for for (int_t k = int_t(start); k < END; k++) { @@ -308,7 +308,7 @@ std::complex apply_reduction_lambda(const size_t start, // Reduction variables double val_re = 0.; double val_im = 0.; -#pragma omp parallel reduction(+:val_re, val_im) if (omp_threads > 0) num_threads(omp_threads) +#pragma omp parallel reduction(+:val_re, val_im) if (omp_threads > 1) num_threads(omp_threads) { #pragma omp for for (int_t k = int_t(start); k < END; k++) { diff --git a/src/simulators/statevector/qubitvector.hpp b/src/simulators/statevector/qubitvector.hpp index 7202ba0935..2e9223807e 100755 --- a/src/simulators/statevector/qubitvector.hpp +++ b/src/simulators/statevector/qubitvector.hpp @@ -29,13 +29,15 @@ #include #include "simulators/statevector/indexes.hpp" +#include "simulators/statevector/transformer.hpp" +#include "simulators/statevector/transformer_avx2.hpp" +#include "framework/avx2_detect.hpp" #include "framework/json.hpp" #include "framework/utils.hpp" #include "framework/linalg/vector.hpp" namespace AER { namespace QV { - template using cvector_t = std::vector>; //============================================================================ @@ -51,8 +53,9 @@ template using cvector_t = std::vector>; // If the template argument does not have these methods then template // specialization must be used to override the default implementations. -template +template class QubitVector { + std::unique_ptr*, data_t>> transformer_; public: @@ -157,10 +160,6 @@ class QubitVector { // Apply Matrices //----------------------------------------------------------------------- - // Apply a 1-qubit matrix to the state vector. - // The matrix is input as vector of the column-major vectorized 1-qubit matrix. - void apply_matrix(const uint_t qubit, const cvector_t &mat); - // Apply a N-qubit matrix to the state vector. // The matrix is input as vector of the column-major vectorized N-qubit matrix. void apply_matrix(const reg_t &qubits, const cvector_t &mat); @@ -169,10 +168,6 @@ class QubitVector { // The matrix is input as vector of the column-major vectorized N-qubit matrix. void apply_multiplexer(const reg_t &control_qubits, const reg_t &target_qubits, const cvector_t &mat); - // Apply a 1-qubit diagonal matrix to the state vector. - // The matrix is input as vector of the matrix diagonal. - void apply_diagonal_matrix(const uint_t qubit, const cvector_t &mat); - // Apply a N-qubit diagonal matrix to the state vector. // The matrix is input as vector of the matrix diagonal. void apply_diagonal_matrix(const reg_t &qubits, const cvector_t &mat); @@ -337,9 +332,16 @@ class QubitVector { int sample_measure_index_size_ = 10; // Sample measure indexing qubit size double json_chop_threshold_ = 0; // Threshold for choping small values // in JSON serialization - inline uint_t omp_threads_managed() const { return (num_qubits_ > omp_threshold_ && omp_threads_ > 1) ? omp_threads_: 0; } + inline uint_t omp_threads_managed() const { + return (num_qubits_ > omp_threshold_ && omp_threads_ > 1) ? omp_threads_: 1; + } - //----------------------------------------------------------------------- + void set_transformer_method(){ + transformer_ = is_avx2_supported() ? std::make_unique*, data_t>>() + : std::make_unique*, data_t>>(); + } + + //----------------------------------------------------------------------- // Error Messages //----------------------------------------------------------------------- @@ -480,13 +482,13 @@ class QubitVector { // JSON Serialization //------------------------------------------------------------------------------ -template +template inline void to_json(json_t &js, const QubitVector &qv) { js = qv.json(); } -template -json_t QubitVector::json() const { +template +json_t QubitVector::json() const { const int_t END = data_size_; const json_t ZERO = std::complex(0.0, 0.0); json_t js = json_t(data_size_, ZERO); @@ -513,8 +515,8 @@ json_t QubitVector::json() const { // Error Handling //------------------------------------------------------------------------------ -template -void QubitVector::check_qubit(const uint_t qubit) const { +template +void QubitVector::check_qubit(const uint_t qubit) const { if (qubit + 1 > num_qubits_) { std::string error = "QubitVector: qubit index " + std::to_string(qubit) + " > " + std::to_string(num_qubits_); @@ -522,8 +524,8 @@ void QubitVector::check_qubit(const uint_t qubit) const { } } -template -void QubitVector::check_matrix(const cvector_t &vec, uint_t nqubits) const { +template +void QubitVector::check_matrix(const cvector_t &vec, uint_t nqubits) const { const size_t DIM = BITS[nqubits]; const auto SIZE = vec.size(); if (SIZE != DIM * DIM) { @@ -533,8 +535,8 @@ void QubitVector::check_matrix(const cvector_t &vec, ui } } -template -void QubitVector::check_vector(const cvector_t &vec, uint_t nqubits) const { +template +void QubitVector::check_vector(const cvector_t &vec, uint_t nqubits) const { const size_t DIM = BITS[nqubits]; const auto SIZE = vec.size(); if (SIZE != DIM) { @@ -544,8 +546,8 @@ void QubitVector::check_vector(const cvector_t &vec, ui } } -template -void QubitVector::check_dimension(const QubitVector &qv) const { +template +void QubitVector::check_dimension(const QubitVector &qv) const { if (data_size_ != qv.size_) { std::string error = "QubitVector: vectors are different shape " + std::to_string(data_size_) + " != " + @@ -554,8 +556,8 @@ void QubitVector::check_dimension(const QubitVector &qv) const } } -template -void QubitVector::check_checkpoint() const { +template +void QubitVector::check_checkpoint() const { if (!checkpoint_) { throw std::runtime_error("QubitVector: checkpoint must exist for inner_product() or revert()"); } @@ -565,16 +567,18 @@ void QubitVector::check_checkpoint() const { // Constructors & Destructor //------------------------------------------------------------------------------ -template -QubitVector::QubitVector(size_t num_qubits) : num_qubits_(0), data_(nullptr), checkpoint_(0){ - set_num_qubits(num_qubits); -} +template +QubitVector::QubitVector(size_t num_qubits) + : num_qubits_(0), data_(nullptr), checkpoint_(0) { + set_num_qubits(num_qubits); + set_transformer_method(); + } -template -QubitVector::QubitVector() : QubitVector(0) {} +template +QubitVector::QubitVector() : QubitVector(0) {} -template -QubitVector::~QubitVector() { +template +QubitVector::~QubitVector() { free_mem(); free_checkpoint(); } @@ -583,8 +587,8 @@ QubitVector::~QubitVector() { // Element access operators //------------------------------------------------------------------------------ -template -std::complex &QubitVector::operator[](uint_t element) { +template +std::complex &QubitVector::operator[](uint_t element) { // Error checking #ifdef DEBUG if (element > data_size_) { @@ -596,8 +600,8 @@ std::complex &QubitVector::operator[](uint_t element) { return data_[element]; } -template -std::complex QubitVector::operator[](uint_t element) const { +template +std::complex QubitVector::operator[](uint_t element) const { // Error checking #ifdef DEBUG if (element > data_size_) { @@ -609,8 +613,8 @@ std::complex QubitVector::operator[](uint_t element) co return data_[element]; } -template -cvector_t QubitVector::vector() const { +template +cvector_t QubitVector::vector() const { cvector_t ret(data_size_, 0.); const int_t END = data_size_; #pragma omp parallel for if (num_qubits_ > omp_threshold_ && omp_threads_ > 1) num_threads(omp_threads_) @@ -620,13 +624,13 @@ cvector_t QubitVector::vector() const { return ret; } -template -AER::Vector> QubitVector::copy_to_vector() const { +template +AER::Vector> QubitVector::copy_to_vector() const { return AER::Vector>::copy_from_buffer(data_size_, data_); } -template -AER::Vector> QubitVector::move_to_vector() { +template +AER::Vector> QubitVector::move_to_vector() { const auto vec = AER::Vector>::move_from_buffer(data_size_, data_); data_ = nullptr; return vec; @@ -635,8 +639,8 @@ AER::Vector> QubitVector::move_to_vector() //------------------------------------------------------------------------------ // State initialize component //------------------------------------------------------------------------------ -template -void QubitVector::initialize_component(const reg_t &qubits, const cvector_t &state0) { +template +void QubitVector::initialize_component(const reg_t &qubits, const cvector_t &state0) { cvector_t state = convert(state0); @@ -656,8 +660,8 @@ void QubitVector::initialize_component(const reg_t &qubits, con // Utility //------------------------------------------------------------------------------ -template -void QubitVector::zero() { +template +void QubitVector::zero() { const int_t END = data_size_; // end for k loop #pragma omp parallel for if (num_qubits_ > omp_threshold_ && omp_threads_ > 1) num_threads(omp_threads_) @@ -666,8 +670,8 @@ void QubitVector::zero() { } } -template -cvector_t QubitVector::convert(const cvector_t& v) const { +template +cvector_t QubitVector::convert(const cvector_t& v) const { cvector_t ret(v.size()); for (size_t i = 0; i < v.size(); ++i) ret[i] = v[i]; @@ -675,8 +679,8 @@ cvector_t QubitVector::convert(const cvector_t& } -template -void QubitVector::set_num_qubits(size_t num_qubits) { +template +void QubitVector::set_num_qubits(size_t num_qubits) { free_checkpoint(); if(num_qubits != num_qubits_){ @@ -688,8 +692,8 @@ void QubitVector::set_num_qubits(size_t num_qubits) { num_qubits_ = num_qubits; } -template -void QubitVector::free_mem(){ +template +void QubitVector::free_mem(){ if (data_) { free(data_); data_ = nullptr; @@ -697,16 +701,16 @@ void QubitVector::free_mem(){ } -template -void QubitVector::free_checkpoint(){ +template +void QubitVector::free_checkpoint(){ if (checkpoint_) { free(checkpoint_); checkpoint_ = nullptr; } } -template -void QubitVector::allocate_mem(size_t data_size){ +template +void QubitVector::allocate_mem(size_t data_size){ // Free any currently assigned memory free_mem(); // Allocate memory for new vector @@ -721,8 +725,8 @@ void QubitVector::allocate_mem(size_t data_size){ } } -template -void QubitVector::allocate_checkpoint(size_t data_size){ +template +void QubitVector::allocate_checkpoint(size_t data_size){ free_checkpoint(); #if !defined(_WIN64) && !defined(_WIN32) void* data; @@ -734,8 +738,8 @@ void QubitVector::allocate_checkpoint(size_t data_size){ } -template -size_t QubitVector::required_memory_mb(uint_t num_qubits) const { +template +size_t QubitVector::required_memory_mb(uint_t num_qubits) const { size_t unit = std::log2(sizeof(std::complex)); size_t shift_mb = std::max(0, num_qubits + unit - 20); @@ -744,8 +748,8 @@ size_t QubitVector::required_memory_mb(uint_t num_qubits) const } -template -void QubitVector::checkpoint() { +template +void QubitVector::checkpoint() { allocate_checkpoint(data_size_); const int_t END = data_size_; // end for k loop @@ -755,8 +759,8 @@ void QubitVector::checkpoint() { } -template -void QubitVector::revert(bool keep) { +template +void QubitVector::revert(bool keep) { #ifdef DEBUG check_checkpoint(); @@ -778,8 +782,8 @@ void QubitVector::revert(bool keep) { } -template -std::complex QubitVector::inner_product() const { +template +std::complex QubitVector::inner_product() const { #ifdef DEBUG check_checkpoint(); @@ -793,18 +797,19 @@ std::complex QubitVector::inner_product() const { return apply_reduction_lambda(lambda); } + //------------------------------------------------------------------------------ // Initialization //------------------------------------------------------------------------------ -template -void QubitVector::initialize() { +template +void QubitVector::initialize() { zero(); data_[0] = 1.; } -template -void QubitVector::initialize_from_vector(const cvector_t &statevec) { +template +void QubitVector::initialize_from_vector(const cvector_t &statevec) { if (data_size_ != statevec.size()) { std::string error = "QubitVector::initialize input vector is incorrect length (" + std::to_string(data_size_) + "!=" + @@ -819,8 +824,8 @@ void QubitVector::initialize_from_vector(const cvector_t -void QubitVector::initialize_from_data(const std::complex* statevec, const size_t num_states) { +template +void QubitVector::initialize_from_data(const std::complex* statevec, const size_t num_states) { if (data_size_ != num_states) { std::string error = "QubitVector::initialize input vector is incorrect length (" + std::to_string(data_size_) + "!=" + std::to_string(num_states) + ")"; @@ -841,20 +846,20 @@ void QubitVector::initialize_from_data(const std::complex -void QubitVector::set_omp_threads(int n) { +template +void QubitVector::set_omp_threads(int n) { if (n > 0) omp_threads_ = n; } -template -void QubitVector::set_omp_threshold(int n) { +template +void QubitVector::set_omp_threshold(int n) { if (n > 0) omp_threshold_ = n; } -template -void QubitVector::set_json_chop_threshold(double threshold) { +template +void QubitVector::set_json_chop_threshold(double threshold) { json_chop_threshold_ = threshold; } @@ -869,15 +874,15 @@ void QubitVector::set_json_chop_threshold(double threshold) { // State update //------------------------------------------------------------------------------ -template +template template -void QubitVector::apply_lambda(Lambda&& func) { +void QubitVector::apply_lambda(Lambda&& func) { QV::apply_lambda(0, data_size_, omp_threads_managed(), func); } -template +template template -void QubitVector::apply_lambda(Lambda&& func, const list_t &qubits) { +void QubitVector::apply_lambda(Lambda&& func, const list_t &qubits) { // Error checking #ifdef DEBUG @@ -888,9 +893,9 @@ void QubitVector::apply_lambda(Lambda&& func, const list_t &qub QV::apply_lambda(0, data_size_, omp_threads_managed(), func, qubits); } -template +template template -void QubitVector::apply_lambda(Lambda&& func, +void QubitVector::apply_lambda(Lambda&& func, const list_t &qubits, const param_t ¶ms) { @@ -908,23 +913,23 @@ void QubitVector::apply_lambda(Lambda&& func, // Reduction Lambda //------------------------------------------------------------------------------ -template +template template std::complex -QubitVector::apply_reduction_lambda(Lambda &&func, size_t start, size_t stop) const { +QubitVector::apply_reduction_lambda(Lambda &&func, size_t start, size_t stop) const { return QV::apply_reduction_lambda(start, stop, omp_threads_managed(), func); } -template +template template -std::complex QubitVector::apply_reduction_lambda(Lambda &&func) const { +std::complex QubitVector::apply_reduction_lambda(Lambda &&func) const { return apply_reduction_lambda(std::move(func), size_t(0), data_size_); } -template +template template std::complex -QubitVector::apply_reduction_lambda(Lambda&& func, +QubitVector::apply_reduction_lambda(Lambda&& func, const list_t &qubits) const { // Error checking @@ -937,10 +942,10 @@ QubitVector::apply_reduction_lambda(Lambda&& func, } -template +template template std::complex -QubitVector::apply_reduction_lambda(Lambda&& func, +QubitVector::apply_reduction_lambda(Lambda&& func, const list_t &qubits, const param_t ¶ms) const { @@ -959,95 +964,14 @@ QubitVector::apply_reduction_lambda(Lambda&& func, * MATRIX MULTIPLICATION * ******************************************************************************/ -template -void QubitVector::apply_matrix(const reg_t &qubits, +template +void QubitVector::apply_matrix(const reg_t &qubits, const cvector_t &mat) { - - const size_t N = qubits.size(); - // Error checking - #ifdef DEBUG - check_vector(mat, 2 * N); - #endif - - // Static array optimized lambda functions - switch (N) { - case 1: - apply_matrix(qubits[0], mat); - return; - case 2: { - // Lambda function for 2-qubit matrix multiplication - auto lambda = [&](const areg_t<4> &inds, const cvector_t &_mat)->void { - std::array, 4> cache; - for (size_t i = 0; i < 4; i++) { - const auto ii = inds[i]; - cache[i] = data_[ii]; - data_[ii] = 0.; - } - // update state vector - for (size_t i = 0; i < 4; i++) - for (size_t j = 0; j < 4; j++) - data_[inds[i]] += _mat[i + 4 * j] * cache[j]; - }; - apply_lambda(lambda, areg_t<2>({{qubits[0], qubits[1]}}), convert(mat)); - return; - } - case 3: { - // Lambda function for 3-qubit matrix multiplication - auto lambda = [&](const areg_t<8> &inds, const cvector_t &_mat)->void { - std::array, 8> cache; - for (size_t i = 0; i < 8; i++) { - const auto ii = inds[i]; - cache[i] = data_[ii]; - data_[ii] = 0.; - } - // update state vector - for (size_t i = 0; i < 8; i++) { - for (size_t j = 0; j < 8; j++) - data_[inds[i]] += _mat[i + 8 * j] * cache[j]; - } - }; - apply_lambda(lambda, areg_t<3>({{qubits[0], qubits[1], qubits[2]}}), convert(mat)); - return; - } - case 4: { - // Lambda function for 4-qubit matrix multiplication - auto lambda = [&](const areg_t<16> &inds, const cvector_t &_mat)->void { - std::array, 16> cache; - for (size_t i = 0; i < 16; i++) { - const auto ii = inds[i]; - cache[i] = data_[ii]; - data_[ii] = 0.; - } - // update state vector - for (size_t i = 0; i < 16; i++) - for (size_t j = 0; j < 16; j++) - data_[inds[i]] += _mat[i + 16 * j] * cache[j]; - }; - apply_lambda(lambda, areg_t<4>({{qubits[0], qubits[1], qubits[2], qubits[3]}}), convert(mat)); - return; - } - default: { - // Lambda function for N-qubit matrix multiplication - auto lambda = [&](const indexes_t &inds, const cvector_t &_mat)->void { - const uint_t DIM = BITS[N]; - auto cache = std::make_unique[]>(DIM); - for (size_t i = 0; i < DIM; i++) { - const auto ii = inds[i]; - cache[i] = data_[ii]; - data_[ii] = 0.; - } - // update state vector - for (size_t i = 0; i < DIM; i++) - for (size_t j = 0; j < DIM; j++) - data_[inds[i]] += _mat[i + DIM * j] * cache[j]; - }; - apply_lambda(lambda, qubits, convert(mat)); - } - } // end switch + transformer_->apply_matrix(data_, data_size_, omp_threads_managed(), qubits, mat); } -template -void QubitVector::apply_multiplexer(const reg_t &control_qubits, +template +void QubitVector::apply_multiplexer(const reg_t &control_qubits, const reg_t &target_qubits, const cvector_t &mat) { @@ -1080,36 +1004,14 @@ void QubitVector::apply_multiplexer(const reg_t &control_qubits apply_lambda(lambda, qubits, convert(mat)); } -template -void QubitVector::apply_diagonal_matrix(const reg_t &qubits, +template +void QubitVector::apply_diagonal_matrix(const reg_t &qubits, const cvector_t &diag) { - - // Error checking - #ifdef DEBUG - check_vector(diag, qubits.size()); - #endif - - if (qubits.size() == 1) { - apply_diagonal_matrix(qubits[0], diag); - return; - } - - auto lambda = [&](const areg_t<2> &inds, const cvector_t &_diag)->void { - for (int_t i = 0; i < 2; ++i) { - const int_t k = inds[i]; - int_t iv = 0; - for (int_t j = 0; j < qubits.size(); j++) - if ((k & (1ULL << qubits[j])) != 0) - iv += (1ULL << j); - if (_diag[iv] != (data_t) 1.0) - data_[k] *= _diag[iv]; - } - }; - apply_lambda(lambda, areg_t<1>({{qubits[0]}}), convert(diag)); + transformer_->apply_diagonal_matrix(data_, data_size_, omp_threads_managed(), qubits, diag); } -template -void QubitVector::apply_permutation_matrix(const reg_t& qubits, +template +void QubitVector::apply_permutation_matrix(const reg_t& qubits, const std::vector> &pairs) { const size_t N = qubits.size(); @@ -1205,8 +1107,8 @@ void QubitVector::apply_permutation_matrix(const reg_t& qubits, // Multi-controlled gates //------------------------------------------------------------------------------ -template -void QubitVector::apply_mcx(const reg_t &qubits) { +template +void QubitVector::apply_mcx(const reg_t &qubits) { // Calculate the permutation positions for the last qubit. const size_t N = qubits.size(); const size_t pos0 = MASKS[N - 1]; @@ -1247,8 +1149,8 @@ void QubitVector::apply_mcx(const reg_t &qubits) { } // end switch } -template -void QubitVector::apply_mcy(const reg_t &qubits) { +template +void QubitVector::apply_mcy(const reg_t &qubits) { // Calculate the permutation positions for the last qubit. const size_t N = qubits.size(); const size_t pos0 = MASKS[N - 1]; @@ -1298,8 +1200,8 @@ void QubitVector::apply_mcy(const reg_t &qubits) { } // end switch } -template -void QubitVector::apply_mcswap(const reg_t &qubits) { +template +void QubitVector::apply_mcswap(const reg_t &qubits) { // Calculate the swap positions for the last two qubits. // If N = 2 this is just a regular SWAP gate rather than a controlled-SWAP gate. const size_t N = qubits.size(); @@ -1333,8 +1235,8 @@ void QubitVector::apply_mcswap(const reg_t &qubits) { } // end switch } -template -void QubitVector::apply_mcphase(const reg_t &qubits, const std::complex phase) { +template +void QubitVector::apply_mcphase(const reg_t &qubits, const std::complex phase) { const size_t N = qubits.size(); switch (N) { case 1: { @@ -1371,8 +1273,8 @@ void QubitVector::apply_mcphase(const reg_t &qubits, const std: } // end switch } -template -void QubitVector::apply_mcu(const reg_t &qubits, +template +void QubitVector::apply_mcu(const reg_t &qubits, const cvector_t &mat) { // Calculate the permutation positions for the last qubit. @@ -1395,7 +1297,7 @@ void QubitVector::apply_mcu(const reg_t &qubits, switch (N) { case 1: { // If N=1 this is just a single-qubit matrix - apply_diagonal_matrix(qubits[0], diag); + apply_diagonal_matrix(qubits, diag); return; } case 2: { @@ -1435,7 +1337,7 @@ void QubitVector::apply_mcu(const reg_t &qubits, switch (N) { case 1: { // If N=1 this is just a single-qubit matrix - apply_matrix(qubits[0], mat); + apply_matrix(qubits, mat); return; } case 2: { @@ -1474,187 +1376,13 @@ void QubitVector::apply_mcu(const reg_t &qubits, } // end switch } -//------------------------------------------------------------------------------ -// Single-qubit matrices -//------------------------------------------------------------------------------ - -template -void QubitVector::apply_matrix(const uint_t qubit, - const cvector_t& mat) { - - // Check if matrix is diagonal and if so use optimized lambda - if (mat[1] == 0.0 && mat[2] == 0.0) { - const cvector_t diag = {{mat[0], mat[3]}}; - apply_diagonal_matrix(qubit, diag); - return; - } - - // Convert qubit to array register for lambda functions - areg_t<1> qubits = {{qubit}}; - - // Check if anti-diagonal matrix and if so use optimized lambda - if(mat[0] == 0.0 && mat[3] == 0.0) { - if (mat[1] == 1.0 && mat[2] == 1.0) { - // X-matrix - auto lambda = [&](const areg_t<2> &inds)->void { - std::swap(data_[inds[0]], data_[inds[1]]); - }; - apply_lambda(lambda, qubits); - return; - } - if (mat[2] == 0.0) { - // Non-unitary projector - // possibly used in measure/reset/kraus update - auto lambda = [&](const areg_t<2> &inds, - const cvector_t &_mat)->void { - data_[inds[1]] = _mat[1] * data_[inds[0]]; - data_[inds[0]] = 0.0; - }; - apply_lambda(lambda, qubits, convert(mat)); - return; - } - if (mat[1] == 0.0) { - // Non-unitary projector - // possibly used in measure/reset/kraus update - auto lambda = [&](const areg_t<2> &inds, - const cvector_t &_mat)->void { - data_[inds[0]] = _mat[2] * data_[inds[1]]; - data_[inds[1]] = 0.0; - }; - apply_lambda(lambda, qubits, convert(mat)); - return; - } - // else we have a general anti-diagonal matrix - auto lambda = [&](const areg_t<2> &inds, - const cvector_t &_mat)->void { - const std::complex cache = data_[inds[0]]; - data_[inds[0]] = _mat[2] * data_[inds[1]]; - data_[inds[1]] = _mat[1] * cache; - }; - apply_lambda(lambda, qubits, convert(mat)); - return; - } - // Otherwise general single-qubit matrix multiplication - auto lambda = [&](const areg_t<2> &inds, const cvector_t &_mat)->void { - const auto cache = data_[inds[0]]; - data_[inds[0]] = _mat[0] * cache + _mat[2] * data_[inds[1]]; - data_[inds[1]] = _mat[1] * cache + _mat[3] * data_[inds[1]]; - }; - apply_lambda(lambda, qubits, convert(mat)); -} - -template -void QubitVector::apply_diagonal_matrix(const uint_t qubit, - const cvector_t& diag) { - - // TODO: This should be changed so it isn't checking doubles with == - if (diag[0] == 1.0) { // [[1, 0], [0, z]] matrix - if (diag[1] == 1.0) - return; // Identity - - if (diag[1] == std::complex(0., -1.)) { // [[1, 0], [0, -i]] - auto lambda = [&](const areg_t<2> &inds, - const cvector_t &_mat)->void { - const auto k = inds[1]; - double cache = data_[k].imag(); - data_[k].imag(data_[k].real() * -1.); - data_[k].real(cache); - }; - apply_lambda(lambda, areg_t<1>({{qubit}}), convert(diag)); - return; - } - if (diag[1] == std::complex(0., 1.)) { - // [[1, 0], [0, i]] - auto lambda = [&](const areg_t<2> &inds, - const cvector_t &_mat)->void { - const auto k = inds[1]; - double cache = data_[k].imag(); - data_[k].imag(data_[k].real()); - data_[k].real(cache * -1.); - }; - apply_lambda(lambda, areg_t<1>({{qubit}}), convert(diag)); - return; - } - if (diag[0] == 0.0) { - // [[1, 0], [0, 0]] - auto lambda = [&](const areg_t<2> &inds, - const cvector_t &_mat)->void { - data_[inds[1]] = 0.0; - }; - apply_lambda(lambda, areg_t<1>({{qubit}}), convert(diag)); - return; - } - // general [[1, 0], [0, z]] - auto lambda = [&](const areg_t<2> &inds, - const cvector_t &_mat)->void { - const auto k = inds[1]; - data_[k] *= _mat[1]; - }; - apply_lambda(lambda, areg_t<1>({{qubit}}), convert(diag)); - return; - } else if (diag[1] == 1.0) { - // [[z, 0], [0, 1]] matrix - if (diag[0] == std::complex(0., -1.)) { - // [[-i, 0], [0, 1]] - auto lambda = [&](const areg_t<2> &inds, - const cvector_t &_mat)->void { - const auto k = inds[1]; - double cache = data_[k].imag(); - data_[k].imag(data_[k].real() * -1.); - data_[k].real(cache); - }; - apply_lambda(lambda, areg_t<1>({{qubit}}), convert(diag)); - return; - } - if (diag[0] == std::complex(0., 1.)) { - // [[i, 0], [0, 1]] - auto lambda = [&](const areg_t<2> &inds, - const cvector_t &_mat)->void { - const auto k = inds[1]; - double cache = data_[k].imag(); - data_[k].imag(data_[k].real()); - data_[k].real(cache * -1.); - }; - apply_lambda(lambda, areg_t<1>({{qubit}}), convert(diag)); - return; - } - if (diag[0] == 0.0) { - // [[0, 0], [0, 1]] - auto lambda = [&](const areg_t<2> &inds, - const cvector_t &_mat)->void { - data_[inds[0]] = 0.0; - }; - apply_lambda(lambda, areg_t<1>({{qubit}}), convert(diag)); - return; - } - // general [[z, 0], [0, 1]] - auto lambda = [&](const areg_t<2> &inds, - const cvector_t &_mat)->void { - const auto k = inds[0]; - data_[k] *= _mat[0]; - }; - apply_lambda(lambda, areg_t<1>({{qubit}}), convert(diag)); - return; - } else { - // Lambda function for diagonal matrix multiplication - auto lambda = [&](const areg_t<2> &inds, - const cvector_t &_mat)->void { - const auto k0 = inds[0]; - const auto k1 = inds[1]; - data_[k0] *= _mat[0]; - data_[k1] *= _mat[1]; - }; - apply_lambda(lambda, areg_t<1>({{qubit}}), convert(diag)); - } -} - /******************************************************************************* * * NORMS * ******************************************************************************/ -template -double QubitVector::norm() const { +template +double QubitVector::norm() const { // Lambda function for norm auto lambda = [&](int_t k, double &val_re, double &val_im)->void { (void)val_im; // unused @@ -1663,8 +1391,8 @@ double QubitVector::norm() const { return std::real(apply_reduction_lambda(lambda)); } -template -double QubitVector::norm(const reg_t &qubits, const cvector_t &mat) const { +template +double QubitVector::norm(const reg_t &qubits, const cvector_t &mat) const { // Error checking #ifdef DEBUG @@ -1739,8 +1467,8 @@ double QubitVector::norm(const reg_t &qubits, const cvector_t -double QubitVector::norm_diagonal(const reg_t &qubits, const cvector_t &mat) const { +template +double QubitVector::norm_diagonal(const reg_t &qubits, const cvector_t &mat) const { const uint_t N = qubits.size(); @@ -1812,8 +1540,8 @@ double QubitVector::norm_diagonal(const reg_t &qubits, const cv //------------------------------------------------------------------------------ // Single-qubit specialization //------------------------------------------------------------------------------ -template -double QubitVector::norm(const uint_t qubit, const cvector_t &mat) const { +template +double QubitVector::norm(const uint_t qubit, const cvector_t &mat) const { // Error handling #ifdef DEBUG check_vector(mat, 2); @@ -1838,8 +1566,8 @@ double QubitVector::norm(const uint_t qubit, const cvector_t({{qubit}}), convert(mat))); } -template -double QubitVector::norm_diagonal(const uint_t qubit, const cvector_t &mat) const { +template +double QubitVector::norm_diagonal(const uint_t qubit, const cvector_t &mat) const { // Error handling #ifdef DEBUG check_vector(mat, 1); @@ -1863,13 +1591,13 @@ double QubitVector::norm_diagonal(const uint_t qubit, const cve * Probabilities * ******************************************************************************/ -template -double QubitVector::probability(const uint_t outcome) const { +template +double QubitVector::probability(const uint_t outcome) const { return std::real(data_[outcome] * std::conj(data_[outcome])); } -template -std::vector QubitVector::probabilities() const { +template +std::vector QubitVector::probabilities() const { const int_t END = 1LL << num_qubits(); std::vector probs(END, 0.); #pragma omp parallel for if (num_qubits_ > omp_threshold_ && omp_threads_ > 1) num_threads(omp_threads_) @@ -1879,8 +1607,8 @@ std::vector QubitVector::probabilities() const { return probs; } -template -std::vector QubitVector::probabilities(const reg_t &qubits) const { +template +std::vector QubitVector::probabilities(const reg_t &qubits) const { const size_t N = qubits.size(); const int_t DIM = BITS[N]; @@ -1919,8 +1647,8 @@ std::vector QubitVector::probabilities(const reg_t &qub //------------------------------------------------------------------------------ // Sample measure outcomes //------------------------------------------------------------------------------ -template -reg_t QubitVector::sample_measure(const std::vector &rnds) const { +template +reg_t QubitVector::sample_measure(const std::vector &rnds) const { const int_t END = 1LL << num_qubits(); const int_t SHOTS = rnds.size(); @@ -2003,8 +1731,8 @@ reg_t QubitVector::sample_measure(const std::vector &rn * ******************************************************************************/ -template -double QubitVector::expval_pauli(const reg_t &qubits, +template +double QubitVector::expval_pauli(const reg_t &qubits, const std::string &pauli) const { // Break string up into Z and X // With Y being both Z and X (plus a phase) @@ -2105,7 +1833,7 @@ double QubitVector::expval_pauli(const reg_t &qubits, //------------------------------------------------------------------------------ // ostream overload for templated qubitvector -template +template inline std::ostream &operator<<(std::ostream &out, const AER::QV::QubitVector&qv) { out << "["; diff --git a/src/simulators/statevector/qubitvector_avx2.hpp b/src/simulators/statevector/qubitvector_avx2.hpp deleted file mode 100755 index 06376025a0..0000000000 --- a/src/simulators/statevector/qubitvector_avx2.hpp +++ /dev/null @@ -1,156 +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. - */ - - - -#ifndef _qv_qubit_vector_avx2_hpp_ -#define _qv_qubit_vector_avx2_hpp_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "qubitvector.hpp" -#include "qv_avx2.hpp" -#include "misc/common_macros.hpp" - -namespace AER { -namespace QV { - -// Type aliases -using uint_t = uint64_t; -using int_t = int64_t; -using reg_t = std::vector; -using indexes_t = std::unique_ptr; -template using areg_t = std::array; -template using cvector_t = std::vector>; - -//============================================================================ -// QubitVectorAvx2 class -//============================================================================ - -template -class QubitVectorAvx2 : public QubitVector> { - - // We need this to access the base class members - using Base = QubitVector>; - -public: - - //----------------------------------------------------------------------- - // Constructors and Destructor - //----------------------------------------------------------------------- - - QubitVectorAvx2(); - explicit QubitVectorAvx2(size_t num_qubits); - virtual ~QubitVectorAvx2(){}; - QubitVectorAvx2(const QubitVectorAvx2& obj) = delete; - QubitVectorAvx2 &operator=(const QubitVectorAvx2& obj) = delete; - - // Apply a 1-qubit matrix to the state vector. - // The matrix is input as vector of the column-major vectorized 1-qubit matrix. - void apply_matrix(const uint_t qubit, const cvector_t &mat); - - // Apply a N-qubit matrix to the state vector. - // The matrix is input as vector of the column-major vectorized N-qubit matrix. - void apply_matrix(const reg_t &qubits, const cvector_t &mat); - - protected: - size_t calculate_num_threads(); -}; - -// We do not define this functions in case we don't use AVX2 -// so it can compile, as this class won't be used -#if defined(_MSC_VER) || defined(GNUC_AVX2) -// ostream overload for templated qubitvector -template -inline std::ostream &operator<<(std::ostream &out, const QV::QubitVectorAvx2&qv) { - - out << "["; - size_t last = qv.size() - 1; - for (size_t i = 0; i < qv.size(); ++i) { - out << qv[i]; - if (i != last) - out << ", "; - } - out << "]"; - return out; -} - - -//------------------------------------------------------------------------------ -// Constructors & Destructor -//------------------------------------------------------------------------------ -template -QubitVectorAvx2::QubitVectorAvx2(size_t num_qubits) { - Base::num_qubits_ = 0; - Base::data_ = nullptr; - Base::checkpoint_ = 0; - Base::set_num_qubits(num_qubits); -} - -template -QubitVectorAvx2::QubitVectorAvx2() : QubitVectorAvx2(0) {} - -template -void QubitVectorAvx2::apply_matrix(const uint_t qubit, - const cvector_t& mat) { - if ((mat[1] == 0.0 && mat[2] == 0.0) || (mat[0] == 0.0 && mat[3] == 0.0)) { - Base::apply_matrix(qubit, mat); - return; - } - - reg_t qubits = {qubit}; - if (apply_matrix_avx(reinterpret_cast(Base::data_), - Base::data_size_, qubits.data(), qubits.size(), - reinterpret_cast(Base::convert(mat).data()), - calculate_num_threads()) == Avx::NotApplied) { - Base::apply_matrix(qubit, mat); - } -} - -template -void QubitVectorAvx2::apply_matrix(const reg_t& qubits, - const cvector_t& mat) { - if (apply_matrix_avx(reinterpret_cast(Base::data_), - Base::data_size_, qubits.data(), qubits.size(), - reinterpret_cast(Base::convert(mat).data()), - calculate_num_threads()) == Avx::NotApplied) { - Base::apply_matrix(qubits, mat); - } -} - -template -size_t QubitVectorAvx2::calculate_num_threads() { - if (Base::num_qubits_ > Base::omp_threshold_ && Base::omp_threads_ > 1) { - return Base::omp_threads_; - } - return 1; -} -#endif - -template class AER::QV::QubitVectorAvx2; -template class AER::QV::QubitVectorAvx2; - -} -} -//------------------------------------------------------------------------------ -#endif // end module diff --git a/src/simulators/statevector/statevector_state.hpp b/src/simulators/statevector/statevector_state.hpp index 87a3c9d36f..3429c85140 100755 --- a/src/simulators/statevector/statevector_state.hpp +++ b/src/simulators/statevector/statevector_state.hpp @@ -429,7 +429,7 @@ template void State::initialize_omp() { template void State::apply_global_phase() { if (BaseState::has_global_phase_) { - BaseState::qreg_.apply_diagonal_matrix(0, {BaseState::global_phase_, BaseState::global_phase_}); + BaseState::qreg_.apply_diagonal_matrix({0}, {BaseState::global_phase_, BaseState::global_phase_}); } } diff --git a/src/simulators/statevector/transformer.hpp b/src/simulators/statevector/transformer.hpp new file mode 100755 index 0000000000..02a973aab8 --- /dev/null +++ b/src/simulators/statevector/transformer.hpp @@ -0,0 +1,378 @@ +/** + * This code is part of Qiskit. + * + * (C) Copyright IBM 2018, 2020. + * + * 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. + */ + +#ifndef _qv_transformer_ +#define _qv_transformer_ + +#include "framework/utils.hpp" +#include "simulators/statevector/indexes.hpp" + +namespace AER { +namespace QV { + +template using cvector_t = std::vector>; + +template class Transformer { + + // TODO: This class should have the indexes.hpp moved inside it + +public: + + virtual ~Transformer() {} + //----------------------------------------------------------------------- + // Apply Matrices + //----------------------------------------------------------------------- + + // Apply a N-qubit matrix to the state vector. + // The matrix is input as vector of the column-major vectorized N-qubit + // matrix. + + virtual void apply_matrix(Container &data, size_t data_size, int threads, + const reg_t &qubits, const cvector_t &mat) const; + + // Apply a N-qubit diagonal matrix to a array container + // The matrix is input as vector of the matrix diagonal. + virtual void apply_diagonal_matrix(Container &data, size_t data_size, + int threads, const reg_t &qubits, + const cvector_t &diag) const; + +protected: + // Apply a N-qubit matrix to the state vector. + // The matrix is input as vector of the column-major vectorized N-qubit + // matrix. + template + void apply_matrix_n(Container &data, size_t data_size, int threads, + const reg_t &qubits, const cvector_t &mat) const; + + // Specialized single qubit apply matrix function + void apply_matrix_1(Container &data, size_t data_size, int threads, + const uint_t qubit, const cvector_t &mat) const; + + // Specialized single qubit apply matrix function + void apply_diagonal_matrix_1(Container &data, size_t data_size, + int threads, const uint_t qubit, + const cvector_t &mat) const; + + // Convert a matrix to a different type + // TODO: this makes an unnecessary copy when data_t = double. + cvector_t convert(const cvector_t &v) const; +}; + +/******************************************************************************* + * + * MATRIX MULTIPLICATION + * + ******************************************************************************/ + +template +cvector_t Transformer::convert(const cvector_t &v) const { + cvector_t ret(v.size()); + for (size_t i = 0; i < v.size(); ++i) + ret[i] = v[i]; + return ret; +} + +template +void Transformer::apply_matrix(Container &data, size_t data_size, + int threads, const reg_t &qubits, + const cvector_t &mat) const { + // Static array optimized lambda functions + switch (qubits.size()) { + case 1: + return apply_matrix_1(data, data_size, threads, qubits[0], mat); + case 2: + return apply_matrix_n<2>(data, data_size, threads, qubits, mat); + case 3: + return apply_matrix_n<3>(data, data_size, threads, qubits, mat); + case 4: + return apply_matrix_n<4>(data, data_size, threads, qubits, mat); + case 5: + return apply_matrix_n<5>(data, data_size, threads, qubits, mat); + case 6: + return apply_matrix_n<6>(data, data_size, threads, qubits, mat); + case 7: + return apply_matrix_n<7>(data, data_size, threads, qubits, mat); + case 8: + return apply_matrix_n<8>(data, data_size, threads, qubits, mat); + case 9: + return apply_matrix_n<9>(data, data_size, threads, qubits, mat); + case 10: + return apply_matrix_n<10>(data, data_size, threads, qubits, mat); + case 11: + return apply_matrix_n<11>(data, data_size, threads, qubits, mat); + case 12: + return apply_matrix_n<12>(data, data_size, threads, qubits, mat); + case 13: + return apply_matrix_n<13>(data, data_size, threads, qubits, mat); + case 14: + return apply_matrix_n<14>(data, data_size, threads, qubits, mat); + case 15: + return apply_matrix_n<15>(data, data_size, threads, qubits, mat); + case 16: + return apply_matrix_n<16>(data, data_size, threads, qubits, mat); + case 17: + return apply_matrix_n<17>(data, data_size, threads, qubits, mat); + case 18: + return apply_matrix_n<18>(data, data_size, threads, qubits, mat); + case 19: + return apply_matrix_n<19>(data, data_size, threads, qubits, mat); + case 20: + return apply_matrix_n<20>(data, data_size, threads, qubits, mat); + default: { + throw std::runtime_error( + "Maximum size of apply matrix is a 20-qubit matrix."); + } + } +} + +template +template +void Transformer::apply_matrix_n(Container &data, size_t data_size, + int threads, const reg_t &qs, + const cvector_t &mat) const { + const size_t DIM = 1ULL << N; + auto func = [&](const areg_t<1UL << N> &inds, + const cvector_t &_mat) -> void { + std::array, 1ULL << N> cache; + for (size_t i = 0; i < DIM; i++) { + const auto ii = inds[i]; + cache[i] = data[ii]; + data[ii] = 0.; + } + // update state vector + for (size_t i = 0; i < DIM; i++) + for (size_t j = 0; j < DIM; j++) + data[inds[i]] += _mat[i + DIM * j] * cache[j]; + }; + areg_t qubits; + std::copy_n(qs.begin(), N, qubits.begin()); + apply_lambda(0, data_size, threads, func, qubits, convert(mat)); +} + +template +void Transformer::apply_matrix_1(Container &data, size_t data_size, + int threads, const uint_t qubit, + const cvector_t &mat) const { + + // Check if matrix is diagonal and if so use optimized lambda + if (mat[1] == 0.0 && mat[2] == 0.0) { + const cvector_t diag = {{mat[0], mat[3]}}; + apply_diagonal_matrix_1(data, data_size, threads, qubit, diag); + return; + } + + // Convert qubit to array register for lambda functions + areg_t<1> qubits = {{qubit}}; + + // Check if anti-diagonal matrix and if so use optimized lambda + if (mat[0] == 0.0 && mat[3] == 0.0) { + if (mat[1] == 1.0 && mat[2] == 1.0) { + // X-matrix + auto func = [&](const areg_t<2> &inds) -> void { + std::swap(data[inds[0]], data[inds[1]]); + }; + apply_lambda(0, data_size, threads, func, qubits); + return; + } + if (mat[2] == 0.0) { + // Non-unitary projector + // possibly used in measure/reset/kraus update + auto func = [&](const areg_t<2> &inds, + const cvector_t &_mat) -> void { + data[inds[1]] = _mat[1] * data[inds[0]]; + data[inds[0]] = 0.0; + }; + apply_lambda(0, data_size, threads, func, qubits, convert(mat)); + return; + } + if (mat[1] == 0.0) { + // Non-unitary projector + // possibly used in measure/reset/kraus update + auto func = [&](const areg_t<2> &inds, + const cvector_t &_mat) -> void { + data[inds[0]] = _mat[2] * data[inds[1]]; + data[inds[1]] = 0.0; + }; + apply_lambda(0, data_size, threads, func, qubits, convert(mat)); + return; + } + // else we have a general anti-diagonal matrix + auto func = [&](const areg_t<2> &inds, + const cvector_t &_mat) -> void { + const std::complex cache = data[inds[0]]; + data[inds[0]] = _mat[2] * data[inds[1]]; + data[inds[1]] = _mat[1] * cache; + }; + apply_lambda(0, data_size, threads, func, qubits, convert(mat)); + return; + } + + auto func = [&](const areg_t<2> &inds, + const cvector_t &_mat) -> void { + const auto cache = data[inds[0]]; + data[inds[0]] = _mat[0] * cache + _mat[2] * data[inds[1]]; + data[inds[1]] = _mat[1] * cache + _mat[3] * data[inds[1]]; + }; + + apply_lambda(0, data_size, threads, func, qubits, convert(mat)); +} + +template +void Transformer::apply_diagonal_matrix(Container &data, + size_t data_size, int threads, + const reg_t &qubits, + const cvector_t &diag) const { + if (qubits.size() == 1) { + apply_diagonal_matrix_1(data, data_size, threads, qubits[0], diag); + return; + } + + const size_t N = qubits.size(); + auto func = [&](const areg_t<2> &inds, + const cvector_t &_diag) -> void { + for (int_t i = 0; i < 2; ++i) { + const int_t k = inds[i]; + int_t iv = 0; + for (int_t j = 0; j < N; j++) + if ((k & (1ULL << qubits[j])) != 0) + iv += (1ULL << j); + if (_diag[iv] != (data_t)1.0) + data[k] *= _diag[iv]; + } + }; + apply_lambda(0, data_size, threads, func, areg_t<1>({{qubits[0]}}), + convert(diag)); +} + +template +void Transformer::apply_diagonal_matrix_1 ( + Container &data, size_t data_size, int threads, const uint_t qubit, + const cvector_t &diag) const { + // TODO: This should be changed so it isn't checking doubles with == + if (diag[0] == 1.0) { // [[1, 0], [0, z]] matrix + if (diag[1] == 1.0) + return; // Identity + + if (diag[1] == std::complex(0., -1.)) { // [[1, 0], [0, -i]] + auto func = [&](const areg_t<2> &inds, + const cvector_t &_mat) -> void { + const auto k = inds[1]; + double cache = data[k].imag(); + data[k].imag(data[k].real() * -1.); + data[k].real(cache); + }; + apply_lambda(0, data_size, threads, func, areg_t<1>({{qubit}}), + convert(diag)); + return; + } + if (diag[1] == std::complex(0., 1.)) { + // [[1, 0], [0, i]] + auto func = [&](const areg_t<2> &inds, + const cvector_t &_mat) -> void { + const auto k = inds[1]; + double cache = data[k].imag(); + data[k].imag(data[k].real()); + data[k].real(cache * -1.); + }; + apply_lambda(0, data_size, threads, func, areg_t<1>({{qubit}}), + convert(diag)); + return; + } + if (diag[0] == 0.0) { + // [[1, 0], [0, 0]] + auto func = [&](const areg_t<2> &inds, + const cvector_t &_mat) -> void { + data[inds[1]] = 0.0; + }; + apply_lambda(0, data_size, threads, func, areg_t<1>({{qubit}}), + convert(diag)); + return; + } + // general [[1, 0], [0, z]] + auto func = [&](const areg_t<2> &inds, + const cvector_t &_mat) -> void { + const auto k = inds[1]; + data[k] *= _mat[1]; + }; + apply_lambda(0, data_size, threads, func, areg_t<1>({{qubit}}), + convert(diag)); + return; + } else if (diag[1] == 1.0) { + // [[z, 0], [0, 1]] matrix + if (diag[0] == std::complex(0., -1.)) { + // [[-i, 0], [0, 1]] + auto func = [&](const areg_t<2> &inds, + const cvector_t &_mat) -> void { + const auto k = inds[1]; + double cache = data[k].imag(); + data[k].imag(data[k].real() * -1.); + data[k].real(cache); + }; + apply_lambda(0, data_size, threads, func, areg_t<1>({{qubit}}), + convert(diag)); + return; + } + if (diag[0] == std::complex(0., 1.)) { + // [[i, 0], [0, 1]] + auto func = [&](const areg_t<2> &inds, + const cvector_t &_mat) -> void { + const auto k = inds[1]; + double cache = data[k].imag(); + data[k].imag(data[k].real()); + data[k].real(cache * -1.); + }; + apply_lambda(0, data_size, threads, func, areg_t<1>({{qubit}}), + convert(diag)); + return; + } + if (diag[0] == 0.0) { + // [[0, 0], [0, 1]] + auto func = [&](const areg_t<2> &inds, + const cvector_t &_mat) -> void { + data[inds[0]] = 0.0; + }; + apply_lambda(0, data_size, threads, func, areg_t<1>({{qubit}}), + convert(diag)); + return; + } + // general [[z, 0], [0, 1]] + auto func = [&](const areg_t<2> &inds, + const cvector_t &_mat) -> void { + const auto k = inds[0]; + data[k] *= _mat[0]; + }; + apply_lambda(0, data_size, threads, func, areg_t<1>({{qubit}}), + convert(diag)); + return; + } else { + // Lambda function for diagonal matrix multiplication + auto func = [&](const areg_t<2> &inds, + const cvector_t &_mat) -> void { + const auto k0 = inds[0]; + const auto k1 = inds[1]; + data[k0] *= _mat[0]; + data[k1] *= _mat[1]; + }; + apply_lambda(0, data_size, threads, func, areg_t<1>({{qubit}}), + convert(diag)); + } +} + +//------------------------------------------------------------------------------ +} // end namespace QV +} // end namespace AER +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +#endif // end module diff --git a/src/simulators/statevector/transformer_avx2.hpp b/src/simulators/statevector/transformer_avx2.hpp new file mode 100755 index 0000000000..bce6bf4aea --- /dev/null +++ b/src/simulators/statevector/transformer_avx2.hpp @@ -0,0 +1,79 @@ +/** + * This code is part of Qiskit. + * + * (C) Copyright IBM 2018, 2020. + * + * 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. + */ + +#ifndef _qv_transformer_avx2_ +#define _qv_transformer_avx2_ + +#include "misc/common_macros.hpp" +#include "simulators/statevector/qv_avx2.hpp" +#include "simulators/statevector/transformer.hpp" + +namespace AER { +namespace QV { + +template +class TransformerAVX2 : public Transformer { + using Base = Transformer; + +public: + //----------------------------------------------------------------------- + // Apply Matrices + //----------------------------------------------------------------------- + + // Apply a N-qubit matrix to the state vector. + // The matrix is input as vector of the column-major vectorized N-qubit + // matrix. + void apply_matrix(Container &data, size_t data_size, int threads, + const reg_t &qubits, const cvector_t &mat) const override; +}; + +/******************************************************************************* + * + * Implementation + * + ******************************************************************************/ + +// We do not define this functions in case we don't use AVX2 +// so it can compile, as this class won't be used +#if defined(_MSC_VER) || defined(GNUC_AVX2) + +template +void TransformerAVX2::apply_matrix(Container &data, size_t data_size, + int threads, const reg_t &qubits, + const cvector_t &mat) const{ + + if (qubits.size() == 1 && + ((mat[1] == 0.0 && mat[2] == 0.0) || (mat[0] == 0.0 && mat[3] == 0.0))) { + return Base::apply_matrix_1(data, data_size, threads, qubits[0], mat); + } + + if (apply_matrix_avx( + reinterpret_cast(data), data_size, qubits.data(), + qubits.size(), reinterpret_cast(Base::convert(mat).data()), + threads) == Avx::Applied) { + return; + } + + Base::apply_matrix(data, data_size, threads, qubits, mat); +} + +#endif // AVX2 Code + +//------------------------------------------------------------------------------ +} // end namespace QV +} // end namespace AER +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +#endif // end module From 6cf7b31cb01481098641fa0bf60ca808ac54d074 Mon Sep 17 00:00:00 2001 From: "Christopher J. Wood" Date: Sat, 3 Oct 2020 12:01:29 -0400 Subject: [PATCH 009/126] Fix snapshots being copied rather than moved (#971) --- releasenotes/notes/fix-snapshot-copy-54ee685094d1e261.yaml | 6 ++++++ src/framework/results/data/average_snapshot.hpp | 2 +- src/framework/results/data/pershot_snapshot.hpp | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 releasenotes/notes/fix-snapshot-copy-54ee685094d1e261.yaml diff --git a/releasenotes/notes/fix-snapshot-copy-54ee685094d1e261.yaml b/releasenotes/notes/fix-snapshot-copy-54ee685094d1e261.yaml new file mode 100644 index 0000000000..b87a3cee53 --- /dev/null +++ b/releasenotes/notes/fix-snapshot-copy-54ee685094d1e261.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + Fixes a bug where snapshot data was always copied from C++ to Python rather + than moved where possible. This will halve memory usage and improve simulation + time when using large statevector or density matrix snapshots. diff --git a/src/framework/results/data/average_snapshot.hpp b/src/framework/results/data/average_snapshot.hpp index 1d372b520b..cab44fb0f9 100755 --- a/src/framework/results/data/average_snapshot.hpp +++ b/src/framework/results/data/average_snapshot.hpp @@ -61,7 +61,7 @@ class AverageSnapshot { json_t to_json(); // Return data reference - stringmap_t>> data() { return data_; } + stringmap_t>> &data() { return data_; } // Return const data reference const stringmap_t>> &data() const { return data_; } diff --git a/src/framework/results/data/pershot_snapshot.hpp b/src/framework/results/data/pershot_snapshot.hpp index dc65ffb3f9..0ec86a1922 100755 --- a/src/framework/results/data/pershot_snapshot.hpp +++ b/src/framework/results/data/pershot_snapshot.hpp @@ -59,7 +59,7 @@ class PershotSnapshot { json_t to_json(); // Return data reference - stringmap_t> data() { return data_; } + stringmap_t> &data() { return data_; } // Return const data reference const stringmap_t> &data() const { return data_; } From d715609b47961305397b608e89931e283248ac99 Mon Sep 17 00:00:00 2001 From: "Christopher J. Wood" Date: Mon, 5 Oct 2020 12:57:30 -0400 Subject: [PATCH 010/126] Deprecate snapshot variance (#974) --- .../aer/extensions/snapshot_expectation_value.py | 6 ++++++ .../providers/aer/extensions/snapshot_probabilities.py | 4 ++++ .../deprecate-snapshot-variance-7d02188deacf9a08.yaml | 9 +++++++++ 3 files changed, 19 insertions(+) create mode 100644 releasenotes/notes/deprecate-snapshot-variance-7d02188deacf9a08.yaml diff --git a/qiskit/providers/aer/extensions/snapshot_expectation_value.py b/qiskit/providers/aer/extensions/snapshot_expectation_value.py index 1603e70ff1..4572fdc9a2 100644 --- a/qiskit/providers/aer/extensions/snapshot_expectation_value.py +++ b/qiskit/providers/aer/extensions/snapshot_expectation_value.py @@ -13,6 +13,7 @@ """ Simulator command to snapshot internal simulator representation. """ +from warnings import warn import math import numpy from qiskit import QuantumCircuit @@ -38,6 +39,11 @@ def __init__(self, label, op, single_shot=False, variance=False): Raises: ExtensionError: if snapshot is invalid. """ + if variance: + warn('The snapshot `variance` kwarg has been deprecated and will' + ' be removed in qiskit-aer 0.8. To compute variance use' + ' `single_shot=True` and compute manually in post-processing', + DeprecationWarning) pauli_op = self._format_pauli_op(op) if pauli_op: # Pauli expectation value diff --git a/qiskit/providers/aer/extensions/snapshot_probabilities.py b/qiskit/providers/aer/extensions/snapshot_probabilities.py index cbcf7807d0..7686c565ce 100644 --- a/qiskit/providers/aer/extensions/snapshot_probabilities.py +++ b/qiskit/providers/aer/extensions/snapshot_probabilities.py @@ -14,6 +14,7 @@ Simulator command to snapshot internal simulator representation. """ +from warnings import warn from qiskit import QuantumCircuit from qiskit.providers.aer.extensions import Snapshot @@ -32,6 +33,9 @@ def __init__(self, label, num_qubits, variance=False): Raises: ExtensionError: if snapshot is invalid. """ + if variance: + warn('The snapshot `variance` kwarg has been deprecated and will be removed' + ' in qiskit-aer 0.8.', DeprecationWarning) snapshot_type = 'probabilities_with_variance' if variance else 'probabilities' super().__init__(label, snapshot_type=snapshot_type, num_qubits=num_qubits) diff --git a/releasenotes/notes/deprecate-snapshot-variance-7d02188deacf9a08.yaml b/releasenotes/notes/deprecate-snapshot-variance-7d02188deacf9a08.yaml new file mode 100644 index 0000000000..01a17da72e --- /dev/null +++ b/releasenotes/notes/deprecate-snapshot-variance-7d02188deacf9a08.yaml @@ -0,0 +1,9 @@ +--- +deprecations: + - | + The `variance` kwarg of Snapshot instructions has been deprecated. This + function computed the sample variance in the snapshot due to noise model + sampling, not the variance due to measurement statistics so was often + being used incorrectly. If noise modeling variance is required single shot + snapshots should be used so variance can be computed manually in + post-processing. From c7c49c128cb52a64d158a12fef72750e08c63b93 Mon Sep 17 00:00:00 2001 From: "Christopher J. Wood" Date: Tue, 6 Oct 2020 10:35:08 -0400 Subject: [PATCH 011/126] Split pybind file into multiple files (#976) This is to allow easier editing of Python binding for individual classes in the future --- .../aer/backends/wrappers/bindings.cc | 4 +- src/framework/pybind_basics.hpp | 172 +++++ src/framework/pybind_json.hpp | 613 +----------------- src/framework/results/pybind_data.hpp | 465 +++++++++++++ src/framework/results/pybind_result.hpp | 130 ++++ 5 files changed, 770 insertions(+), 614 deletions(-) create mode 100755 src/framework/pybind_basics.hpp create mode 100755 src/framework/results/pybind_data.hpp create mode 100755 src/framework/results/pybind_result.hpp diff --git a/qiskit/providers/aer/backends/wrappers/bindings.cc b/qiskit/providers/aer/backends/wrappers/bindings.cc index 637398c6b8..9215cfe740 100644 --- a/qiskit/providers/aer/backends/wrappers/bindings.cc +++ b/qiskit/providers/aer/backends/wrappers/bindings.cc @@ -13,7 +13,7 @@ DISABLE_WARNING_POP #include "framework/matrix.hpp" #include "framework/types.hpp" -#include "framework/pybind_json.hpp" +#include "framework/results/pybind_result.hpp" #include "controllers/qasm_controller.hpp" #include "controllers/statevector_controller.hpp" @@ -24,7 +24,7 @@ template class ControllerExecutor { public: ControllerExecutor() = default; - py::object operator()(const py::object &qobj) { return AerToPy::from_result(AER::controller_execute(qobj)); } + py::object operator()(const py::object &qobj) { return AerToPy::to_python(AER::controller_execute(qobj)); } }; PYBIND11_MODULE(controller_wrappers, m) { diff --git a/src/framework/pybind_basics.hpp b/src/framework/pybind_basics.hpp new file mode 100755 index 0000000000..1f2e6c42d1 --- /dev/null +++ b/src/framework/pybind_basics.hpp @@ -0,0 +1,172 @@ +/** + * This code is part of Qiskit. + * + * (C) Copyright IBM 2018, 2019, 2020. + * + * 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. + */ + +#ifndef _aer_framework_pybind_basics_hpp_ +#define _aer_framework_pybind_basics_hpp_ + +#include +#include + +#include "framework/linalg/vector.hpp" +#include "framework/matrix.hpp" + +#include "framework/pybind_json.hpp" + +namespace AerToPy { + +//============================================================================ +// Pybind11 move conversion of basic types +//============================================================================ + +// Move an arbitrary object to Python by calling Pybind11 cast with move +// Template specialization is used with this function for adding custom +// conversion for other types +// NOTE: Can this function be replaced by overload py::cast for custom types? +template py::object to_python(T &&obj); + +// Move a matrix to Python via conversion to Numpy array +template py::object to_python(matrix &&obj); + +// Move a Vector to Python via conversion to Numpy array +template py::object to_python(AER::Vector &&obj); + +// Move a Vector to Python via recusivly calling to_python on elements +template py::object to_python(std::vector &&obj); + +// Template specialization for moving numeric std::vectors to Numpy arrays +template <> py::object to_python(std::vector &&obj); +template <> py::object to_python(std::vector &&obj); +template <> py::object to_python(std::vector &&obj); +template <> py::object to_python(std::vector &&obj); +template <> py::object to_python(std::vector> &&obj); +template <> py::object to_python(std::vector> &&obj); + +//------------------------------------------------------------------------------ +// Convert To Numpy Arrays +//------------------------------------------------------------------------------ + +// Convert a matrix to a 2D Numpy array in Fortan order +template +py::array_t to_numpy(matrix &&obj); + +// Convert a Vector to a 1D Numpy array +template +py::array_t to_numpy(AER::Vector &&obj); + +// Convert a vector to a 1D Numpy array +template +py::array_t to_numpy(std::vector &&obj); + +//============================================================================ +// Implementation +//============================================================================ + +//------------------------------------------------------------------------------ +// Basic Types +//------------------------------------------------------------------------------ + +template +py::object to_python(T &&obj) { + return py::cast(obj, py::return_value_policy::move); +} + +template +py::object to_python(std::vector &&obj) { + py::list pydata; + for(auto& elt : obj) { + pydata.append(to_python(std::move(elt))); + } + return std::move(pydata); +} + +template +py::object to_python(matrix &&obj) { + return to_numpy(std::move(obj)); +} + +template +py::object to_python(AER::Vector &&obj) { + return to_numpy(std::move(obj)); +} + +template <> +py::object to_python(std::vector &&obj) { + return to_numpy(std::move(obj)); +} + +template <> +py::object to_python(std::vector &&obj) { + return to_numpy(std::move(obj)); +} + +template <> +py::object to_python(std::vector &&obj) { + return to_numpy(std::move(obj)); +} + +template <> +py::object to_python(std::vector &&obj) { + return to_numpy(std::move(obj)); +} + +template <> +py::object to_python(std::vector> &&obj) { + return to_numpy(std::move(obj)); +} + +template <> +py::object to_python(std::vector> &&obj) { + return to_numpy(std::move(obj)); +} + +//------------------------------------------------------------------------------ +// Array Types +//------------------------------------------------------------------------------ + +template +py::array_t to_numpy(matrix &&src) { + std::array shape {static_cast(src.GetRows()), + static_cast(src.GetColumns())}; + matrix* src_ptr = new matrix(std::move(src)); + auto capsule = py::capsule(src_ptr, [](void* p) { delete reinterpret_cast*>(p); }); + return py::array_t(shape, src_ptr->data(), capsule); +} + +template +py::array_t to_numpy(AER::Vector &&src) { + AER::Vector* src_ptr = new AER::Vector(std::move(src)); + auto capsule = py::capsule(src_ptr, [](void* p) { delete reinterpret_cast*>(p); }); + return py::array_t( + src_ptr->size(), // shape of array + src_ptr->data(), // c-style contiguous strides for vector + capsule // numpy array references this parent + ); +} + + +template +py::array_t to_numpy(std::vector &&src) { + std::vector* src_ptr = new std::vector(std::move(src)); + auto capsule = py::capsule(src_ptr, [](void* p) { delete reinterpret_cast*>(p); }); + return py::array_t( + src_ptr->size(), // shape of array + src_ptr->data(), // c-style contiguous strides for vector + capsule // numpy array references this parent + ); +} + +//------------------------------------------------------------------------------ +} // end namespace AerToPy +//------------------------------------------------------------------------------ +#endif diff --git a/src/framework/pybind_json.hpp b/src/framework/pybind_json.hpp index 975c0cc7ac..83de9c93b6 100755 --- a/src/framework/pybind_json.hpp +++ b/src/framework/pybind_json.hpp @@ -49,181 +49,10 @@ namespace nl = nlohmann; using namespace pybind11::literals; using json_t = nlohmann::json; -#include "framework/results/result.hpp" -#include "framework/results/data/average_data.hpp" - //------------------------------------------------------------------------------ -// Aer C++ -> Python Conversion +// Nlohman JSON <--> Python Conversion //------------------------------------------------------------------------------ -namespace AerToPy { - -/** - * Convert a 1D contiguous container into a numpy array - * @param src is a vector - * @returns a python object (py::array_t) - */ -template -py::array_t array_from_sequence(Sequence& src); -template -py::array_t array_from_sequence(Sequence&& src); - -/** - * Convert a Matrix into a numpy array - * @param mat is a Matrix - * @returns a python object (py::array_t) - */ -template -py::array_t array_from_matrix(matrix &&mat); -template -py::array_t array_from_matrix(matrix &mat); - -/** - * Convert a Vector into a numpy array - * @param mat is a Vector - * @returns a python object (py::array_t) - */ -template -py::array_t array_from_vector(AER::Vector &&vec); -template -py::array_t array_from_vector(AER::Vector &vec); - -/** - * Convert a AverageData to a python object - * @param avg_data is an AverageData - * @returns a py::dict - */ -template -py::object from_avg_data(AER::AverageData &&avg_data); -template -py::object from_avg_data(AER::AverageData &avg_data); - -// JSON specialization -template<> -py::object from_avg_data(AER::AverageData &&avg_data); - -/** - * Convert a AverageData to a python object - * @param avg_data is an AverageData - * @returns a py::dict - */ -template -py::object from_avg_data(AER::AverageData> &&avg_data); -template -py::object from_avg_data(AER::AverageData> &avg_data); - - -/** - * Convert a AverageData to a python object - * @param avg_data is an AverageData - * @returns a py::dict - */ -template -py::object from_avg_data(AER::AverageData> &&avg_data); -template -py::object from_avg_data(AER::AverageData> &avg_data); - -/** - * Convert a AverageData to a python object - * @param avg_data is an AverageData - * @returns a py::dict - */ -template -py::object from_avg_data(AER::AverageData> &&avg_data); -template -py::object from_avg_data(AER::AverageData> &avg_data); - -/** - * Convert a AverageSnapshot to a python object - * @param avg_snap is an AverageSnapshot - * @returns a py::dict - */ -template -py::object from_avg_snap(AER::AverageSnapshot &&avg_snap); -template -py::object from_avg_snap(AER::AverageSnapshot &avg_snap); - -/** - * Convert a PershotSnapshot to a python object - * @param avg_snap is an PershotSnapshot - * @returns a py::dict - */ -template -py::object from_pershot_snap(AER::PershotSnapshot &&snap); -template -py::object from_pershot_snap(AER::PershotSnapshot &snap); - -/** - * Convert a PershotData to a python object - * @param data is an PershotData - * @returns a py::dict - */ -template -py::object from_pershot_data(AER::PershotData &&data); -template -py::object from_pershot_data(AER::PershotData &data); - -// JSON specialization -template<> -py::object from_pershot_data(AER::PershotData &&avg_data); - -/** - * Convert a PershotData to a python object - * @param data is an PershotData - * @returns a py::dict - */ -template -py::object from_pershot_data(AER::PershotData> &&data); -template -py::object from_pershot_data(AER::PershotData> &data); - - -/** - * Convert a PershotData to a python object - * @param data is an PershotData - * @returns a py::dict - */ -template -py::object from_pershot_data(AER::PershotData> &&data); -template -py::object from_pershot_data(AER::PershotData> &data); - -/** - * Convert a PershotData to a python object - * @param data is an PershotData - * @returns a py::dict - */ -template -py::object from_pershot_data(AER::PershotData> &&data); -template -py::object from_pershot_data(AER::PershotData> &data); - -/** - * Convert an ExperimentData to a python object - * @param result is an ExperimentData - * @returns a py::dict - */ -py::object from_data(AER::ExperimentData &&result); -py::object from_data(AER::ExperimentData &result); - -/** - * Convert an ExperimentResult to a python object - * @param result is an ExperimentResult - * @returns a py::dict - */ -py::object from_experiment(AER::ExperimentResult &&result); -py::object from_experiment(AER::ExperimentResult &result); - -/** - * Convert a Result to a python object - * @param result is a Result - * @returns a py::dict - */ -py::object from_result(AER::Result &&result); -py::object from_result(AER::Result &result); - -} //end namespace AerToPy - namespace std { /** @@ -466,444 +295,4 @@ void std::from_json(const json_t &js, py::object &o) { //------------------------------------------------------------------------------ -//============================================================================ -// Pybind Conversion for Simulator types -//============================================================================ - -template -py::array_t AerToPy::array_from_sequence(Sequence& seq) { - return AerToPy::array_from_sequence(std::move(seq)); -} - -template -py::array_t AerToPy::array_from_sequence(Sequence&& seq) { - // Move entire object to heap (Ensure is moveable!). Memory handled via Python capsule - Sequence* seq_ptr = new Sequence(std::move(seq)); - auto capsule = py::capsule(seq_ptr, [](void* p) { delete reinterpret_cast(p); }); - return py::array_t( - seq_ptr->size(), // shape of array - seq_ptr->data(), // c-style contiguous strides for Sequence - capsule // numpy array references this parent - ); -} - -template -py::array_t AerToPy::array_from_vector(AER::Vector &src) { - return AerToPy::array_from_vector(std::move(src)); -} - -template -py::array_t AerToPy::array_from_vector(AER::Vector &&src) { - // Move entire object to heap (Ensure is moveable!). Memory handled via Python capsule - AER::Vector* src_ptr = new AER::Vector(std::move(src)); - auto capsule = py::capsule(src_ptr, [](void* p) { delete reinterpret_cast*>(p); }); - return py::array_t(src_ptr->size(), src_ptr->data(), capsule); -} - -template -py::array_t AerToPy::array_from_matrix(matrix &src) { - return AerToPy::array_from_matrix(std::move(src)); -} - -template -py::array_t AerToPy::array_from_matrix(matrix &&src) { - std::array shape {static_cast(src.GetRows()), - static_cast(src.GetColumns())}; - matrix* src_ptr = new matrix(std::move(src)); - auto capsule = py::capsule(src_ptr, [](void* p) { delete reinterpret_cast*>(p); }); - return py::array_t(shape, src_ptr->data(), capsule); -} - -template -py::object AerToPy::from_avg_data(AER::AverageData &avg_data) { - return AerToPy::from_avg_data(std::move(avg_data)); -} - -template -py::object AerToPy::from_avg_data(AER::AverageData &&avg_data) { - py::dict d; - d["value"] = avg_data.mean(); - if (avg_data.has_variance()) { - d["variance"] = avg_data.variance(); - } - return std::move(d); -} - -template <> -py::object AerToPy::from_avg_data(AER::AverageData &&avg_data) { - py::dict d; - py::object py_mean; - from_json(avg_data.mean(), py_mean); - d["value"] = std::move(py_mean); - if (avg_data.has_variance()) { - py::object py_var; - from_json(avg_data.variance(), py_var); - d["variance"] = std::move(py_var); - } - return std::move(d); -} - -template -py::object AerToPy::from_avg_data(AER::AverageData> &avg_data) { - return AerToPy::from_avg_data(std::move(avg_data)); -} - -template -py::object AerToPy::from_avg_data(AER::AverageData> &&avg_data) { - py::dict d; - d["value"] = AerToPy::array_from_vector(avg_data.mean()); - if (avg_data.has_variance()) { - d["variance"] = AerToPy::array_from_vector(avg_data.variance()); - } - return std::move(d); -} - -template -py::object AerToPy::from_avg_data(AER::AverageData> &avg_data) { - return AerToPy::from_avg_data(std::move(avg_data)); -} - -template -py::object AerToPy::from_avg_data(AER::AverageData> &&avg_data) { - py::dict d; - d["value"] = AerToPy::array_from_matrix(avg_data.mean()); - if (avg_data.has_variance()) { - d["variance"] = AerToPy::array_from_matrix(avg_data.variance()); - } - return std::move(d); -} - -template -py::object AerToPy::from_avg_data(AER::AverageData> &avg_data) { - return AerToPy::from_avg_data(std::move(avg_data)); -} - -template -py::object AerToPy::from_avg_data(AER::AverageData> &&avg_data) { - py::dict d; - d["value"] = AerToPy::array_from_sequence(avg_data.mean()); - if (avg_data.has_variance()) { - d["variance"] = AerToPy::array_from_sequence(avg_data.variance()); - } - return std::move(d); -} - -template -py::object AerToPy::from_avg_snap(AER::AverageSnapshot &avg_snap) { - return AerToPy::from_avg_snap(std::move(avg_snap)); -} - -template -py::object AerToPy::from_avg_snap(AER::AverageSnapshot &&avg_snap) { - py::dict d; - for (auto &outer_pair : avg_snap.data()) { - py::list d1; - for (auto &inner_pair : outer_pair.second) { - // Store mean and variance for snapshot - py::dict datum = AerToPy::from_avg_data(inner_pair.second); - // Add memory key if there are classical registers - auto memory = inner_pair.first; - if ( ! memory.empty()) { - datum["memory"] = inner_pair.first; - } - // Add to list of output - d1.append(std::move(datum)); - } - d[outer_pair.first.data()] = std::move(d1); - } - return std::move(d); -} - -template -py::object AerToPy::from_pershot_snap(AER::PershotSnapshot &snap) { - return AerToPy::from_pershot_snap(std::move(snap)); -} -template -py::object AerToPy::from_pershot_snap(AER::PershotSnapshot &&snap) { - py::dict d; - // string PershotData - for (auto &pair : snap.data()) - d[pair.first.data()] = AerToPy::from_pershot_data(pair.second); - return std::move(d); -} - -template -py::object AerToPy::from_pershot_data(AER::PershotData &&data) { - return py::cast(data.data(), py::return_value_policy::move); -} - -template -py::object AerToPy::from_pershot_data(AER::PershotData &data) { - return AerToPy::from_pershot_data(std::move(data)); -} - -template<> -py::object AerToPy::from_pershot_data(AER::PershotData &&data) { - py::object tmp; - from_json(data.data(), tmp); - return tmp; -} - -template -py::object AerToPy::from_pershot_data(AER::PershotData> &&data) { - py::list l; - for (auto &&item : data.data()) { - l.append(AerToPy::array_from_matrix(item)); - } - return std::move(l); -} - -template -py::object AerToPy::from_pershot_data(AER::PershotData> &data) { - return AerToPy::from_pershot_data(std::move(data)); -} - - - -template -py::object AerToPy::from_pershot_data(AER::PershotData> &&data) { - py::list l; - for (auto &&item : data.data()) { - l.append(AerToPy::array_from_vector(item)); - } - return std::move(l); -} - -template -py::object AerToPy::from_pershot_data(AER::PershotData> &data) { - return AerToPy::from_pershot_data(std::move(data)); -} - - - -template -py::object AerToPy::from_pershot_data(AER::PershotData> &&data) { - py::list l; - for (auto &&item : data.data()) { - l.append(AerToPy::array_from_sequence(item)); - } - return std::move(l); -} - -template -py::object AerToPy::from_pershot_data(AER::PershotData> &data) { - return AerToPy::from_pershot_data(std::move(data)); -} - - -py::object AerToPy::from_data(AER::ExperimentData &datum) { - return AerToPy::from_data(std::move(datum)); -} - -py::object AerToPy::from_data(AER::ExperimentData &&datum) { - py::dict pydata; - - // Measure data - if (datum.return_counts_ && ! datum.counts_.empty()) { - pydata["counts"] = std::move(datum.counts_); - } - if (datum.return_memory_ && ! datum.memory_.empty()) { - pydata["memory"] = std::move(datum.memory_); - } - if (datum.return_register_ && ! datum.register_.empty()) { - pydata["register"] = std::move(datum.register_); - } - - // Add additional data - for (auto &pair : datum.additional_data()) { - py::object tmp; - from_json(pair.second, tmp); - pydata[pair.first.data()] = std::move(tmp); - } - for (auto &pair : datum.additional_data>()) { - pydata[pair.first.data()] = pair.second; - } - for (auto &pair : datum.additional_data>>()) { - pydata[pair.first.data()] = AerToPy::array_from_sequence(pair.second); - } - for (auto &pair : datum.additional_data>>()) { - pydata[pair.first.data()] = AerToPy::array_from_sequence(pair.second); - } - for (auto &pair : datum.additional_data>>()) { - pydata[pair.first.data()] = AerToPy::array_from_vector(pair.second); - } - for (auto &pair : datum.additional_data>>()) { - pydata[pair.first.data()] = AerToPy::array_from_vector(pair.second); - } - for (auto &pair : datum.additional_data>>()) { - pydata[pair.first.data()] = AerToPy::array_from_matrix(pair.second); - } - for (auto &pair : datum.additional_data>>()) { - pydata[pair.first.data()] = AerToPy::array_from_matrix(pair.second); - } - for (auto &pair : datum.additional_data>>()) { - pydata[pair.first.data()] = pair.second; - } - for (auto &pair : datum.additional_data>()) { - pydata[pair.first.data()] = pair.second; - } - - // Snapshot data - if (datum.return_snapshots_) { - py::dict snapshots; - - // Average snapshots - for (auto &pair : datum.average_snapshots()) { - snapshots[pair.first.data()] = AerToPy::from_avg_snap(pair.second); - } - for (auto &pair : datum.average_snapshots>()) { - snapshots[pair.first.data()] = AerToPy::from_avg_snap(pair.second); - } - for (auto &pair : datum.average_snapshots>>()) { - snapshots[pair.first.data()] = AerToPy::from_avg_snap(pair.second); - } - for (auto &pair : datum.average_snapshots>>()) { - snapshots[pair.first.data()] = AerToPy::from_avg_snap(pair.second); - } - for (auto &pair : datum.average_snapshots>>()) { - snapshots[pair.first.data()] = AerToPy::from_avg_snap(pair.second); - } - for (auto &pair : datum.average_snapshots>>()) { - snapshots[pair.first.data()] = AerToPy::from_avg_snap(pair.second); - } - for (auto &pair : datum.average_snapshots>>()) { - snapshots[pair.first.data()] = AerToPy::from_avg_snap(pair.second); - } - for (auto &pair : datum.average_snapshots>>()) { - snapshots[pair.first.data()] = AerToPy::from_avg_snap(pair.second); - } - for (auto &pair : datum.average_snapshots>>()) { - snapshots[pair.first.data()] = AerToPy::from_avg_snap(pair.second); - } - for (auto &pair : datum.average_snapshots>()) { - snapshots[pair.first.data()] = AerToPy::from_avg_snap(pair.second); - } - // Singleshot snapshot data - // Note these will override the average snapshots - // if they share the same type string - - for (auto &pair : datum.pershot_snapshots()) { - snapshots[pair.first.data()] = AerToPy::from_pershot_snap(pair.second); - } - for (auto &pair : datum.pershot_snapshots>()) { - snapshots[pair.first.data()] = AerToPy::from_pershot_snap(pair.second); - } - for (auto &pair : datum.pershot_snapshots>>()) { - snapshots[pair.first.data()] = AerToPy::from_pershot_snap(pair.second); - } - for (auto &pair : datum.pershot_snapshots>>()) { - snapshots[pair.first.data()] = AerToPy::from_pershot_snap(pair.second); - } - for (auto &pair : datum.pershot_snapshots>>()) { - snapshots[pair.first.data()] = AerToPy::from_pershot_snap(pair.second); - } - for (auto &pair : datum.pershot_snapshots>>()) { - snapshots[pair.first.data()] = AerToPy::from_pershot_snap(pair.second); - } - for (auto &pair : datum.pershot_snapshots>>()) { - snapshots[pair.first.data()] = AerToPy::from_pershot_snap(pair.second); - } - for (auto &pair : datum.pershot_snapshots>>()) { - snapshots[pair.first.data()] = AerToPy::from_pershot_snap(pair.second); - } - for (auto &pair : datum.pershot_snapshots>>()) { - snapshots[pair.first.data()] = AerToPy::from_pershot_snap(pair.second); - } - for (auto &pair : datum.pershot_snapshots>()) { - snapshots[pair.first.data()] = AerToPy::from_pershot_snap(pair.second); - } - - if ( py::len(snapshots) != 0 ) - pydata["snapshots"] = std::move(snapshots); - } - //for (auto item : pydatum) - // py::print(" {}:, {}"_s.format(item.first, item.second)); - return std::move(pydata); -} - -py::object AerToPy::from_experiment(AER::ExperimentResult &result) { - return AerToPy::from_experiment(std::move(result)); -} - -py::object AerToPy::from_experiment(AER::ExperimentResult &&result) { - py::dict pyexperiment; - - pyexperiment["shots"] = result.shots; - pyexperiment["seed_simulator"] = result.seed; - - pyexperiment["data"] = AerToPy::from_data(result.data); - - pyexperiment["success"] = (result.status == AER::ExperimentResult::Status::completed); - switch (result.status) { - case AER::ExperimentResult::Status::completed: - pyexperiment["status"] = "DONE"; - break; - case AER::ExperimentResult::Status::error: - pyexperiment["status"] = std::string("ERROR: ") + result.message; - break; - case AER::ExperimentResult::Status::empty: - pyexperiment["status"] = "EMPTY"; - } - pyexperiment["time_taken"] = result.time_taken; - if (result.header.empty() == false) { - py::object tmp; - from_json(result.header, tmp); - pyexperiment["header"] = std::move(tmp); - } - if (result.metadata.empty() == false) { - py::object tmp; - from_json(result.metadata, tmp); - pyexperiment["metadata"] = std::move(tmp); - } - return std::move(pyexperiment); -} - -py::object AerToPy::from_result(AER::Result &result) { - return AerToPy::from_result(std::move(result)); -} - -py::object AerToPy::from_result(AER::Result &&result) { - py::dict pyresult; - pyresult["qobj_id"] = result.qobj_id; - - pyresult["backend_name"] = result.backend_name; - pyresult["backend_version"] = result.backend_version; - pyresult["date"] = result.date; - pyresult["job_id"] = result.job_id; - - py::list exp_results; - for(AER::ExperimentResult& exp : result.results) - exp_results.append(AerToPy::from_experiment(std::move(exp))); - pyresult["results"] = std::move(exp_results); - - // For header and metadata we continue using the json->pyobject casting - // bc these are assumed to be small relative to the ExperimentResults - if (result.header.empty() == false) { - py::object tmp; - from_json(result.header, tmp); - pyresult["header"] = std::move(tmp); - } - if (result.metadata.empty() == false) { - py::object tmp; - from_json(result.metadata, tmp); - pyresult["metadata"] = std::move(tmp); - } - pyresult["success"] = (result.status == AER::Result::Status::completed); - switch (result.status) { - case AER::Result::Status::completed: - pyresult["status"] = "COMPLETED"; - break; - case AER::Result::Status::partial_completed: - pyresult["status"] = "PARTIAL COMPLETED"; - break; - case AER::Result::Status::error: - pyresult["status"] = std::string("ERROR: ") + result.message; - break; - case AER::Result::Status::empty: - pyresult["status"] = "EMPTY"; - } - return std::move(pyresult); - -} - #endif diff --git a/src/framework/results/pybind_data.hpp b/src/framework/results/pybind_data.hpp new file mode 100755 index 0000000000..e06e7a750b --- /dev/null +++ b/src/framework/results/pybind_data.hpp @@ -0,0 +1,465 @@ +/** + * This code is part of Qiskit. + * + * (C) Copyright IBM 2018, 2019, 2020. + * + * 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. + */ + +#ifndef _aer_framework_result_pybind_data_hpp_ +#define _aer_framework_result_pybind_data_hpp_ + +#include "framework/pybind_basics.hpp" +#include "framework/results/experiment_data.hpp" + +//------------------------------------------------------------------------------ +// Aer C++ -> Python Conversion +//------------------------------------------------------------------------------ + +namespace AerToPy { + +/** + * Convert a AverageData to a python object + * @param avg_data is an AverageData + * @returns a py::dict + */ +template +py::object from_avg_data(AER::AverageData &&avg_data); +template +py::object from_avg_data(AER::AverageData &avg_data); + +// JSON specialization +template<> +py::object from_avg_data(AER::AverageData &&avg_data); + +/** + * Convert a AverageData to a python object + * @param avg_data is an AverageData + * @returns a py::dict + */ +template +py::object from_avg_data(AER::AverageData> &&avg_data); +template +py::object from_avg_data(AER::AverageData> &avg_data); + + +/** + * Convert a AverageData to a python object + * @param avg_data is an AverageData + * @returns a py::dict + */ +template +py::object from_avg_data(AER::AverageData> &&avg_data); +template +py::object from_avg_data(AER::AverageData> &avg_data); + +/** + * Convert a AverageData to a python object + * @param avg_data is an AverageData + * @returns a py::dict + */ +template +py::object from_avg_data(AER::AverageData> &&avg_data); +template +py::object from_avg_data(AER::AverageData> &avg_data); + +/** + * Convert a AverageSnapshot to a python object + * @param avg_snap is an AverageSnapshot + * @returns a py::dict + */ +template +py::object from_avg_snap(AER::AverageSnapshot &&avg_snap); +template +py::object from_avg_snap(AER::AverageSnapshot &avg_snap); + +/** + * Convert a PershotSnapshot to a python object + * @param avg_snap is an PershotSnapshot + * @returns a py::dict + */ +template +py::object from_pershot_snap(AER::PershotSnapshot &&snap); +template +py::object from_pershot_snap(AER::PershotSnapshot &snap); + +/** + * Convert a PershotData to a python object + * @param data is an PershotData + * @returns a py::dict + */ +template +py::object from_pershot_data(AER::PershotData &&data); +template +py::object from_pershot_data(AER::PershotData &data); + +// JSON specialization +template<> +py::object from_pershot_data(AER::PershotData &&avg_data); + +/** + * Convert a PershotData to a python object + * @param data is an PershotData + * @returns a py::dict + */ +template +py::object from_pershot_data(AER::PershotData> &&data); +template +py::object from_pershot_data(AER::PershotData> &data); + + +/** + * Convert a PershotData to a python object + * @param data is an PershotData + * @returns a py::dict + */ +template +py::object from_pershot_data(AER::PershotData> &&data); +template +py::object from_pershot_data(AER::PershotData> &data); + +/** + * Convert a PershotData to a python object + * @param data is an PershotData + * @returns a py::dict + */ +template +py::object from_pershot_data(AER::PershotData> &&data); +template +py::object from_pershot_data(AER::PershotData> &data); + +/** + * Convert an ExperimentData to a python object + * @param result is an ExperimentData + * @returns a py::dict + */ +py::object from_data(AER::ExperimentData &&result); +py::object from_data(AER::ExperimentData &result); + +} //end namespace AerToPy + + +/******************************************************************************* + * + * Implementations + * + ******************************************************************************/ + +//============================================================================ +// Pybind Conversion for Simulator types +//============================================================================ + +template +py::object AerToPy::from_avg_data(AER::AverageData &avg_data) { + return AerToPy::from_avg_data(std::move(avg_data)); +} + +template +py::object AerToPy::from_avg_data(AER::AverageData &&avg_data) { + py::dict d; + d["value"] = std::move(avg_data.mean()); + if (avg_data.has_variance()) { + d["variance"] = std::move(avg_data.variance()); + } + return std::move(d); +} + +template <> +py::object AerToPy::from_avg_data(AER::AverageData &&avg_data) { + py::dict d; + py::object py_mean; + from_json(avg_data.mean(), py_mean); + d["value"] = std::move(py_mean); + if (avg_data.has_variance()) { + py::object py_var; + from_json(avg_data.variance(), py_var); + d["variance"] = std::move(py_var); + } + return std::move(d); +} + +template +py::object AerToPy::from_avg_data(AER::AverageData> &avg_data) { + return AerToPy::from_avg_data(std::move(avg_data)); +} + +template +py::object AerToPy::from_avg_data(AER::AverageData> &&avg_data) { + py::dict d; + d["value"] = AerToPy::to_numpy(std::move(avg_data.mean())); + if (avg_data.has_variance()) { + d["variance"] = AerToPy::to_numpy(std::move(avg_data.variance())); + } + return std::move(d); +} + +template +py::object AerToPy::from_avg_data(AER::AverageData> &avg_data) { + return AerToPy::from_avg_data(std::move(avg_data)); +} + +template +py::object AerToPy::from_avg_data(AER::AverageData> &&avg_data) { + py::dict d; + d["value"] = AerToPy::to_numpy(std::move(avg_data.mean())); + if (avg_data.has_variance()) { + d["variance"] = AerToPy::to_numpy(std::move(avg_data.variance())); + } + return std::move(d); +} + +template +py::object AerToPy::from_avg_data(AER::AverageData> &avg_data) { + return AerToPy::from_avg_data(std::move(avg_data)); +} + +template +py::object AerToPy::from_avg_data(AER::AverageData> &&avg_data) { + py::dict d; + d["value"] = AerToPy::to_numpy(std::move(avg_data.mean())); + if (avg_data.has_variance()) { + d["variance"] = AerToPy::to_numpy(std::move(avg_data.variance())); + } + return std::move(d); +} + +template +py::object AerToPy::from_avg_snap(AER::AverageSnapshot &avg_snap) { + return AerToPy::from_avg_snap(std::move(avg_snap)); +} + +template +py::object AerToPy::from_avg_snap(AER::AverageSnapshot &&avg_snap) { + py::dict d; + for (auto &outer_pair : avg_snap.data()) { + py::list d1; + for (auto &inner_pair : outer_pair.second) { + // Store mean and variance for snapshot + py::dict datum = AerToPy::from_avg_data(inner_pair.second); + // Add memory key if there are classical registers + auto memory = inner_pair.first; + if ( ! memory.empty()) { + datum["memory"] = inner_pair.first; + } + // Add to list of output + d1.append(std::move(datum)); + } + d[outer_pair.first.data()] = std::move(d1); + } + return std::move(d); +} + +template +py::object AerToPy::from_pershot_snap(AER::PershotSnapshot &snap) { + return AerToPy::from_pershot_snap(std::move(snap)); +} +template +py::object AerToPy::from_pershot_snap(AER::PershotSnapshot &&snap) { + py::dict d; + // string PershotData + for (auto &pair : snap.data()) + d[pair.first.data()] = AerToPy::from_pershot_data(pair.second); + return std::move(d); +} + +template +py::object AerToPy::from_pershot_data(AER::PershotData &&data) { + return py::cast(data.data(), py::return_value_policy::move); +} + +template +py::object AerToPy::from_pershot_data(AER::PershotData &data) { + return AerToPy::from_pershot_data(std::move(data)); +} + +template<> +py::object AerToPy::from_pershot_data(AER::PershotData &&data) { + py::object tmp; + from_json(data.data(), tmp); + return tmp; +} + +template +py::object AerToPy::from_pershot_data(AER::PershotData> &&data) { + py::list l; + for (auto &item : data.data()) { + l.append(AerToPy::to_numpy(std::move(item))); + } + return std::move(l); +} + +template +py::object AerToPy::from_pershot_data(AER::PershotData> &data) { + return AerToPy::from_pershot_data(std::move(data)); +} + + + +template +py::object AerToPy::from_pershot_data(AER::PershotData> &&data) { + py::list l; + for (auto &item : data.data()) { + l.append(AerToPy::to_numpy(std::move(item))); + } + return std::move(l); +} + +template +py::object AerToPy::from_pershot_data(AER::PershotData> &data) { + return AerToPy::from_pershot_data(std::move(data)); +} + + + +template +py::object AerToPy::from_pershot_data(AER::PershotData> &&data) { + py::list l; + for (auto &item : data.data()) { + l.append(AerToPy::to_numpy(std::move(item))); + } + return std::move(l); +} + +template +py::object AerToPy::from_pershot_data(AER::PershotData> &data) { + return AerToPy::from_pershot_data(std::move(data)); +} + + +py::object AerToPy::from_data(AER::ExperimentData &datum) { + return AerToPy::from_data(std::move(datum)); +} + +py::object AerToPy::from_data(AER::ExperimentData &&datum) { + py::dict pydata; + + // Measure data + if (datum.return_counts_ && ! datum.counts_.empty()) { + pydata["counts"] = std::move(datum.counts_); + } + if (datum.return_memory_ && ! datum.memory_.empty()) { + pydata["memory"] = std::move(datum.memory_); + } + if (datum.return_register_ && ! datum.register_.empty()) { + pydata["register"] = std::move(datum.register_); + } + + // Add additional data + for (auto &pair : datum.additional_data()) { + py::object tmp; + from_json(pair.second, tmp); + pydata[pair.first.data()] = std::move(tmp); + } + for (auto &pair : datum.additional_data>()) { + pydata[pair.first.data()] = pair.second; + } + for (auto &pair : datum.additional_data>>()) { + pydata[pair.first.data()] = AerToPy::to_numpy(std::move(pair.second)); + } + for (auto &pair : datum.additional_data>>()) { + pydata[pair.first.data()] = AerToPy::to_numpy(std::move(pair.second)); + } + for (auto &pair : datum.additional_data>>()) { + pydata[pair.first.data()] = AerToPy::to_numpy(std::move(pair.second)); + } + for (auto &pair : datum.additional_data>>()) { + pydata[pair.first.data()] = AerToPy::to_numpy(std::move(pair.second)); + } + for (auto &pair : datum.additional_data>>()) { + pydata[pair.first.data()] = AerToPy::to_numpy(std::move(pair.second)); + } + for (auto &pair : datum.additional_data>>()) { + pydata[pair.first.data()] = AerToPy::to_numpy(std::move(pair.second)); + } + for (auto &pair : datum.additional_data>>()) { + pydata[pair.first.data()] = pair.second; + } + for (auto &pair : datum.additional_data>()) { + pydata[pair.first.data()] = pair.second; + } + + // Snapshot data + if (datum.return_snapshots_) { + py::dict snapshots; + + // Average snapshots + for (auto &pair : datum.average_snapshots()) { + snapshots[pair.first.data()] = AerToPy::from_avg_snap(pair.second); + } + for (auto &pair : datum.average_snapshots>()) { + snapshots[pair.first.data()] = AerToPy::from_avg_snap(pair.second); + } + for (auto &pair : datum.average_snapshots>>()) { + snapshots[pair.first.data()] = AerToPy::from_avg_snap(pair.second); + } + for (auto &pair : datum.average_snapshots>>()) { + snapshots[pair.first.data()] = AerToPy::from_avg_snap(pair.second); + } + for (auto &pair : datum.average_snapshots>>()) { + snapshots[pair.first.data()] = AerToPy::from_avg_snap(pair.second); + } + for (auto &pair : datum.average_snapshots>>()) { + snapshots[pair.first.data()] = AerToPy::from_avg_snap(pair.second); + } + for (auto &pair : datum.average_snapshots>>()) { + snapshots[pair.first.data()] = AerToPy::from_avg_snap(pair.second); + } + for (auto &pair : datum.average_snapshots>>()) { + snapshots[pair.first.data()] = AerToPy::from_avg_snap(pair.second); + } + for (auto &pair : datum.average_snapshots>>()) { + snapshots[pair.first.data()] = AerToPy::from_avg_snap(pair.second); + } + for (auto &pair : datum.average_snapshots>()) { + snapshots[pair.first.data()] = AerToPy::from_avg_snap(pair.second); + } + // Singleshot snapshot data + // Note these will override the average snapshots + // if they share the same type string + + for (auto &pair : datum.pershot_snapshots()) { + snapshots[pair.first.data()] = AerToPy::from_pershot_snap(pair.second); + } + for (auto &pair : datum.pershot_snapshots>()) { + snapshots[pair.first.data()] = AerToPy::from_pershot_snap(pair.second); + } + for (auto &pair : datum.pershot_snapshots>>()) { + snapshots[pair.first.data()] = AerToPy::from_pershot_snap(pair.second); + } + for (auto &pair : datum.pershot_snapshots>>()) { + snapshots[pair.first.data()] = AerToPy::from_pershot_snap(pair.second); + } + for (auto &pair : datum.pershot_snapshots>>()) { + snapshots[pair.first.data()] = AerToPy::from_pershot_snap(pair.second); + } + for (auto &pair : datum.pershot_snapshots>>()) { + snapshots[pair.first.data()] = AerToPy::from_pershot_snap(pair.second); + } + for (auto &pair : datum.pershot_snapshots>>()) { + snapshots[pair.first.data()] = AerToPy::from_pershot_snap(pair.second); + } + for (auto &pair : datum.pershot_snapshots>>()) { + snapshots[pair.first.data()] = AerToPy::from_pershot_snap(pair.second); + } + for (auto &pair : datum.pershot_snapshots>>()) { + snapshots[pair.first.data()] = AerToPy::from_pershot_snap(pair.second); + } + for (auto &pair : datum.pershot_snapshots>()) { + snapshots[pair.first.data()] = AerToPy::from_pershot_snap(pair.second); + } + + if ( py::len(snapshots) != 0 ) + pydata["snapshots"] = std::move(snapshots); + } + //for (auto item : pydatum) + // py::print(" {}:, {}"_s.format(item.first, item.second)); + return std::move(pydata); +} + +#endif diff --git a/src/framework/results/pybind_result.hpp b/src/framework/results/pybind_result.hpp new file mode 100755 index 0000000000..53ff410f50 --- /dev/null +++ b/src/framework/results/pybind_result.hpp @@ -0,0 +1,130 @@ +/** + * This code is part of Qiskit. + * + * (C) Copyright IBM 2018, 2019, 2020. + * + * 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. + */ + +#ifndef _aer_framework_result_pybind_result_hpp_ +#define _aer_framework_result_pybind_result_hpp_ + +#include "framework/pybind_basics.hpp" +#include "framework/results/pybind_data.hpp" +#include "framework/results/experiment_data.hpp" +#include "framework/results/result.hpp" + +//------------------------------------------------------------------------------ +// Aer C++ -> Python Conversion +//------------------------------------------------------------------------------ + +namespace AerToPy { + +// Move an ExperimentData object to a Python dict +template <> py::object to_python(AER::ExperimentData &&result); + +// Move an ExperimentResult object to a Python dict +template <> py::object to_python(AER::ExperimentResult &&result); + +// Move a Result object to a Python dict +template <> py::object to_python(AER::Result &&result); + +} //end namespace AerToPy + + +//============================================================================ +// Implementations +//============================================================================ + +template <> +py::object AerToPy::to_python(AER::ExperimentData &&datum) { + return AerToPy::from_data(std::move(datum)); +} + + +template <> +py::object AerToPy::to_python(AER::ExperimentResult &&result) { + py::dict pyexperiment; + + pyexperiment["shots"] = result.shots; + pyexperiment["seed_simulator"] = result.seed; + + pyexperiment["data"] = AerToPy::to_python(std::move(result.data)); + + pyexperiment["success"] = (result.status == AER::ExperimentResult::Status::completed); + switch (result.status) { + case AER::ExperimentResult::Status::completed: + pyexperiment["status"] = "DONE"; + break; + case AER::ExperimentResult::Status::error: + pyexperiment["status"] = std::string("ERROR: ") + result.message; + break; + case AER::ExperimentResult::Status::empty: + pyexperiment["status"] = "EMPTY"; + } + pyexperiment["time_taken"] = result.time_taken; + if (result.header.empty() == false) { + py::object tmp; + from_json(result.header, tmp); + pyexperiment["header"] = std::move(tmp); + } + if (result.metadata.empty() == false) { + py::object tmp; + from_json(result.metadata, tmp); + pyexperiment["metadata"] = std::move(tmp); + } + return std::move(pyexperiment); +} + + +template <> +py::object AerToPy::to_python(AER::Result &&result) { + py::dict pyresult; + pyresult["qobj_id"] = result.qobj_id; + + pyresult["backend_name"] = result.backend_name; + pyresult["backend_version"] = result.backend_version; + pyresult["date"] = result.date; + pyresult["job_id"] = result.job_id; + + py::list exp_results; + for(AER::ExperimentResult& exp : result.results) + exp_results.append(AerToPy::to_python(std::move(exp))); + pyresult["results"] = std::move(exp_results); + + // For header and metadata we continue using the json->pyobject casting + // bc these are assumed to be small relative to the ExperimentResults + if (result.header.empty() == false) { + py::object tmp; + from_json(result.header, tmp); + pyresult["header"] = std::move(tmp); + } + if (result.metadata.empty() == false) { + py::object tmp; + from_json(result.metadata, tmp); + pyresult["metadata"] = std::move(tmp); + } + pyresult["success"] = (result.status == AER::Result::Status::completed); + switch (result.status) { + case AER::Result::Status::completed: + pyresult["status"] = "COMPLETED"; + break; + case AER::Result::Status::partial_completed: + pyresult["status"] = "PARTIAL COMPLETED"; + break; + case AER::Result::Status::error: + pyresult["status"] = std::string("ERROR: ") + result.message; + break; + case AER::Result::Status::empty: + pyresult["status"] = "EMPTY"; + } + return std::move(pyresult); +} + +#endif From b12f6258ef560e1f4c12dcccdec04003c39f6372 Mon Sep 17 00:00:00 2001 From: "Christopher J. Wood" Date: Tue, 6 Oct 2020 12:34:44 -0400 Subject: [PATCH 012/126] Use move semantics when snapshot is final circuit instruction (#975) * Add final_ops flag to State apply_ops function If True this flag indicates that no more instructions will be applied to the state so that it does not need to be preserved after the instructions are applied. This is, for example, to allow a final snapshot instruction to move the state to results rather than copy, or measurement sampling to modify the state. --- ...move-final-snapshots-1cdc5e93b4695324.yaml | 9 ++ src/controllers/qasm_controller.hpp | 5 +- .../density_matrix/densitymatrix_state.hpp | 120 ++++++++++-------- .../extended_stabilizer_state.hpp | 5 +- .../matrix_product_state.hpp | 5 +- .../stabilizer/stabilizer_state.hpp | 5 +- src/simulators/state.hpp | 6 +- .../statevector/statevector_state.hpp | 29 +++-- .../superoperator/superoperator_state.hpp | 8 +- src/simulators/unitary/unitary_state.hpp | 8 +- 10 files changed, 122 insertions(+), 78 deletions(-) create mode 100644 releasenotes/notes/move-final-snapshots-1cdc5e93b4695324.yaml diff --git a/releasenotes/notes/move-final-snapshots-1cdc5e93b4695324.yaml b/releasenotes/notes/move-final-snapshots-1cdc5e93b4695324.yaml new file mode 100644 index 0000000000..eacd528ce9 --- /dev/null +++ b/releasenotes/notes/move-final-snapshots-1cdc5e93b4695324.yaml @@ -0,0 +1,9 @@ +--- +features: + - | + Use move semantics for statevector and density matrix snapshots for the + `"statevector"` and `"density_matrix"` methods of the + :class:`~qiskit.providers.aer.QasmSimulator` if they are the final + instruction in a circuit. This reduces the memory usage of the + simulator improves the performance by avoiding copying a large array in + the results. diff --git a/src/controllers/qasm_controller.hpp b/src/controllers/qasm_controller.hpp index a9669ab14b..9c3431db56 100755 --- a/src/controllers/qasm_controller.hpp +++ b/src/controllers/qasm_controller.hpp @@ -942,7 +942,7 @@ void QasmController::run_single_shot(const Circuit& circ, ExperimentData& data, RngEngine& rng) const { initialize_state(circ, state, initial_state); - state.apply_ops(circ.ops, data, rng); + state.apply_ops(circ.ops, data, rng, true); state.add_creg_to_data(data); } @@ -962,8 +962,9 @@ void QasmController::run_multi_shot(const Circuit& circ, // Run circuit instructions before first measure std::vector ops(circ.ops.begin(), circ.ops.begin() + pos); + bool final_ops = (pos == circ.ops.size()); initialize_state(circ, state, initial_state); - state.apply_ops(ops, data, rng); + state.apply_ops(ops, data, rng, final_ops); // Get measurement operations and set of measured qubits ops = std::vector(circ.ops.begin() + pos, diff --git a/src/simulators/density_matrix/densitymatrix_state.hpp b/src/simulators/density_matrix/densitymatrix_state.hpp index e394ea801e..0dbabec1f6 100644 --- a/src/simulators/density_matrix/densitymatrix_state.hpp +++ b/src/simulators/density_matrix/densitymatrix_state.hpp @@ -89,7 +89,9 @@ 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. virtual void apply_ops(const std::vector &ops, - ExperimentData &data, RngEngine &rng) override; + ExperimentData &data, + RngEngine &rng, + bool final_ops = false) override; // Initializes an n-qubit state to the all |0> state virtual void initialize_qreg(uint_t num_qubits) override; @@ -148,7 +150,9 @@ class State : public Base::State { // Apply a supported snapshot instruction // If the input is not in allowed_snapshots an exeption will be raised. - virtual void apply_snapshot(const Operations::Op &op, ExperimentData &data); + virtual void apply_snapshot(const Operations::Op &op, + ExperimentData &data, + bool last_op = false); // Apply a matrix to given qubits (identity on all other qubits) void apply_matrix(const reg_t &qubits, const cmatrix_t &mat); @@ -194,8 +198,10 @@ class State : public Base::State { //----------------------------------------------------------------------- // Snapshot reduced density matrix - void snapshot_density_matrix(const Operations::Op &op, ExperimentData &data); - + void snapshot_density_matrix(const Operations::Op &op, + ExperimentData &data, + bool last_op = false); + // Snapshot current qubit probabilities for a measurement (average) void snapshot_probabilities(const Operations::Op &op, ExperimentData &data, bool variance); @@ -386,48 +392,50 @@ void State::set_config(const json_t &config) { template void State::apply_ops(const std::vector &ops, - ExperimentData &data, RngEngine &rng) { + ExperimentData &data, + RngEngine &rng, + bool final_ops) { // Simple loop over vector of input operations - for (const auto &op: ops) { + for (size_t i = 0; i < ops.size(); ++i) { + const auto& op = ops[i]; // If conditional op check conditional if (BaseState::creg_.check_conditional(op)) { switch (op.type) { - case Operations::OpType::barrier: - break; - case Operations::OpType::reset: - apply_reset(op.qubits); - break; - case Operations::OpType::measure: - apply_measure(op.qubits, op.memory, op.registers, rng); - break; - case Operations::OpType::bfunc: - BaseState::creg_.apply_bfunc(op); - break; - case Operations::OpType::roerror: - BaseState::creg_.apply_roerror(op, rng); - break; - case Operations::OpType::gate: - apply_gate(op); - break; - case Operations::OpType::snapshot: - apply_snapshot(op, data); - break; - case Operations::OpType::matrix: - apply_matrix(op.qubits, op.mats[0]); - break; - case Operations::OpType::diagonal_matrix: - BaseState::qreg_.apply_diagonal_unitary_matrix(op.qubits, op.params); - break; - case Operations::OpType::superop: - BaseState::qreg_.apply_superop_matrix( - op.qubits, Utils::vectorize_matrix(op.mats[0])); - break; - case Operations::OpType::kraus: - apply_kraus(op.qubits, op.mats); - break; - default: - throw std::invalid_argument( - "DensityMatrix::State::invalid instruction \'" + op.name + "\'."); + case Operations::OpType::barrier: + break; + case Operations::OpType::reset: + apply_reset(op.qubits); + break; + case Operations::OpType::measure: + apply_measure(op.qubits, op.memory, op.registers, rng); + break; + case Operations::OpType::bfunc: + BaseState::creg_.apply_bfunc(op); + break; + case Operations::OpType::roerror: + BaseState::creg_.apply_roerror(op, rng); + break; + case Operations::OpType::gate: + apply_gate(op); + break; + case Operations::OpType::snapshot: + apply_snapshot(op, data, final_ops && ops.size() == i + 1); + break; + case Operations::OpType::matrix: + apply_matrix(op.qubits, op.mats[0]); + break; + case Operations::OpType::diagonal_matrix: + BaseState::qreg_.apply_diagonal_unitary_matrix(op.qubits, op.params); + break; + case Operations::OpType::superop: + BaseState::qreg_.apply_superop_matrix(op.qubits, Utils::vectorize_matrix(op.mats[0])); + break; + case Operations::OpType::kraus: + apply_kraus(op.qubits, op.mats); + break; + default: + throw std::invalid_argument("DensityMatrix::State::invalid instruction \'" + + op.name + "\'."); } } } @@ -439,7 +447,8 @@ void State::apply_ops(const std::vector &ops, template void State::apply_snapshot(const Operations::Op &op, - ExperimentData &data) { + ExperimentData &data, + bool last_op) { // Look for snapshot type in snapshotset auto it = snapshotset_.find(op.name); @@ -449,7 +458,7 @@ void State::apply_snapshot(const Operations::Op &op, "\'."); switch (it->second) { case Snapshots::densitymatrix: - snapshot_density_matrix(op, data); + snapshot_density_matrix(op, data, last_op); break; case Snapshots::cmemory: BaseState::snapshot_creg_memory(op, data); @@ -492,10 +501,13 @@ void State::snapshot_probabilities(const Operations::Op &op, ExperimentData &data, bool variance) { // get probs as hexadecimal - auto probs = - Utils::vec2ket(measure_probs(op.qubits), json_chop_threshold_, 16); - data.add_average_snapshot("probabilities", op.string_params[0], - BaseState::creg_.memory_hex(), probs, variance); + auto probs = Utils::vec2ket(measure_probs(op.qubits), + json_chop_threshold_, 16); + data.add_average_snapshot("probabilities", + op.string_params[0], + BaseState::creg_.memory_hex(), + std::move(probs), + variance); } template @@ -524,7 +536,8 @@ void State::snapshot_pauli_expval(const Operations::Op &op, template void State::snapshot_density_matrix(const Operations::Op &op, - ExperimentData &data) { + ExperimentData &data, + bool last_op) { cmatrix_t reduced_state; // Check if tracing over all qubits @@ -536,9 +549,12 @@ void State::snapshot_density_matrix(const Operations::Op &op, auto qubits_sorted = op.qubits; std::sort(qubits_sorted.begin(), qubits_sorted.end()); - if ((op.qubits.size() == BaseState::qreg_.num_qubits()) && - (op.qubits == qubits_sorted)) { - reduced_state = BaseState::qreg_.copy_to_matrix(); + if ((op.qubits.size() == BaseState::qreg_.num_qubits()) && (op.qubits == qubits_sorted)) { + if (last_op) { + reduced_state = BaseState::qreg_.move_to_matrix(); + } else { + reduced_state = BaseState::qreg_.copy_to_matrix(); + } } else { reduced_state = reduced_density_matrix(op.qubits, qubits_sorted); } diff --git a/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp b/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp index 0099e5b7a1..b589358e05 100644 --- a/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp +++ b/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp @@ -74,7 +74,8 @@ class State: public Base::State //we loop over the terms in the decomposition in parallel virtual void apply_ops(const std::vector &ops, ExperimentData &data, - RngEngine &rng) override; + RngEngine &rng, + bool final_ops = false) override; virtual void initialize_qreg(uint_t num_qubits) override; @@ -316,7 +317,7 @@ bool State::check_measurement_opt(const std::vector &ops) const //------------------------------------------------------------------------- void State::apply_ops(const std::vector &ops, ExperimentData &data, - RngEngine &rng) + RngEngine &rng, bool final_ops) { std::pair stabilizer_opts = check_stabilizer_opt(ops); bool is_stabilizer = stabilizer_opts.first; diff --git a/src/simulators/matrix_product_state/matrix_product_state.hpp b/src/simulators/matrix_product_state/matrix_product_state.hpp index a6e1c39f12..fc72af7d0a 100644 --- a/src/simulators/matrix_product_state/matrix_product_state.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state.hpp @@ -104,7 +104,8 @@ class State : public Base::State { // 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; + RngEngine &rng, + bool final_ops = false) override; // Initializes an n-qubit state to the all |0> state virtual void initialize_qreg(uint_t num_qubits) override; @@ -444,7 +445,7 @@ void State::add_metadata(ExperimentData &data) const { void State::apply_ops(const std::vector &ops, ExperimentData &data, - RngEngine &rng) { + RngEngine &rng, bool final_ops) { // Simple loop over vector of input operations for (const auto &op: ops) { diff --git a/src/simulators/stabilizer/stabilizer_state.hpp b/src/simulators/stabilizer/stabilizer_state.hpp index 286f612cfb..e73079f5e8 100644 --- a/src/simulators/stabilizer/stabilizer_state.hpp +++ b/src/simulators/stabilizer/stabilizer_state.hpp @@ -80,7 +80,8 @@ class State : public Base::State { // If the input is not in allowed_ops an exeption will be raised. virtual void apply_ops(const std::vector &ops, ExperimentData &data, - RngEngine &rng) override; + RngEngine &rng, + bool final_ops = false) override; // Initializes an n-qubit state to the all |0> state virtual void initialize_qreg(uint_t num_qubits) override; @@ -276,7 +277,7 @@ void State::set_config(const json_t &config) { void State::apply_ops(const std::vector &ops, ExperimentData &data, - RngEngine &rng) { + RngEngine &rng, bool final_ops) { // Simple loop over vector of input operations for (const auto &op: ops) { if(BaseState::creg_.check_conditional(op)) { diff --git a/src/simulators/state.hpp b/src/simulators/state.hpp index 1860549fc9..3df92e4b1e 100644 --- a/src/simulators/state.hpp +++ b/src/simulators/state.hpp @@ -104,9 +104,13 @@ class State { // executed (ie in sequence, or some other execution strategy.) // If this sequence contains operations not in the supported opset // an exeption will be thrown. + // The `final_ops` flag indicates no more instructions will be applied + // to the state after this sequence, so the state can be modified at the + // end of the instructions. virtual void apply_ops(const std::vector &ops, ExperimentData &data, - RngEngine &rng) = 0; + RngEngine &rng, + bool final_ops = false) = 0; // Initializes the State to the default state. // Typically this is the n-qubit all |0> state diff --git a/src/simulators/statevector/statevector_state.hpp b/src/simulators/statevector/statevector_state.hpp index 3429c85140..daeecf89bb 100755 --- a/src/simulators/statevector/statevector_state.hpp +++ b/src/simulators/statevector/statevector_state.hpp @@ -104,7 +104,9 @@ class State : public Base::State { // Apply a sequence of operations by looping over list // 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; + ExperimentData &data, + RngEngine &rng, + bool final_ops = false) override; // Initializes an n-qubit state to the all |0> state virtual void initialize_qreg(uint_t num_qubits) override; @@ -169,7 +171,7 @@ class State : public Base::State { // Apply a supported snapshot instruction // If the input is not in allowed_snapshots an exeption will be raised. - virtual void apply_snapshot(const Operations::Op &op, ExperimentData &data); + virtual void apply_snapshot(const Operations::Op &op, ExperimentData &data, bool last_op = false); // Apply a matrix to given qubits (identity on all other qubits) void apply_matrix(const Operations::Op &op); @@ -226,10 +228,6 @@ class State : public Base::State { // should be left in the pre-snapshot state. //----------------------------------------------------------------------- - // Snapshot current amplitudes - void snapshot_statevector(const Operations::Op &op, ExperimentData &data, - SnapshotDataType type); - // Snapshot current qubit probabilities for a measurement (average) void snapshot_probabilities(const Operations::Op &op, ExperimentData &data, SnapshotDataType type); @@ -466,10 +464,13 @@ void State::set_config(const json_t &config) { template void State::apply_ops(const std::vector &ops, - ExperimentData &data, RngEngine &rng) { + ExperimentData &data, + RngEngine &rng, + bool final_ops) { // Simple loop over vector of input operations - for (const auto &op: ops) { + for (size_t i = 0; i < ops.size(); ++i) { + const auto& op = ops[i]; if(BaseState::creg_.check_conditional(op)) { switch (op.type) { case Operations::OpType::barrier: @@ -493,7 +494,7 @@ void State::apply_ops(const std::vector &ops, apply_gate(op); break; case Operations::OpType::snapshot: - apply_snapshot(op, data); + apply_snapshot(op, data, final_ops && ops.size() == i + 1); break; case Operations::OpType::matrix: apply_matrix(op); @@ -522,7 +523,8 @@ void State::apply_ops(const std::vector &ops, template void State::apply_snapshot(const Operations::Op &op, - ExperimentData &data) { + ExperimentData &data, + bool last_op) { // Look for snapshot type in snapshotset auto it = snapshotset_.find(op.name); @@ -531,8 +533,11 @@ void State::apply_snapshot(const Operations::Op &op, "QubitVectorState::invalid snapshot instruction \'" + op.name + "\'."); switch (it->second) { case Snapshots::statevector: - data.add_pershot_snapshot("statevector", op.string_params[0], - BaseState::qreg_.vector()); + if (last_op) { + data.add_pershot_snapshot("statevector", op.string_params[0], BaseState::qreg_.move_to_vector()); + } else { + data.add_pershot_snapshot("statevector", op.string_params[0], BaseState::qreg_.copy_to_vector()); + } break; case Snapshots::cmemory: BaseState::snapshot_creg_memory(op, data); diff --git a/src/simulators/superoperator/superoperator_state.hpp b/src/simulators/superoperator/superoperator_state.hpp index c3a056406a..e7a48fee82 100755 --- a/src/simulators/superoperator/superoperator_state.hpp +++ b/src/simulators/superoperator/superoperator_state.hpp @@ -73,7 +73,9 @@ 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. virtual void apply_ops(const std::vector &ops, - ExperimentData &data, RngEngine &rng) override; + ExperimentData &data, + RngEngine &rng, + bool final_ops = false) override; // Initializes an n-qubit unitary to the identity matrix virtual void initialize_qreg(uint_t num_qubits) override; @@ -207,7 +209,9 @@ const stringmap_t State::gateset_({ template void State::apply_ops(const std::vector &ops, - ExperimentData &data, RngEngine &rng) { + ExperimentData &data, + RngEngine &rng, + bool final_ops) { // Simple loop over vector of input operations for (const auto &op: ops) { switch (op.type) { diff --git a/src/simulators/unitary/unitary_state.hpp b/src/simulators/unitary/unitary_state.hpp index ebb4898095..74d47cf065 100755 --- a/src/simulators/unitary/unitary_state.hpp +++ b/src/simulators/unitary/unitary_state.hpp @@ -74,7 +74,8 @@ 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. virtual void apply_ops(const std::vector &ops, - ExperimentData &data, RngEngine &rng) override; + ExperimentData &data, RngEngine &rng, + bool final_ops = false) override; // Initializes an n-qubit unitary to the identity matrix virtual void initialize_qreg(uint_t num_qubits) override; @@ -228,8 +229,9 @@ const stringmap_t State::gateset_({ //============================================================================ template -void State::apply_ops(const std::vector &ops, - ExperimentData &data, RngEngine &rng) { +void State::apply_ops( + const std::vector &ops, ExperimentData &data, + RngEngine &rng, bool final_ops) { // Simple loop over vector of input operations for (const auto &op : ops) { switch (op.type) { From f6b6a4e477f92bb368f3952194edd73524498772 Mon Sep 17 00:00:00 2001 From: "Christopher J. Wood" Date: Thu, 8 Oct 2020 10:50:32 -0400 Subject: [PATCH 013/126] Remove absolute imports from qiskit.provider.aer (#980) Qiskit/qiskit-terra#5086 seemd to break pylint testing by preventing the Aer package from being found by pylint without building and installing. This fixes the issue by replacing all absolute imports in Aer with relative module imports. This is a work around until general namespace packaging issues are implemented to move all of Aer into its own namespace. --- qiskit/providers/aer/backends/qasm_simulator.py | 4 ++-- qiskit/providers/aer/backends/statevector_simulator.py | 4 ++-- qiskit/providers/aer/backends/unitary_simulator.py | 4 ++-- qiskit/providers/aer/extensions/snapshot_density_matrix.py | 2 +- qiskit/providers/aer/extensions/snapshot_expectation_value.py | 2 +- qiskit/providers/aer/extensions/snapshot_probabilities.py | 2 +- qiskit/providers/aer/extensions/snapshot_stabilizer.py | 2 +- qiskit/providers/aer/extensions/snapshot_statevector.py | 2 +- qiskit/providers/aer/noise/device/basic_device_model.py | 2 +- qiskit/providers/aer/noise/noise_model.py | 4 ++-- qiskit/providers/aer/pulse/controllers/digest_pulse_qobj.py | 2 +- qiskit/providers/aer/pulse/system_models/hamiltonian_model.py | 2 +- .../providers/aer/pulse/system_models/pulse_system_model.py | 2 +- 13 files changed, 17 insertions(+), 17 deletions(-) diff --git a/qiskit/providers/aer/backends/qasm_simulator.py b/qiskit/providers/aer/backends/qasm_simulator.py index 5f960a3cce..f652d4a052 100644 --- a/qiskit/providers/aer/backends/qasm_simulator.py +++ b/qiskit/providers/aer/backends/qasm_simulator.py @@ -18,9 +18,9 @@ from qiskit.util import local_hardware_info from qiskit.providers.models import QasmBackendConfiguration from .aerbackend import AerBackend -# pylint: disable=import-error -from .controller_wrappers import qasm_controller_execute from ..version import __version__ +# pylint: disable=import-error,no-name-in-module +from .controller_wrappers import qasm_controller_execute logger = logging.getLogger(__name__) diff --git a/qiskit/providers/aer/backends/statevector_simulator.py b/qiskit/providers/aer/backends/statevector_simulator.py index cf2b97bdaa..20733023c7 100644 --- a/qiskit/providers/aer/backends/statevector_simulator.py +++ b/qiskit/providers/aer/backends/statevector_simulator.py @@ -19,10 +19,10 @@ from qiskit.util import local_hardware_info from qiskit.providers.models import QasmBackendConfiguration from .aerbackend import AerBackend -# pylint: disable=import-error -from .controller_wrappers import statevector_controller_execute from ..aererror import AerError from ..version import __version__ +# pylint: disable=import-error,no-name-in-module +from .controller_wrappers import statevector_controller_execute # Logger logger = logging.getLogger(__name__) diff --git a/qiskit/providers/aer/backends/unitary_simulator.py b/qiskit/providers/aer/backends/unitary_simulator.py index 1b6324af03..c667c51393 100644 --- a/qiskit/providers/aer/backends/unitary_simulator.py +++ b/qiskit/providers/aer/backends/unitary_simulator.py @@ -22,9 +22,9 @@ from .aerbackend import AerBackend from ..aererror import AerError -# pylint: disable=import-error -from .controller_wrappers import unitary_controller_execute from ..version import __version__ +# pylint: disable=import-error,no-name-in-module +from .controller_wrappers import unitary_controller_execute # Logger logger = logging.getLogger(__name__) diff --git a/qiskit/providers/aer/extensions/snapshot_density_matrix.py b/qiskit/providers/aer/extensions/snapshot_density_matrix.py index 3f7434268f..bbac3f23f4 100644 --- a/qiskit/providers/aer/extensions/snapshot_density_matrix.py +++ b/qiskit/providers/aer/extensions/snapshot_density_matrix.py @@ -15,7 +15,7 @@ """ from qiskit import QuantumCircuit -from qiskit.providers.aer.extensions import Snapshot +from .snapshot import Snapshot class SnapshotDensityMatrix(Snapshot): diff --git a/qiskit/providers/aer/extensions/snapshot_expectation_value.py b/qiskit/providers/aer/extensions/snapshot_expectation_value.py index 4572fdc9a2..375258ed48 100644 --- a/qiskit/providers/aer/extensions/snapshot_expectation_value.py +++ b/qiskit/providers/aer/extensions/snapshot_expectation_value.py @@ -21,7 +21,7 @@ from qiskit.extensions.exceptions import ExtensionError from qiskit.qobj import QasmQobjInstruction from qiskit.quantum_info.operators import Pauli, Operator -from qiskit.providers.aer.extensions import Snapshot +from .snapshot import Snapshot class SnapshotExpectationValue(Snapshot): diff --git a/qiskit/providers/aer/extensions/snapshot_probabilities.py b/qiskit/providers/aer/extensions/snapshot_probabilities.py index 7686c565ce..7f9b64ba65 100644 --- a/qiskit/providers/aer/extensions/snapshot_probabilities.py +++ b/qiskit/providers/aer/extensions/snapshot_probabilities.py @@ -16,7 +16,7 @@ from warnings import warn from qiskit import QuantumCircuit -from qiskit.providers.aer.extensions import Snapshot +from .snapshot import Snapshot class SnapshotProbabilities(Snapshot): diff --git a/qiskit/providers/aer/extensions/snapshot_stabilizer.py b/qiskit/providers/aer/extensions/snapshot_stabilizer.py index 86ce2ca5c8..8065824e24 100644 --- a/qiskit/providers/aer/extensions/snapshot_stabilizer.py +++ b/qiskit/providers/aer/extensions/snapshot_stabilizer.py @@ -15,7 +15,7 @@ """ from qiskit import QuantumCircuit -from qiskit.providers.aer.extensions import Snapshot +from .snapshot import Snapshot class SnapshotStabilizer(Snapshot): diff --git a/qiskit/providers/aer/extensions/snapshot_statevector.py b/qiskit/providers/aer/extensions/snapshot_statevector.py index 19bf1550d1..901adf3148 100644 --- a/qiskit/providers/aer/extensions/snapshot_statevector.py +++ b/qiskit/providers/aer/extensions/snapshot_statevector.py @@ -15,7 +15,7 @@ """ from qiskit import QuantumCircuit -from qiskit.providers.aer.extensions import Snapshot +from .snapshot import Snapshot class SnapshotStatevector(Snapshot): diff --git a/qiskit/providers/aer/noise/device/basic_device_model.py b/qiskit/providers/aer/noise/device/basic_device_model.py index c6d752430a..523297d95d 100644 --- a/qiskit/providers/aer/noise/device/basic_device_model.py +++ b/qiskit/providers/aer/noise/device/basic_device_model.py @@ -116,7 +116,7 @@ def basic_device_noise_model(properties, # This wrapper is for the deprecated function # We need to import noise model here to avoid cyclic import errors # pylint: disable=import-outside-toplevel - from qiskit.providers.aer.noise.noise_model import NoiseModel + from ..noise_model import NoiseModel return NoiseModel.from_backend(properties, gate_error=gate_error, readout_error=readout_error, diff --git a/qiskit/providers/aer/noise/noise_model.py b/qiskit/providers/aer/noise/noise_model.py index 419f771a93..d8fd2ad950 100644 --- a/qiskit/providers/aer/noise/noise_model.py +++ b/qiskit/providers/aer/noise/noise_model.py @@ -21,8 +21,8 @@ from qiskit.providers import BaseBackend from qiskit.providers.models import BackendProperties -from qiskit.providers.aer.backends.aerbackend import AerJSONEncoder -from qiskit.providers.aer.backends.qasm_simulator import QasmSimulator +from ..backends.aerbackend import AerJSONEncoder +from ..backends.qasm_simulator import QasmSimulator from .noiseerror import NoiseError from .errors.quantum_error import QuantumError diff --git a/qiskit/providers/aer/pulse/controllers/digest_pulse_qobj.py b/qiskit/providers/aer/pulse/controllers/digest_pulse_qobj.py index 35d6484db9..d840bfb29e 100644 --- a/qiskit/providers/aer/pulse/controllers/digest_pulse_qobj.py +++ b/qiskit/providers/aer/pulse/controllers/digest_pulse_qobj.py @@ -18,7 +18,7 @@ from collections import OrderedDict import numpy as np -from qiskit.providers.aer.aererror import AerError +from ...aererror import AerError # pylint: disable=no-name-in-module from .pulse_utils import oplist_to_array diff --git a/qiskit/providers/aer/pulse/system_models/hamiltonian_model.py b/qiskit/providers/aer/pulse/system_models/hamiltonian_model.py index 0cf3348d59..35fe8fdd1e 100644 --- a/qiskit/providers/aer/pulse/system_models/hamiltonian_model.py +++ b/qiskit/providers/aer/pulse/system_models/hamiltonian_model.py @@ -18,7 +18,7 @@ from collections import OrderedDict import numpy as np import numpy.linalg as la -from qiskit.providers.aer.aererror import AerError +from ...aererror import AerError from .string_model_parser.string_model_parser import HamiltonianParser diff --git a/qiskit/providers/aer/pulse/system_models/pulse_system_model.py b/qiskit/providers/aer/pulse/system_models/pulse_system_model.py index db139926da..1e02d1c0ab 100644 --- a/qiskit/providers/aer/pulse/system_models/pulse_system_model.py +++ b/qiskit/providers/aer/pulse/system_models/pulse_system_model.py @@ -18,7 +18,7 @@ from warnings import warn from collections import OrderedDict from qiskit.providers import BaseBackend -from qiskit.providers.aer.aererror import AerError +from ...aererror import AerError from .hamiltonian_model import HamiltonianModel From 8c81f3e6838fb0eb8e32e278e0d4c5aaf52ec773 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Thu, 8 Oct 2020 13:38:06 -0400 Subject: [PATCH 014/126] Update Code of Conduct (#978) IBM Quantum has rewritten the code of conduct to put in place a stronger enforcement process and tighten up the language. This commit updates the contents of CODE_OF_CONDUCT.md with this new version. Related to Qiskit/qiskit#1057 --- CODE_OF_CONDUCT.md | 143 +++++++++++++++++++++++++++++++++------------ 1 file changed, 105 insertions(+), 38 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index ec7c435994..159eca449b 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,46 +1,113 @@ -# Contributor Covenant Code of Conduct +# Code of Conduct ## Our Pledge -In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. +The Qiskit Community is dedicated to our values of treating every individual +with respect and dignity. In the interest of fostering an open and welcoming +environment, all participants, including attendees, speakers, sponsors, +volunteers, online contributors, and IBM employees are expected to show +courtesy for each other and our community by creating a harassment-free +experience for everyone, regardless of age, personal appearance, disability, +ethnicity, gender identity and expression, body size, level of experience, +nationality, race, religion, caste, or sexual identity and orientation. +Expected behavior applies to both online and offline engagement within the +Qiskit Community. ## Scope -This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at qiskit@qiskit.org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. +The purpose of this Code of Conduct is to define and enforce the values and +conduct of contributors and participants in the Qiskit open source community. +The Code of Conduct applies both within project spaces and in public spaces +when an individual is engaging with the Qiskit open source community. Examples +include attending a Qiskit event, contributing to online projects, commentary +on Slack, or representing a project or community, including using an official +project e-mail address, posting via an official social media account, or +acting as an appointed representative at an online or offline event. +Representation of a project may be further defined and clarified by project +maintainers. -Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] +## Our Standards -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ +Examples of behavior that contributes to creating a positive environment +include: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints, experiences, and cultures +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members +- Being mindful of your surroundings and your fellow participants and listening + to others +- Valuing the contributions of all participants +- Engaging in collaboration before conflict +- Pointing out unintentionally racist, sexist, casteist, or biased comments and + jokes made by community members when they happen + +Examples of unacceptable behavior by participants, even when presented as +"ironic" or "joking," include: + +- The use of sexualized language or imagery and unwelcome physical contact, + sexual attention, or advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment, including offensive or degrading language +- Publishing others' private information, such as a physical or electronic + address, without explicit permission. This includes any sort of "outing" of + any aspect of someone's identity without their consent. +- "Doxxing," Publishing screenshots or quotes, especially from identity slack + channels, private chat, or public events, without all quoted users' explicit + consent. +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Responsibilities & Enforcement + +The entire Qiskit community is responsible for upholding the terms of the Code +of Conduct in Qiskit Community events and spaces and reporting violations if +they see them. The internal Qiskit team at IBM is ultimately responsible for +clarifying the standards of acceptable behavior and enforcement, and is expected +to take appropriate and fair corrective action in response to any instances of +unacceptable behavior. + +If a participant or contributor engages in negative or harmful behavior, IBM +will take any action they deem appropriate, including but not limited to +issuing warnings, expulsion from an event with no refund, deleting comments, +permanent banning from future events or online community, or calling local law +enforcement. IBM has the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, or to temporarily or permanently ban any +contributor or participant for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +If you see a Code of Conduct violation: + +1. If you feel comfortable, let the person know that what they did is not + appropriate and ask them to stop and/or edit or delete their message(s) or + comment(s). +2. If the person does not immediately stop the behavior or correct the issue, + or if you're uncomfortable speaking up, flag a moderator and, if appropriate, + fill out the anonymous + [Code of Conduct violation form](https://airtable.com/shrl5mEF4Eun1aIDm). +3. The Qiskit Community will open an investigation upon receiving your form + entry. When reporting, please include any relevant details, links, + screenshots, context, or other information that may be used to better + understand and resolve the situation. +4. If the code of conduct violation occurs at an event and requires immediate + response or contains a concern about an individual attending an upcoming + event, contact the event's on-call Code of Conduct point of contact listed + in the event specific code of conduct document. If you don't feel comfortable + speaking to the point of contact in person, fill out a Code of Conduct + violation form entry and include the details of the event so that the Code of + Conduct enforcement board can contact the event's on-call Code of Conduct + point of contact. +5. If an IBM employee witnesses a Code of Conduct violation at any time, such as + at events, in a Slack channel, or open source forums, it is their + responsibility to file a Code of Conduct violation report. + +This Code of Conduct does not supersede existing IBM corporate policies, such as +the IBM Business Conduct Guidelines and IBM Business Partner Code of Conduct. +IBM employees must follow IBM's Business Conduct Guidelines. IBM's business +partners must follow the IBM Business Partner Code of Conduct. IBM employees +concerned with a fellow IBMer's behavior should follow IBM's own internal HR +reporting protocols, which include engaging the offending IBMer's manager and +involving IBM Concerns and Appeals. IBM employees concerned with an IBM +business partner's behavior should notify tellibm@us.ibm.com. From c2b82111dcfbbe945007575c1fd396cd48c61d71 Mon Sep 17 00:00:00 2001 From: "Christopher J. Wood" Date: Sat, 10 Oct 2020 11:52:38 -0400 Subject: [PATCH 015/126] Remove functions deprecated in Aer 0.4 (#984) --- qiskit/providers/aer/extensions/snapshot.py | 11 +- .../aer/extensions/snapshot_density_matrix.py | 2 +- .../extensions/snapshot_expectation_value.py | 2 +- .../aer/extensions/snapshot_probabilities.py | 2 +- .../aer/extensions/snapshot_stabilizer.py | 2 +- .../aer/extensions/snapshot_statevector.py | 2 +- qiskit/providers/aer/noise/__init__.py | 1 - qiskit/providers/aer/noise/device/__init__.py | 1 - .../aer/noise/device/basic_device_model.py | 127 --------- qiskit/providers/aer/noise/utils/__init__.py | 191 ------------- qiskit/providers/aer/utils/__init__.py | 2 - qiskit/providers/aer/utils/qobj_utils.py | 266 ------------------ 12 files changed, 10 insertions(+), 599 deletions(-) delete mode 100644 qiskit/providers/aer/noise/device/basic_device_model.py delete mode 100644 qiskit/providers/aer/noise/utils/__init__.py delete mode 100644 qiskit/providers/aer/utils/qobj_utils.py diff --git a/qiskit/providers/aer/extensions/snapshot.py b/qiskit/providers/aer/extensions/snapshot.py index 23539bacbb..d5cd6165fd 100644 --- a/qiskit/providers/aer/extensions/snapshot.py +++ b/qiskit/providers/aer/extensions/snapshot.py @@ -65,15 +65,14 @@ def inverse(self): @staticmethod def define_snapshot_register(circuit, - label, + label=None, qubits=None): """Defines qubits to snapshot for all snapshot methods""" # Convert label to string for backwards compatibility - if not isinstance(label, str): + if label is not None: warnings.warn( - "Snapshot label should be a string, " - "implicit conversion is deprecated.", DeprecationWarning) - label = str(label) + "The 'label' arg of `define_snapshot_register` has been deprecated" + "as of qiskit-aer 0.7.0.", DeprecationWarning) # If no qubits are specified we add all qubits so it acts as a barrier # This is needed for full register snapshots like statevector if isinstance(qubits, QuantumRegister): @@ -136,7 +135,7 @@ def snapshot(self, Raises: ExtensionError: malformed command """ - snapshot_register = Snapshot.define_snapshot_register(self, label, qubits) + snapshot_register = Snapshot.define_snapshot_register(self, qubits=qubits) return self.append( Snapshot( diff --git a/qiskit/providers/aer/extensions/snapshot_density_matrix.py b/qiskit/providers/aer/extensions/snapshot_density_matrix.py index bbac3f23f4..63a3196a94 100644 --- a/qiskit/providers/aer/extensions/snapshot_density_matrix.py +++ b/qiskit/providers/aer/extensions/snapshot_density_matrix.py @@ -51,7 +51,7 @@ def snapshot_density_matrix(self, label, qubits=None): ExtensionError: if snapshot is invalid. """ - snapshot_register = Snapshot.define_snapshot_register(self, label, qubits) + snapshot_register = Snapshot.define_snapshot_register(self, qubits=qubits) return self.append( SnapshotDensityMatrix(label, num_qubits=len(snapshot_register)), diff --git a/qiskit/providers/aer/extensions/snapshot_expectation_value.py b/qiskit/providers/aer/extensions/snapshot_expectation_value.py index 375258ed48..ee579a0bbc 100644 --- a/qiskit/providers/aer/extensions/snapshot_expectation_value.py +++ b/qiskit/providers/aer/extensions/snapshot_expectation_value.py @@ -142,7 +142,7 @@ def snapshot_expectation_value(self, label, op, qubits, ExtensionError: if snapshot is invalid. """ - snapshot_register = Snapshot.define_snapshot_register(self, label, qubits) + snapshot_register = Snapshot.define_snapshot_register(self, qubits=qubits) return self.append( SnapshotExpectationValue(label, op, diff --git a/qiskit/providers/aer/extensions/snapshot_probabilities.py b/qiskit/providers/aer/extensions/snapshot_probabilities.py index 7f9b64ba65..c209a45bfb 100644 --- a/qiskit/providers/aer/extensions/snapshot_probabilities.py +++ b/qiskit/providers/aer/extensions/snapshot_probabilities.py @@ -55,7 +55,7 @@ def snapshot_probabilities(self, label, qubits, variance=False): Raises: ExtensionError: if snapshot is invalid. """ - snapshot_register = Snapshot.define_snapshot_register(self, label, qubits) + snapshot_register = Snapshot.define_snapshot_register(self, qubits=qubits) return self.append( SnapshotProbabilities(label, diff --git a/qiskit/providers/aer/extensions/snapshot_stabilizer.py b/qiskit/providers/aer/extensions/snapshot_stabilizer.py index 8065824e24..97d8cb556d 100644 --- a/qiskit/providers/aer/extensions/snapshot_stabilizer.py +++ b/qiskit/providers/aer/extensions/snapshot_stabilizer.py @@ -59,7 +59,7 @@ def snapshot_stabilizer(self, label): qubits in the circuit. """ - snapshot_register = Snapshot.define_snapshot_register(self, label) + snapshot_register = Snapshot.define_snapshot_register(self) return self.append( SnapshotStabilizer(label, num_qubits=len(snapshot_register)), diff --git a/qiskit/providers/aer/extensions/snapshot_statevector.py b/qiskit/providers/aer/extensions/snapshot_statevector.py index 901adf3148..8c7a23a5d3 100644 --- a/qiskit/providers/aer/extensions/snapshot_statevector.py +++ b/qiskit/providers/aer/extensions/snapshot_statevector.py @@ -60,7 +60,7 @@ def snapshot_statevector(self, label): """ # Statevector snapshot acts as a barrier across all qubits in the # circuit - snapshot_register = Snapshot.define_snapshot_register(self, label) + snapshot_register = Snapshot.define_snapshot_register(self) return self.append( SnapshotStatevector(label, num_qubits=len(snapshot_register)), diff --git a/qiskit/providers/aer/noise/__init__.py b/qiskit/providers/aer/noise/__init__.py index f79b3faaf2..841019e7ec 100644 --- a/qiskit/providers/aer/noise/__init__.py +++ b/qiskit/providers/aer/noise/__init__.py @@ -195,4 +195,3 @@ # Submodules from . import errors from . import device -from . import utils diff --git a/qiskit/providers/aer/noise/device/__init__.py b/qiskit/providers/aer/noise/device/__init__.py index 76a778bd7c..658baf69c0 100644 --- a/qiskit/providers/aer/noise/device/__init__.py +++ b/qiskit/providers/aer/noise/device/__init__.py @@ -14,7 +14,6 @@ Functions for building noise models from backend properties. """ -from .basic_device_model import basic_device_noise_model from .models import basic_device_readout_errors from .models import basic_device_gate_errors from .parameters import gate_param_values diff --git a/qiskit/providers/aer/noise/device/basic_device_model.py b/qiskit/providers/aer/noise/device/basic_device_model.py deleted file mode 100644 index 523297d95d..0000000000 --- a/qiskit/providers/aer/noise/device/basic_device_model.py +++ /dev/null @@ -1,127 +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. -# pylint: disable=invalid-name,import-outside-toplevel -""" -Simplified noise models for devices backends. -""" - -import warnings - - -def basic_device_noise_model(properties, - gate_error=True, - readout_error=True, - thermal_relaxation=True, - temperature=0, - gate_lengths=None, - gate_length_units='ns', - standard_gates=True): - """ - Return a noise model derived from a devices backend properties. - - This function generates a noise model based on: - - * 1 and 2 qubit gate errors consisting of a - :func:`depolarizing_error` followed - by a :func:`thermal_relaxation_error`. - - * Single qubit :class:`ReadoutError` on all measurements. - - The Error error parameters are tuned for each individual qubit based on - the :math:`T_1`, :math:`T_2`, frequency and readout error parameters for - each qubit, and the gate error and gate time parameters for each gate - obtained from the device backend properties. - - **Additional Information** - - The noise model includes the following errors: - - * If ``readout_error=True`` include single qubit readout - errors on measurements. - - * If ``gate_error=True`` and ``thermal_relaxation=True`` include: - - * Single-qubit gate errors consisting of a :func:`depolarizing_error` - followed by a :func:`thermal_relaxation_error` for the qubit the - gate acts on. - - * Two-qubit gate errors consisting of a 2-qubit - :func:`depolarizing_error` followed by single qubit - :func:`thermal_relaxation_error` on each qubit participating in - the gate. - - * If ``gate_error=True`` is ``True`` and ``thermal_relaxation=False``: - - * An N-qubit :func:`depolarizing_error` on each N-qubit gate. - - * If ``gate_error=False`` and ``thermal_relaxation=True`` include - single-qubit :func:`thermal_relaxation_errors` on each qubits - participating in a multi-qubit gate. - - For best practice in simulating a backend make sure that the - circuit is compiled using the set of basis gates in the noise - module by setting ``basis_gates=noise_model.basis_gates`` - and using the device coupling map with - ``coupling_map=backend.configuration().coupling_map`` - - **Specifying custom gate times** - - The ``gate_lengths`` kwarg can be used to specify custom gate times - to add gate errors using the :math:`T_1` and :math:`T_2` values from - the backend properties. This should be passed as a list of tuples - ``gate_lengths=[(name, value), ...]`` - where ``name`` is the gate name string, and ``value`` is the gate time - in nanoseconds. - - If a custom gate is specified that already exists in - the backend properties, the ``gate_lengths`` value will override the - gate time value from the backend properties. - If non-default values are used gate_lengths should be a list - - Args: - properties (BackendProperties): backend properties. - gate_error (bool): Include depolarizing gate errors (Default: True). - readout_error (Bool): Include readout errors in model - (Default: True). - thermal_relaxation (Bool): Include thermal relaxation errors - (Default: True). - temperature (double): qubit temperature in milli-Kelvin (mK) for - thermal relaxation errors (Default: 0). - gate_lengths (list): Custom gate times for thermal relaxation errors. - Used to extend or override the gate times in - the backend properties (Default: None)) - gate_length_units (str): Time units for gate length values in gate_lengths. - Can be 'ns', 'ms', 'us', or 's' (Default: 'ns'). - standard_gates (bool): If true return errors as standard - qobj gates. If false return as unitary - qobj instructions (Default: True) - - Returns: - NoiseModel: An approximate noise model for the device backend. - """ - warnings.warn( - 'This function is been deprecated and moved to a method of the' - '`NoiseModel` class. For equivalent functionality use' - ' `NoiseModel.from_backend(properties, **kwargs).', - DeprecationWarning) - # This wrapper is for the deprecated function - # We need to import noise model here to avoid cyclic import errors - # pylint: disable=import-outside-toplevel - from ..noise_model import NoiseModel - return NoiseModel.from_backend(properties, - gate_error=gate_error, - readout_error=readout_error, - thermal_relaxation=thermal_relaxation, - temperature=temperature, - gate_lengths=gate_lengths, - gate_length_units=gate_length_units, - standard_gates=standard_gates) diff --git a/qiskit/providers/aer/noise/utils/__init__.py b/qiskit/providers/aer/noise/utils/__init__.py deleted file mode 100644 index 06712a5c62..0000000000 --- a/qiskit/providers/aer/noise/utils/__init__.py +++ /dev/null @@ -1,191 +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. -""" -The functions here have been moved to `qiskit.providers.aer.utils`. -""" - -import warnings as warn - -# DEPRECATED: these functions have been moved -from ...utils import remap_noise_model as _remap_noise_model -from ...utils import NoiseTransformer as _NoiseTransformer -from ...utils import approximate_quantum_error as _approximate_quantum_error -from ...utils import approximate_noise_model as _approximate_noise_model -from ...utils import insert_noise as _insert_noise - - -def remap_noise_model(noise_model, - remapping, - discard_qubits=False, - warnings=True): - """Remap qubits in a noise model. - - This remaps the specified gate qubits for local quantum errors, the gate - and noise qubits for non-local quantum errors, and the gate qubits for - local ReadoutErrors. All-qubit quantum and readout errors are unaffected. - - Args: - noise_model (NoiseModel): a noise model to remap qubits. - remapping (list): list or remappings of old qubit to new qubit. - See Additional Information. - discard_qubits (bool): if True discard qubits not in remapping keys, - if False an identity mapping wil be assumed - for unnamed qubits (Default: False). - warnings (bool): display warnings if qubits being remapped are not - in the input noise model (Default: True). - - Returns: - NoiseModel: a new noise model with the same errors but remapped - gate and noise qubits for local and non-local errors. - - Raises: - NoiseError: if remapping has duplicate qubits in the remapped qubits. - - Additional Information: - * The remapping map be specified as either a list of pairs: - ``[(old, new), ...]``, or a list of old qubits where the new qubit is - inferred from the position: ``[old0, old1, ...]`` is treated as - ``[(old0, 0), (old1, 1), ...]``. - - * If ``discard_qubits`` is ``False``, any qubits in the noise model not - specified in the list of old qubits will be added to the remapping as - a trivial mapping ``(qubit, qubit)``. - """ - warn.warn( - 'This function is been moved to `qiskit.providers.aer.utils.remap_noise_model`.' - ' Importing it from `qiskit.providers.aer.noise.utils` will be' - ' removed in a future release.', DeprecationWarning) - return _remap_noise_model(noise_model, - remapping, - discard_qubits=discard_qubits, - warnings=warnings) - - -def insert_noise(circuits, noise_model, transpile=False): - """Return a noisy version of a QuantumCircuit. - - Args: - circuits (QuantumCircuit or list[QuantumCircuit]): Input noise-free circuits. - noise_model (NoiseModel): The noise model containing the errors to add - transpile (Boolean): Should the circuit be transpiled into the noise model basis gates - - Returns: - QuantumCircuit: The new circuit with the Kraus noise instructions inserted. - - Additional Information: - The noisy circuit return by this function will consist of the - original circuit with ``Kraus`` instructions inserted after all - instructions referenced in the ``noise_model``. The resulting circuit - cannot be ran on a quantum computer but can be executed on the - :class:`~qiskit.providers.aer.QasmSimulator`. - """ - warn.warn( - 'This function is been moved to `qiskit.providers.aer.utils.insert_noise`.' - ' Importing it from `qiskit.providers.aer.noise.utils` will be' - ' removed in a future release.', DeprecationWarning) - return _insert_noise(circuits, noise_model, transpile=transpile) - - -def approximate_quantum_error(error, - *, - operator_string=None, - operator_dict=None, - operator_list=None): - """ - Return an approximate QuantumError bases on the Hilbert-Schmidt metric. - - Currently this is only implemented for 1-qubit QuantumErrors. - - Args: - error (QuantumError): the error to be approximated. - operator_string (string or None): a name for a pre-made set of - building blocks for the output channel (Default: None). - operator_dict (dict or None): a dictionary whose values are the - building blocks for the output channel (Default: None). - operator_list (dict or None): list of building blocks for the - output channel (Default: None). - - Returns: - QuantumError: the approximate quantum error. - - Raises: - NoiseError: if number of qubits is not supported or approximation - failed. - RuntimeError: If there's no information about the noise type. - - Additional Information: - The operator input precedence is: ``list`` < ``dict`` < ``str``. - If a string is given, dict is overwritten; if a dict is given, list is - overwritten. Oossible values for string are ``'pauli'``, ``'reset'``, - ``'clifford'``. - For further information see :meth:`NoiseTransformer.named_operators`. - """ - warn.warn( - 'This function is been moved to `qiskit.providers.aer.utils.approximate_qauntum_error`.' - ' Importing it from `qiskit.providers.aer.noise.utils` will be removed' - ' in a future release.', - DeprecationWarning) - return _approximate_quantum_error(error, - operator_string=operator_string, - operator_dict=operator_dict, - operator_list=operator_list) - - -def approximate_noise_model(model, - *, - operator_string=None, - operator_dict=None, - operator_list=None): - """ - Return an approximate noise model. - - Args: - model (NoiseModel): the noise model to be approximated. - operator_string (string or None): a name for a pre-made set of - building blocks for the output channel (Default: None). - operator_dict (dict or None): a dictionary whose values are the - building blocks for the output channel (Default: None). - operator_list (dict or None): list of building blocks for the - output channel (Default: None). - - Returns: - NoiseModel: the approximate noise model. - - Raises: - NoiseError: if number of qubits is not supported or approximation - failed. - - Additional Information: - The operator input precedence is: ``list`` < ``dict`` < ``str``. - If a string is given, dict is overwritten; if a dict is given, list is - overwritten. Oossible values for string are ``'pauli'``, ``'reset'``, - ``'clifford'``. - For further information see :meth:`NoiseTransformer.named_operators`. - """ - warn.warn( - 'This function is been moved to `qiskit.providers.aer.utils.approximate_noise_model`.' - ' Importing it from `qiskit.providers.aer.noise.utils` will be removed in a' - ' future release.', DeprecationWarning) - return _approximate_noise_model(model, - operator_string=operator_string, - operator_dict=operator_dict, - operator_list=operator_list) - - -class NoiseTransformer(_NoiseTransformer): - """Transforms one quantum channel to another based on a specified criteria.""" - def __init__(self): - warn.warn( - 'This function is been moved to `qiskit.providers.aer.utils.NoiseTransformer`.' - ' Importing it from `qiskit.providers.aer.noise.utils` will be removed in a' - ' future release.', DeprecationWarning) - super().__init__() diff --git a/qiskit/providers/aer/utils/__init__.py b/qiskit/providers/aer/utils/__init__.py index b64ad32a39..98bbfaa946 100644 --- a/qiskit/providers/aer/utils/__init__.py +++ b/qiskit/providers/aer/utils/__init__.py @@ -48,5 +48,3 @@ from .noise_transformation import approximate_quantum_error from .noise_transformation import approximate_noise_model from .noise_model_inserter import insert_noise - -from . import qobj_utils diff --git a/qiskit/providers/aer/utils/qobj_utils.py b/qiskit/providers/aer/utils/qobj_utils.py deleted file mode 100644 index 3e660be819..0000000000 --- a/qiskit/providers/aer/utils/qobj_utils.py +++ /dev/null @@ -1,266 +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. -""" -Temporary hacks for qobj until Terra supports Aer instructions (likely 0.8) - -THESE SHOULD ONLY BE USED UNTIL A PROPER QUANTUM CIRCUIT INTERFACE -IS ADDED TO QISKIT TERRA. THEY WILL NOT BE SUPPORTED AFTER THAT. -""" - -import copy -import warnings -import numpy as np -from qiskit.qobj import QasmQobjInstruction - - -def append_instr(qobj, exp_index, instruction): - """Append a QasmQobjInstruction to a QobjExperiment. - - Args: - qobj (Qobj): a Qobj object. - exp_index (int): The index of the experiment in the qobj. - instruction (QasmQobjInstruction): instruction to insert. - - Returns: - qobj(Qobj): The Qobj object - """ - warnings.warn( - 'This function is deprecated and will be removed in a future release.', - DeprecationWarning) - qobj.experiments[exp_index].instructions.append(instruction) - return qobj - - -def insert_instr(qobj, exp_index, item, pos): - """Insert a QasmQobjInstruction into a QobjExperiment. - - Args: - qobj (Qobj): a Qobj object - exp_index (int): The index of the experiment in the qobj. - item (QasmQobjInstruction): instruction to insert. - pos (int): the position to insert the item. - - Returns: - qobj(Qobj): The Qobj object - """ - warnings.warn( - 'This function is deprecated and will be removed in a future release.', - DeprecationWarning) - qobj.experiments[exp_index].instructions.insert(pos, item) - return qobj - - -def get_instr_pos(qobj, exp_index, name): - """Return all locations of QasmQobjInstruction in a Qobj experiment. - - The return list is sorted in reverse order so iterating over it - to insert new items will work as expected. - - Args: - qobj (Qobj): a Qobj object - exp_index (int): The index of the experiment in the qobj - name (str): QasmQobjInstruction name to find - - Returns: - list[int]: A list of positions where the QasmQobjInstruction is located. - """ - warnings.warn( - 'This funnction is deprecated and will be removed in a future release.', - DeprecationWarning) - # Check only the name string of the item - positions = [ - i for i, val in enumerate(qobj.experiments[exp_index].instructions) - if val.name == name - ] - return positions - - -def unitary_instr(mat, qubits, label=None): - """Create a unitary gate QasmQobjInstruction. - - Args: - mat (matrix_like): an n-qubit unitary matrix - qubits (list[int]): qubits to apply the matrix to. - label (str): optional string label for the unitary matrix - - Returns: - QasmQobjInstruction: The qobj item for the unitary instruction. - - Raises: - ValueError: if the input matrix is not unitary - - Additional Information: - - Qubit Ordering: - The n-qubit matrix is ordered in little-endian with respect to - the qubits in the label string. For example. If M is a tensor - product of single qubit matrices `M = kron(M_(n-1), ..., M_1, M_0)` - then `M_0` is applied to `qubits[0]`, `M_1` to `qubits[1]` etc. - - Label string: - The string label is used for identifying the matrix in a noise - model so that noise may be applied to the implementation of - this matrix. - """ - warnings.warn( - 'This function is deprecated and will be removed in a future release.', - DeprecationWarning) - array = np.array(mat, dtype=complex) - dim = 2**len(qubits) - if array.shape not in [(dim, dim), (1, dim)]: - raise ValueError("Invalid") - instruction = { - "name": "unitary", - "qubits": list(qubits), - "params": [np.array(mat, dtype=complex)] - } - if label is not None: - instruction["label"] = str(label) - return QasmQobjInstruction(**instruction) - - -def measure_instr(qubits, memory, registers=None): - """Create a multi-qubit measure instruction""" - warnings.warn( - 'This function is deprecated and will be removed in a future release.', - DeprecationWarning) - if len(qubits) != len(memory): - raise ValueError("Number of qubits does not match number of memory") - if registers is None: - return QasmQobjInstruction(name='measure', - qubits=qubits, - memory=memory) - # Case where we also measure to registers - if len(qubits) != len(registers): - raise ValueError("Number of qubits does not match number of registers") - return QasmQobjInstruction(name='measure', - qubits=qubits, - memory=memory, - register=registers) - - -def reset_instr(qubits): - """Create a multi-qubit reset instruction""" - warnings.warn( - 'This function is deprecated and will be removed in a future release.', - DeprecationWarning) - return QasmQobjInstruction(name='reset', qubits=qubits) - - -def barrier_instr(num_qubits): - """Create a barrier QasmQobjInstruction.""" - warnings.warn( - 'This function is deprecated and will be removed in a future release.', - DeprecationWarning) - return QasmQobjInstruction(name='barrier', qubits=list(range(num_qubits))) - - -def iden_instr(qubit): - """Create a barrier QasmQobjInstruction.""" - warnings.warn( - 'This function is deprecated and will be removed in a future release.', - DeprecationWarning) - return QasmQobjInstruction(name='id', qubits=[qubit]) - - -def snapshot_instr(snapshot_type, label, qubits=None, params=None): - """Create a snapshot qobj item. - - Args: - snapshot_type (str): the snapshot type identifier - label (str): the snapshot label string - qubits (list[int]): qubits snapshot applies to (optional) - params (custom): optional parameters for special snapshot types. - See additional information. - - Returns: - QasmQobjInstruction: The qobj item for the snapshot instruction. - - - Additional Information: - Snapshot types: - "statevector" -- returns the current statevector for each shot - "memory" -- returns the current memory hex-string for each shot - "register" -- returns the current register hex-string for each shot - "probabilities" -- returns the measurement outcome probabilities - averaged over all shots, but conditioned on the - current memory value. - This requires the qubits field to be set. - "expval_pauli" -- returns the expectation value of an operator - averaged over all shots, but conditioned on the - current memory value. - This requires the qubits field to be set and - the params field to be set. - "expval_matrix" -- same as expval_pauli but with different params - - Pauli expectation value params: - These are a list of terms [complex_coeff, pauli_str] - where string is in little endian: pauli_str CBA applies Pauli - A to qubits[0], B to qubits[1] and C to qubits[2]. - Example for op 0.5 XX + 0.7 IZ we have [[0.5, 'XX'], [0.7, 'IZ']] - - Matrix expectation value params: - TODO - """ - warnings.warn( - 'This function is deprecated and will be removed in a future release.' - ' Use the snapshot circuit instructions in' - ' `qiskit.provider.aer.extensions` instead.', DeprecationWarning) - snap = { - "name": "snapshot", - "snapshot_type": snapshot_type, - "label": str(label) - } - if qubits is not None: - snap["qubits"] = list(qubits) - if params is not None: - snap["params"] = params - # Check if single-matrix expectation value - if snapshot_type in ["expval", "expval_matrix"] and \ - isinstance(params, np.ndarray): - snap["name"] = "expval_matrix" - snap["params"] = [[1.0, qubits, params]] - # TODO: implicit conversion for Pauli expval params - return QasmQobjInstruction(**snap) - - -def insert_snapshots_after_barriers(qobj, snapshot): - """Insert a snapshot instruction after each barrier in qobj. - - The label of the input snapshot will be appended with "i" where - "i" ranges from 0 to the 1 - number of barriers. - - Args: - qobj (Qobj): a qobj to insert snapshots into - snapshot (QasmQobjInstruction): a snapshot instruction. - - Returns: - qobj(Qobj): The Qobj object - - Raises: - ValueError: if the name of the instruction is not an snapshot - - Additional Information: - """ - warnings.warn( - 'This function is deprecated and will be removed in a future release.', - DeprecationWarning) - if snapshot.name != "snapshot": - raise ValueError("Invalid snapshot instruction") - label = snapshot.label - for exp_index in range(len(qobj.experiments)): - positions = get_instr_pos(qobj, exp_index, "barrier") - for i, pos in reversed(list(enumerate(positions))): - item = copy.copy(snapshot) - item.label = label + "{}".format(i) - insert_instr(qobj, exp_index, item, pos) - return qobj From e76155ef10f17e256a0685892be2c0159811b6e9 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Tue, 13 Oct 2020 14:05:27 -0400 Subject: [PATCH 016/126] Fix CI failures because of azure image update (#987) * Fix CI failures because of azure image update Azure pipelines recently updated their windows images with a newer version of conda. This has started causing CI failures when the wheel jobs run virtualenv to build an isolated python env to test that the built wheels work for a user without any dependencies pre-installed. This commit attempts to fix this by installing virtualenv from pip. If this does not work this will pivot the PR to use python outside of conda or use conda for the virtualenv creation. * Just use conda to create isolated env in CI Since the previous commit failed to address the issue with the updated azure images. This commit pivots away from using virtualenv to create an isolated test environment, and instead just uses conda create to build a new isolated environment for installing the wheels. This should hopefully be more reliable since it doesn't mix system python and conda python which often have weird cross interactions. --- azure-pipelines.yml | 46 +++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5ac8194946..a3e0787417 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -45,11 +45,12 @@ stages: source activate qiskit-aer-$version conda update --yes -n base conda conda config --add channels conda-forge - conda install --yes --quiet --name qiskit-aer-$version python=$version numpy cmake virtualenv pip setuptools pybind11 cython scipy + conda install --yes --quiet --name qiskit-aer-$version python=$version numpy cmake pip setuptools pybind11 cython scipy python setup.py bdist_wheel -- -G "Visual Studio 15 2017 Win64" - virtualenv test-$version - test-$version/Scripts/pip install -c constraints.txt dist/*whl - test-$version/Scripts/python tools/verify_wheels.py + conda create --yes --quiet python=$version --name test-$version + source activate test-$version + pip install -c constraints.txt dist/*whl + python tools/verify_wheels.py mv dist/*whl wheelhouse/. rm -rf test-$version rm -rf _skbuild @@ -98,12 +99,13 @@ stages: mkdir wheelhouse for version in 3.6 3.7 3.8 ; do source activate qiskit-aer-$version - conda install --yes --quiet --name qiskit-aer-$version python=$version numpy cmake virtualenv pip setuptools pybind11 cython scipy + conda install --yes --quiet --name qiskit-aer-$version python=$version numpy cmake pip setuptools pybind11 cython scipy python -m pip install -U setuptools wheel python setup.py bdist_wheel -- -G "Visual Studio 15 2017" - virtualenv test-$version - test-$version/Scripts/pip install -c constraints.txt dist/*whl - test-$version/Scripts/python tools/verify_wheels.py + conda create --yes --quiet python=$version --name test-$version + source activate test-$version + pip install -c constraints.txt dist/*whl + python tools/verify_wheels.py mv dist/*whl wheelhouse/. rm -rf test-$version rm -rf _skbuild @@ -161,7 +163,7 @@ stages: source activate qiskit-aer conda update --yes -n base conda conda config --add channels conda-forge - conda install --yes --quiet --name qiskit-aer python=$(python.version) numpy cmake virtualenv pip setuptools pybind11 cython scipy + conda install --yes --quiet --name qiskit-aer python=$(python.version) numpy cmake pip setuptools pybind11 cython scipy displayName: Create Anaconda environments - bash: | set -x @@ -172,11 +174,11 @@ stages: - bash: | set -x set -e - source activate qiskit-aer - virtualenv test-wheel - test-wheel/Scripts/pip install -c constraints.txt dist/*whl - test-wheel/Scripts/pip install -c constraints.txt git+https://github.com/Qiskit/qiskit-terra - test-wheel/Scripts/python tools/verify_wheels.py + conda create --yes --quiet --name test-wheel python=$(python.version) + source activate test-wheel + pip install -c constraints.txt dist/*whl + pip install -c constraints.txt git+https://github.com/Qiskit/qiskit-terra + python tools/verify_wheels.py displayName: Verify wheels - job: 'Windows_win32_Wheel_Builds' pool: {vmImage: 'vs2017-win2016'} @@ -211,7 +213,7 @@ stages: set -e conda create --yes --quiet --name qiskit-aer python=$(python.version) source activate qiskit-aer - conda install --yes --quiet --name qiskit-aer python=$(python.version) numpy cmake virtualenv pip setuptools pybind11 cython scipy + conda install --yes --quiet --name qiskit-aer python=$(python.version) numpy cmake pip setuptools pybind11 cython scipy displayName: Create Anaconda environments env: CONDA_FORCE_32BIT: 1 @@ -227,11 +229,11 @@ stages: - bash: | set -x set -e - source activate qiskit-aer - virtualenv test-wheel - test-wheel/Scripts/pip install -c constraints.txt dist/*whl - test-wheel/Scripts/pip install -c constraints.txt git+https://github.com/Qiskit/qiskit-terra - test-wheel/Scripts/python tools/verify_wheels.py + conda create --yes --quiet --name test-wheel python=$(python.version) + source activate test-wheel + pip install -c constraints.txt dist/*whl + pip install -c constraints.txt git+https://github.com/Qiskit/qiskit-terra + python tools/verify_wheels.py displayName: Verify wheels env: CONDA_FORCE_32BIT: 1 @@ -268,7 +270,7 @@ stages: source activate qiskit-aer conda update --yes -n base conda conda config --add channels conda-forge - conda install --yes --quiet --name qiskit-aer python=$(python.version) numpy cmake virtualenv pip setuptools pybind11 cython scipy + conda install --yes --quiet --name qiskit-aer python=$(python.version) numpy cmake pip setuptools pybind11 cython scipy displayName: Create Anaconda environments - bash: | set -x @@ -280,7 +282,7 @@ stages: set -x set -e source activate qiskit-aer - pip install -U setuptools virtualenv wheel + pip install -U setuptools wheel pip install dist/*tar.gz pip install git+https://github.com/Qiskit/qiskit-terra python tools/verify_wheels.py From d5deb420fede53782cbb84fccc64f19919c37b37 Mon Sep 17 00:00:00 2001 From: "Christopher J. Wood" Date: Tue, 13 Oct 2020 15:45:49 -0400 Subject: [PATCH 017/126] Configurable backends (#486) * Make Aer simulator backends configurable * Add deprecation warning to backend_options kwarg * Make pulse_controller only require qobj input * update tests to remove deprecation warnings Co-authored-by: Daniel Puzzuoli --- qiskit/providers/aer/aerjob.py | 9 +- qiskit/providers/aer/backends/aerbackend.py | 382 ++++++++--- .../providers/aer/backends/backend_utils.py | 68 ++ .../providers/aer/backends/pulse_simulator.py | 336 +++++++--- .../providers/aer/backends/qasm_simulator.py | 305 ++++++--- .../aer/backends/statevector_simulator.py | 134 ++-- .../aer/backends/unitary_simulator.py | 103 ++- qiskit/providers/aer/noise/noise_model.py | 72 +- .../pulse/controllers/digest_pulse_qobj.py | 11 +- .../aer/pulse/controllers/pulse_controller.py | 52 +- .../pulse/system_models/pulse_system_model.py | 39 +- ...onfigurable-backends-a55cd6a39a0a1561.yaml | 35 + test/benchmark/fusion_benchmarks.py | 5 +- test/benchmark/randomized_benchmarking.py | 4 +- .../qasm_simulator/qasm_algorithms.py | 12 +- .../backends/qasm_simulator/qasm_cliffords.py | 84 +-- .../qasm_simulator/qasm_conditional.py | 16 +- .../qasm_simulator/qasm_delay_measure.py | 12 +- .../backends/qasm_simulator/qasm_fusion.py | 34 +- .../qasm_simulator/qasm_initialize.py | 10 +- .../backends/qasm_simulator/qasm_measure.py | 20 +- .../backends/qasm_simulator/qasm_method.py | 34 +- .../qasm_simulator/qasm_multiplexer.py | 8 +- .../backends/qasm_simulator/qasm_noise.py | 20 +- .../qasm_simulator/qasm_noncliffords.py | 58 +- .../backends/qasm_simulator/qasm_reset.py | 8 +- .../backends/qasm_simulator/qasm_snapshot.py | 32 +- .../qasm_simulator/qasm_standard_gates.py | 4 +- .../qasm_simulator/qasm_thread_management.py | 52 +- .../backends/qasm_simulator/qasm_truncate.py | 10 +- .../qasm_simulator/qasm_unitary_gate.py | 6 +- .../statevector_basics.py | 174 ++--- .../statevector_fusion.py | 14 +- .../backends/test_config_pulse_simulator.py | 338 ++++++++++ test/terra/backends/test_pulse_simulator.py | 615 +++++++++--------- ...test_qasm_simulator_extended_stabilizer.py | 70 +- .../unitary_simulator/unitary_basics.py | 156 ++--- .../unitary_simulator/unitary_fusion.py | 14 +- .../unitary_simulator/unitary_snapshot.py | 20 +- test/terra/decorators.py | 2 +- test/terra/extensions/test_wrappers.py | 4 +- test/terra/pulse/test_system_models.py | 23 +- test/terra/test_python_to_cpp.py | 1 - tools/verify_wheels.py | 6 +- 44 files changed, 2240 insertions(+), 1172 deletions(-) create mode 100644 qiskit/providers/aer/backends/backend_utils.py create mode 100644 releasenotes/notes/configurable-backends-a55cd6a39a0a1561.yaml create mode 100644 test/terra/backends/test_config_pulse_simulator.py diff --git a/qiskit/providers/aer/aerjob.py b/qiskit/providers/aer/aerjob.py index 275544e03b..5912f2b505 100644 --- a/qiskit/providers/aer/aerjob.py +++ b/qiskit/providers/aer/aerjob.py @@ -14,6 +14,7 @@ """This module implements the job class used for AerBackend objects.""" +import warnings from concurrent import futures import logging import functools @@ -55,6 +56,10 @@ def __init__(self, backend, job_id, fn, qobj, *args): super().__init__(backend, job_id) self._fn = fn self._qobj = qobj + if args: + warnings.warn('Using *args for AerJob is deprecated. All backend' + ' options should be contained in the assembled Qobj.', + DeprecationWarning) self._args = args self._future = None @@ -70,7 +75,9 @@ def submit(self): if self._future is not None: raise JobError("We have already submitted the job!") - self._future = self._executor.submit(self._fn, self._job_id, self._qobj, + self._future = self._executor.submit(self._fn, + self._qobj, + self._job_id, *self._args) @requires_submit diff --git a/qiskit/providers/aer/backends/aerbackend.py b/qiskit/providers/aer/backends/aerbackend.py index ae467f8bf1..28bcb8543a 100644 --- a/qiskit/providers/aer/backends/aerbackend.py +++ b/qiskit/providers/aer/backends/aerbackend.py @@ -9,34 +9,30 @@ # 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. - """ Qiskit Aer qasm simulator backend. """ +import copy import json import logging import datetime -import os import time import uuid +import warnings +from abc import ABC, abstractmethod from numpy import ndarray from qiskit.providers import BaseBackend from qiskit.providers.models import BackendStatus -from qiskit.qobj import validate_qobj_against_schema from qiskit.result import Result -from qiskit.util import local_hardware_info from ..aerjob import AerJob +from ..aererror import AerError # Logger logger = logging.getLogger(__name__) -# Location where we put external libraries that will be loaded at runtime -# by the simulator extension -LIBRARY_DIR = os.path.dirname(__file__) - class AerJSONEncoder(json.JSONEncoder): """ @@ -59,10 +55,15 @@ def default(self, obj): return super().default(obj) -class AerBackend(BaseBackend): +class AerBackend(BaseBackend, ABC): """Qiskit Aer Backend class.""" - - def __init__(self, controller, configuration, provider=None): + def __init__(self, + configuration, + properties=None, + defaults=None, + available_methods=None, + backend_options=None, + provider=None): """Aer class for backends. This method should initialize the module and its configuration, and @@ -70,126 +71,327 @@ def __init__(self, controller, configuration, provider=None): not available. Args: - controller (function): Aer controller to be executed - configuration (BackendConfiguration): backend configuration - provider (BaseProvider): provider responsible for this backend + configuration (BackendConfiguration): backend configuration. + properties (BackendProperties or None): Optional, backend properties. + defaults (PulseDefaults or None): Optional, backend pulse defaults. + available_methods (list or None): Optional, the available simulation methods + if backend supports multiple methods. + provider (BaseProvider): Optional, provider responsible for this backend. + backend_options (dict or None): Optional set custom backend options. Raises: - FileNotFoundError if backend executable is not available. AerError: if there is no name in the configuration """ + # Init configuration and provider in BaseBackend + configuration.simulator = True super().__init__(configuration, provider=provider) - self._controller = controller + + # Initialize backend properties and pulse defaults. + self._properties = properties + self._defaults = defaults + + # Custom configuration, properties, and pulse defaults which will store + # any configured modifications to the base simulator values. + self._custom_configuration = None + self._custom_properties = None + self._custom_defaults = None + + # Set available methods + self._available_methods = [] if available_methods is None else available_methods + + # Set custom configured options from backend_options dictionary + self._options = {} + if backend_options is not None: + for key, val in backend_options.items(): + self._set_option(key, val) # pylint: disable=arguments-differ - def run(self, qobj, backend_options=None, noise_model=None, validate=False): + def run(self, + qobj, + backend_options=None, # DEPRECATED + validate=True, + **run_options): """Run a qobj on the backend. Args: qobj (QasmQobj): The Qobj to be executed. - backend_options (dict or None): dictionary of backend options + backend_options (dict or None): DEPRECATED dictionary of backend options for the execution (default: None). - noise_model (NoiseModel or None): noise model to use for - simulation (default: None). validate (bool): validate the Qobj before running (default: True). + run_options (kwargs): additional run time backend options. Returns: AerJob: The simulation job. Additional Information: + * kwarg options specified in ``run_options`` will temporarily override + any set options of the same name for the current run. + * The entries in the ``backend_options`` will be combined with the ``Qobj.config`` dictionary with the values of entries in - ``backend_options`` taking precedence. - - * If present the ``noise_model`` will override any noise model - specified in the ``backend_options`` or ``Qobj.config``. + ``backend_options`` taking precedence. This kwarg is deprecated + and direct kwarg's should be used for options to pass them to + ``run_options``. """ + # DEPRECATED + if backend_options is not None: + warnings.warn( + 'Using `backend_options` kwarg has been deprecated as of' + ' qiskit-aer 0.7.0 and will be removed no earlier than 3' + ' months from that release date. Runtime backend options' + ' should now be added directly using kwargs for each option.', + DeprecationWarning, + stacklevel=3) + + # Add backend options to the Job qobj + qobj = self._format_qobj( + qobj, backend_options=backend_options, **run_options) + + # Optional validation + if validate: + self._validate(qobj) + # Submit job job_id = str(uuid.uuid4()) - aer_job = AerJob(self, job_id, self._run_job, qobj, - backend_options, noise_model, validate) + aer_job = AerJob(self, job_id, self._run, qobj) aer_job.submit() return aer_job + def configuration(self): + """Return the simulator backend configuration. + + Returns: + BackendConfiguration: the configuration for the backend. + """ + if self._custom_configuration is not None: + return self._custom_configuration + return self._configuration + + def properties(self): + """Return the simulator backend properties if set. + + Returns: + BackendProperties: The backend properties or ``None`` if the + backend does not have properties set. + """ + if self._custom_properties is not None: + return self._custom_properties + return self._properties + + def defaults(self): + """Return the simulator backend pulse defaults. + + Returns: + PulseDefaults: The backend pulse defaults or ``None`` if the + backend does not support pulse. + """ + if self._custom_defaults is not None: + return self._custom_defaults + return self._defaults + + @property + def options(self): + """Return the current simulator options""" + return self._options + + def set_options(self, **backend_options): + """Set the simulator options""" + for key, val in backend_options.items(): + self._set_option(key, val) + + def clear_options(self): + """Reset the simulator options to default values.""" + self._custom_configuration = None + self._custom_properties = None + self._custom_defaults = None + self._options = {} + + def available_methods(self): + """Return the available simulation methods.""" + return self._available_methods + def status(self): """Return backend status. Returns: BackendStatus: the status of the backend. """ - return BackendStatus(backend_name=self.name(), - backend_version=self.configuration().backend_version, - operational=True, - pending_jobs=0, - status_msg='') + return BackendStatus( + backend_name=self.name(), + backend_version=self.configuration().backend_version, + operational=True, + pending_jobs=0, + status_msg='') def _run_job(self, job_id, qobj, backend_options, noise_model, validate): """Run a qobj job""" - start = time.time() + warnings.warn( + 'The `_run_job` method has been deprecated. Use `_run` instead.', + DeprecationWarning) if validate: - validate_qobj_against_schema(qobj) - self._validate(qobj, backend_options, noise_model) - output = self._controller(self._format_qobj(qobj, backend_options, noise_model)) - end = time.time() - return Result.from_dict(self._format_results(job_id, output, end - start)) - - def _format_qobj(self, qobj, backend_options, noise_model): - """Format qobj string for qiskit aer controller""" - # Convert qobj to dict so as to avoid editing original - output = qobj.to_dict() - # Add new parameters to config from backend options - config = output["config"] - if backend_options is not None: - for key, val in backend_options.items(): - config[key] = val if not hasattr(val, 'to_dict') else val.to_dict() - # Add noise model to config - if noise_model is not None: - config["noise_model"] = noise_model - - # Add runtime config - if 'library_dir' not in config: - config['library_dir'] = LIBRARY_DIR - if "max_memory_mb" not in config: - max_memory_mb = int(local_hardware_info()['memory'] * 1024 / 2) - config['max_memory_mb'] = max_memory_mb - - self._validate_config(config) - # Return output - return output - - def _validate_config(self, config): - # sanity checks on config- should be removed upon fixing of assemble w.r.t. backend_options - if 'backend_options' in config: - if isinstance(config['backend_options'], dict): - for key, val in config['backend_options'].items(): - if hasattr(val, 'to_dict'): - config['backend_options'][key] = val.to_dict() - elif not isinstance(config['backend_options'], list): - raise ValueError("config[backend_options] must be a dict or list!") - # Double-check noise_model is a dict type - if 'noise_model' in config and not isinstance(config["noise_model"], dict): - if hasattr(config["noise_model"], 'to_dict'): - config["noise_model"] = config["noise_model"].to_dict() - else: - raise ValueError("noise_model must be a dict : " + str(type(config["noise_model"]))) - - def _format_results(self, job_id, output, time_taken): - """Construct Result object from simulator output.""" + warnings.warn( + 'The validate arg of `_run_job` has been removed. Use ' + 'validate=True in the `run` method instead.', + DeprecationWarning) + + # The new function swaps positional args qobj and job id so we do a + # type check to swap them back + if not isinstance(job_id, str) and isinstance(qobj, str): + job_id, qobj = qobj, job_id + run_qobj = self._format_qobj(qobj, backend_options=backend_options, + noise_model=noise_model) + return self._run(run_qobj, job_id) + + def _run(self, qobj, job_id=''): + """Run a job""" + # Start timer + start = time.time() + + # Run simulation + output = self._execute(qobj) + + # Validate output + if not isinstance(output, dict): + logger.error("%s: simulation failed.", self.name()) + if output: + logger.error('Output: %s', output) + raise AerError( + "simulation terminated without returning valid output.") + + # Format results output["job_id"] = job_id output["date"] = datetime.datetime.now().isoformat() output["backend_name"] = self.name() output["backend_version"] = self.configuration().backend_version - output["time_taken"] = time_taken - return output - def _validate(self, qobj, backend_options, noise_model): - """Validate the qobj, backend_options, noise_model for the backend""" + # Add execution time + output["time_taken"] = time.time() - start + return Result.from_dict(output) + + @abstractmethod + def _execute(self, qobj): + """Execute a qobj on the backend. + + Args: + qobj (QasmQobj or PulseQobj): simulator input. + + Returns: + dict: return a dictionary of results. + """ pass + def _validate(self, qobj): + """Validate the qobj for the backend""" + pass + + def _set_option(self, key, value): + """Special handling for setting backend options. + + This method should be extended by sub classes to + update special option values. + + Args: + key (str): key to update + value (any): value to update. + + Raises: + AerError: if key is 'method' and val isn't in available methods. + """ + # Check for key in configuration, properties, and defaults + # If the key requires modification of one of these fields a copy + # will be generated that can store the modified values without + # changing the original object + if hasattr(self._configuration, key): + self._set_configuration_option(key, value) + return + + if hasattr(self._properties, key): + self._set_properties_option(key, value) + return + + if hasattr(self._defaults, key): + self._set_defaults_option(key, value) + return + + # If key is method, we validate it is one of the available methods + if key == 'method' and value not in self._available_methods: + raise AerError("Invalid simulation method {}. Available methods" + " are: {}".format(value, self._available_methods)) + + # Add all other options to the options dict + # TODO: in the future this could be replaced with an options class + # for the simulators like configuration/properties to show all + # available options + if value is not None: + # Only add an option if its value is not None + self._options[key] = value + elif key in self._options: + # If setting an existing option to None remove it from options dict + self._options.pop(key) + + def _set_configuration_option(self, key, value): + """Special handling for setting backend configuration options.""" + if self._custom_configuration is None: + self._custom_configuration = copy.copy(self._configuration) + setattr(self._custom_configuration, key, value) + + def _set_properties_option(self, key, value): + """Special handling for setting backend properties options.""" + if self._custom_properties is None: + self._custom_properties = copy.copy(self._properties) + setattr(self._custom_properties, key, value) + + def _set_defaults_option(self, key, value): + """Special handling for setting backend defaults options.""" + if self._custom_defaults is None: + self._custom_defaults = copy.copy(self._defaults) + setattr(self._custom_defaults, key, value) + + def _format_qobj(self, qobj, + backend_options=None, # DEPRECATED + **run_options): + """Return execution sim config dict from backend options.""" + # Add options to qobj config overriding any existing fields + config = qobj.config + + # Add options + for key, val in self.options.items(): + setattr(config, key, val) + + # DEPRECATED backend options + if backend_options is not None: + for key, val in backend_options.items(): + setattr(config, key, val) + + # Override with run-time options + for key, val in run_options.items(): + setattr(config, key, val) + + return qobj + + def _run_config( + self, + backend_options=None, # DEPRECATED + **run_options): + """Return execution sim config dict from backend options.""" + # Get sim config + run_config = self._options.copy() + + # DEPRECATED backend options + if backend_options is not None: + for key, val in backend_options.items(): + run_config[key] = val + + # Override with run-time options + for key, val in run_options.items(): + run_config[key] = val + return run_config + def __repr__(self): - """Official string representation of an AerBackend.""" - display = "{}('{}')".format(self.__class__.__name__, self.name()) - provider = self.provider() - if provider is not None: - display = display + " from {}()".format(provider) - return "<" + display + ">" + """String representation of an AerBackend.""" + display = "backend_name='{}'".format(self.name()) + if self.provider(): + display += ', provider={}()'.format(self.provider()) + for key, val in self.options.items(): + display += ',\n {}={}'.format(key, repr(val)) + return '{}(\n{})'.format(self.__class__.__name__, display) diff --git a/qiskit/providers/aer/backends/backend_utils.py b/qiskit/providers/aer/backends/backend_utils.py new file mode 100644 index 0000000000..053722aeae --- /dev/null +++ b/qiskit/providers/aer/backends/backend_utils.py @@ -0,0 +1,68 @@ +# 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. + +# pylint: disable=invalid-name +""" +Qiskit Aer simulator backend utils +""" +import os +from math import log2 +from qiskit.util import local_hardware_info +from qiskit.circuit import QuantumCircuit +from qiskit.compiler import assemble + +# Available system memory +SYSTEM_MEMORY_GB = local_hardware_info()['memory'] + +# Max number of qubits for complex double statevector +# given available system memory +MAX_QUBITS_STATEVECTOR = int(log2(SYSTEM_MEMORY_GB * (1024**3) / 16)) + +# Location where we put external libraries that will be +# loaded at runtime by the simulator extension +LIBRARY_DIR = os.path.dirname(__file__) + + +def cpp_execute(controller, qobj): + """Execute qobj_dict on C++ controller wrapper""" + # Convert qobj to dict + qobj_dict = qobj.to_dict() + + # Convert noise model to dict + noise_model = qobj_dict['config'].pop('noise_model', None) + if noise_model is not None: + if not isinstance(noise_model, dict): + noise_model = noise_model.to_dict() + qobj_dict['config']['noise_model'] = noise_model + + # Location where we put external libraries that will be + # loaded at runtime by the simulator extension + qobj_dict['config']['library_dir'] = LIBRARY_DIR + + return controller(qobj_dict) + + +def available_methods(controller, methods): + """Check available simulation methods by running a dummy circuit.""" + # Test methods are available using the controller + dummy_circ = QuantumCircuit(1) + dummy_circ.i(0) + + valid_methods = [] + for method in methods: + qobj = assemble(dummy_circ, + optimization_level=0, + method=method) + result = cpp_execute(controller, qobj) + if result.get('success', False): + valid_methods.append(method) + return valid_methods diff --git a/qiskit/providers/aer/backends/pulse_simulator.py b/qiskit/providers/aer/backends/pulse_simulator.py index b97bc4b350..5dc9bdabae 100644 --- a/qiskit/providers/aer/backends/pulse_simulator.py +++ b/qiskit/providers/aer/backends/pulse_simulator.py @@ -10,25 +10,43 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. # pylint: disable=arguments-differ, missing-return-type-doc - """ Qiskit Aer pulse simulator backend. """ -import uuid -import time -import datetime +import copy import logging +from warnings import warn from numpy import inf -from qiskit.result import Result + from qiskit.providers.models import BackendConfiguration, PulseDefaults -from .aerbackend import AerBackend -from ..aerjob import AerJob + from ..version import __version__ +from ..aererror import AerError from ..pulse.controllers.pulse_controller import pulse_controller +from ..pulse.system_models.pulse_system_model import PulseSystemModel +from .aerbackend import AerBackend logger = logging.getLogger(__name__) +DEFAULT_CONFIGURATION = { + 'backend_name': 'pulse_simulator', + 'backend_version': __version__, + 'n_qubits': 20, + 'coupling_map': None, + 'url': 'https://github.com/Qiskit/qiskit-aer', + 'simulator': True, + 'meas_levels': [1, 2], + 'local': True, + 'conditional': True, + 'open_pulse': True, + 'memory': False, + 'max_shots': int(1e6), + 'description': 'A Pulse-based Hamiltonian simulator for Pulse Qobj files', + 'gates': [], + 'basis_gates': [] +} + class PulseSimulator(AerBackend): r"""Pulse schedule simulator backend. @@ -38,12 +56,26 @@ class PulseSimulator(AerBackend): physical system specified by :class:`~qiskit.providers.aer.pulse.PulseSystemModel` objects. Results are returned in the same format as when jobs are submitted to actual devices. - **Example** + **Examples** + + The minimal information a ``PulseSimulator`` needs to simulate is a + :class:`~qiskit.providers.aer.pulse.PulseSystemModel`, which can be supplied either by + setting the backend option before calling ``run``, e.g.: + + .. code-block:: python + + backend_sim = qiskit.providers.aer.PulseSimulator() + + # Set the pulse system model for the simulator + backend_sim.set_options(system_model=system_model) - To use the simulator, first :func:`~qiskit.assemble` a :class:`PulseQobj` object - from a list of pulse :class:`~qiskit.Schedule` objects, using ``backend=PulseSimulator()``. - Call the simulator with the :class:`PulseQobj` and a - :class:`~qiskit.providers.aer.pulse.PulseSystemModel` object representing the physical system. + # Assemble schedules using PulseSimulator as the backend + pulse_qobj = assemble(schedules, backend=backend_sim) + + # Run simulation + results = backend_sim.run(pulse_qobj) + + or by supplying the system model at runtime, e.g.: .. code-block:: python @@ -53,7 +85,23 @@ class PulseSimulator(AerBackend): pulse_qobj = assemble(schedules, backend=backend_sim) # Run simulation on a PulseSystemModel object - results = backend_sim.run(pulse_qobj, system_model) + results = backend_sim.run(pulse_qobj, system_model=system_model) + + Alternatively, an instance of the ``PulseSimulator`` may be further configured to contain more + information present in a real backend. The simplest way to do this is to instantiate the + ``PulseSimulator`` from a real backend: + + .. code-block:: python + + armonk_sim = qiskit.providers.aer.PulseSimulator.from_backend(FakeArmonk()) + pulse_qobj = assemble(schedules, backend=armonk_sim) + armonk_sim.run(pulse_qobj) + + In the above example, the ``PulseSimulator`` copies all configuration and default data from + ``FakeArmonk()``, and as such has the same affect as ``FakeArmonk()`` when passed as an + argument to ``assemble``. Furthermore it constructs a + :class:`~qiskit.providers.aer.pulse.PulseSystemModel` from the model details in the supplied + backend, which is then used in simulation. **Supported PulseQobj parameters** @@ -77,91 +125,205 @@ class PulseSimulator(AerBackend): **Other options** - :meth:`PulseSimulator.run` takes an additional ``dict`` argument ``backend_options`` for - customization. Accepted keys: + Additional valid keyword arguments for ``run()``: * ``'solver_options'``: A ``dict`` for solver options. Accepted keys are ``'atol'``, ``'rtol'``, ``'nsteps'``, ``'max_step'``, ``'num_cpus'``, ``'norm_tol'``, and ``'norm_steps'``. """ + def __init__(self, + configuration=None, + properties=None, + defaults=None, + provider=None, + **backend_options): + + if configuration is None: + configuration = BackendConfiguration.from_dict( + DEFAULT_CONFIGURATION) + else: + configuration = copy.copy(configuration) + configuration.meas_levels = self._meas_levels(configuration.meas_levels) + + if defaults is None: + defaults = PulseDefaults(qubit_freq_est=[inf], + meas_freq_est=[inf], + buffer=0, + cmd_def=[], + pulse_library=[]) + + super().__init__(configuration, + properties=properties, + defaults=defaults, + provider=provider, + backend_options=backend_options) - DEFAULT_CONFIGURATION = { - 'backend_name': 'pulse_simulator', - 'backend_version': __version__, - 'n_qubits': 20, - 'coupling_map': None, - 'url': 'https://github.com/Qiskit/qiskit-aer', - 'simulator': True, - 'meas_levels': [0, 1, 2], - 'local': True, - 'conditional': True, - 'open_pulse': True, - 'memory': False, - 'max_shots': int(1e6), - 'description': 'A pulse-based Hamiltonian simulator for Pulse Qobj files', - 'gates': [], - 'basis_gates': [] - } - - def __init__(self, configuration=None, provider=None): - - # purpose of defaults is to pass assemble checks - self._defaults = PulseDefaults(qubit_freq_est=[inf], - meas_freq_est=[inf], - buffer=0, - cmd_def=[], - pulse_library=[]) - super().__init__(self, - BackendConfiguration.from_dict(self.DEFAULT_CONFIGURATION), - provider=provider) - - def run(self, qobj, system_model, backend_options=None, validate=False): - """Run a qobj on system_model. + # Set up default system model + subsystem_list = backend_options.get('subsystem_list', None) + if backend_options.get('system_model') is None: + if hasattr(configuration, 'hamiltonian'): + system_model = PulseSystemModel.from_config( + configuration, subsystem_list) + self._set_system_model(system_model) + + # pylint: disable=arguments-differ, missing-param-doc + def run(self, + qobj, + *args, + backend_options=None, # DEPRECATED + validate=True, + **run_options): + """Run a qobj on the backend. Args: - qobj (PulseQobj): Qobj for pulse Schedules to run - system_model (PulseSystemModel): Physical model to run simulation on - backend_options (dict): Other options - validate (bool): Flag for validation checks + qobj (QasmQobj): The Qobj to be executed. + backend_options (dict or None): DEPRECATED dictionary of backend options + for the execution (default: None). + validate (bool): validate the Qobj before running (default: True). + run_options (kwargs): additional run time backend options. Returns: - Result: results of simulation + AerJob: The simulation job. + + Additional Information: + * kwarg options specified in ``run_options`` will override options + of the same kwarg specified in the simulator options, the + ``backend_options`` and the ``Qobj.config``. + + * The entries in the ``backend_options`` will be combined with + the ``Qobj.config`` dictionary with the values of entries in + ``backend_options`` taking precedence. This kwarg is deprecated + and direct kwarg's should be used for options to pass them to + ``run_options``. """ - # Submit job - job_id = str(uuid.uuid4()) - aer_job = AerJob(self, job_id, self._run_job, qobj, system_model, - backend_options, validate) - aer_job.submit() - return aer_job - - def _run_job(self, job_id, qobj, system_model, backend_options, validate): - """Run a qobj job""" - start = time.time() - if validate: - self._validate(qobj, backend_options, noise_model=None) - # Send problem specification to pulse_controller and get results - results = pulse_controller(qobj, system_model, backend_options) - end = time.time() - return self._format_results(job_id, results, end - start, qobj.qobj_id) - - def _format_results(self, job_id, results, time_taken, qobj_id): - """Construct Result object from simulator output.""" - # Add result metadata - output = {} - output['qobj_id'] = qobj_id - output['results'] = results - output['success'] = True - output["job_id"] = job_id - output["date"] = datetime.datetime.now().isoformat() - output["backend_name"] = self.name() - output["backend_version"] = self.configuration().backend_version - output["time_taken"] = time_taken - return Result.from_dict(output) - - def defaults(self): - """Return defaults. + if args: + if isinstance(args[0], PulseSystemModel): + warn( + 'Passing `system_model` as a positional argument to' + ' `PulseSimulator.run` has been deprecated as of' + ' qiskit-aer 0.7.0 and will be removed no earlier than 3' + ' months from that release date. Pass `system_model` as a kwarg' + ' `system_model=model` instead.', + DeprecationWarning, + stacklevel=3) + run_options['system_model'] = args[0] + if len(args) > 1: + backend_options = args[1] + if len(args) > 2: + validate = args[3] + elif isinstance(args[0], bool): + validate = args[0] + if len(args) > 1: + backend_options = args[1] + return super().run(qobj, backend_options=backend_options, validate=validate, + **run_options) + + @property + def _system_model(self): + return self._options.get('system_model') + + @classmethod + def from_backend(cls, backend, **options): + """Initialize simulator from backend.""" + configuration = copy.copy(backend.configuration()) + defaults = copy.copy(backend.defaults()) + properties = copy.copy(backend.properties()) + + backend_name = 'pulse_simulator({})'.format(configuration.backend_name) + description = 'A Pulse-based simulator configured from the backend: ' + description += configuration.backend_name + + sim = cls(configuration=configuration, + properties=properties, + defaults=defaults, + backend_name=backend_name, + description=description, + **options) + return sim + + def _execute(self, qobj): + """Execute a qobj on the backend. + + Args: + qobj (PulseQobj): simulator input. Returns: - PulseDefaults: object for passing assemble. + dict: return a dictionary of results. """ - return self._defaults + qobj.config.qubit_freq_est = self.defaults().qubit_freq_est + return pulse_controller(qobj) + + def _set_option(self, key, value): + """Set pulse simulation options and update backend.""" + if key == 'meas_levels': + self._set_configuration_option(key, self._meas_levels(value)) + return + + # Handle cases that require updating two places + if key in ['dt', 'u_channel_lo']: + self._set_configuration_option(key, value) + if self._system_model is not None: + setattr(self._system_model, key, value) + return + + if key == 'hamiltonian': + # if option is hamiltonian, set in configuration and reconstruct pulse system model + subsystem_list = self._options.get('subsystem_list', None) + system_model = PulseSystemModel.from_config(self.configuration(), + subsystem_list) + super()._set_option('system_model', system_model) + self._set_configuration_option(key, value) + return + + # if system model is specified directly + if key == 'system_model': + if hasattr(self.configuration(), 'hamiltonian'): + warn('Specifying both a configuration with a Hamiltonian and a ' + 'system model may result in inconsistencies.') + # Set config dt and u_channel_lo to system model values + self._set_system_model(value) + return + + # Set all other options from AerBackend + super()._set_option(key, value) + + def _set_system_model(self, system_model): + """Set system model option""" + self._set_configuration_option( + 'dt', getattr(system_model, 'dt', [])) + self._set_configuration_option( + 'u_channel_lo', getattr(system_model, 'u_channel_lo', [])) + super()._set_option('system_model', system_model) + + def _validate(self, qobj): + """Validation of qobj. + + Ensures that exactly one Acquire instruction is present in each + schedule. Checks SystemModel is in qobj config + """ + if getattr(qobj.config, 'system_model', None) is None: + raise AerError("PulseSimulator requires a system model to run.") + + for exp in qobj.experiments: + num_acquires = 0 + for instruction in exp.instructions: + if instruction.name == 'acquire': + num_acquires += 1 + + if num_acquires > 1: + raise AerError("PulseSimulator does not support multiple Acquire " + "instructions in a single schedule.") + + if num_acquires == 0: + raise AerError("PulseSimulator requires at least one Acquire " + "instruction per schedule.") + + @staticmethod + def _meas_levels(meas_levels): + """Function for setting meas_levels in a pulse simulator configuration.""" + if 0 in meas_levels: + warn('Measurement level 0 not supported in pulse simulator.') + tmp = copy.copy(meas_levels) + tmp.remove(0) + return tmp + return meas_levels diff --git a/qiskit/providers/aer/backends/qasm_simulator.py b/qiskit/providers/aer/backends/qasm_simulator.py index f652d4a052..0dc0908ba8 100644 --- a/qiskit/providers/aer/backends/qasm_simulator.py +++ b/qiskit/providers/aer/backends/qasm_simulator.py @@ -13,13 +13,15 @@ Qiskit Aer qasm simulator backend. """ +import copy import logging -from math import log2 -from qiskit.util import local_hardware_info from qiskit.providers.models import QasmBackendConfiguration -from .aerbackend import AerBackend + from ..version import __version__ -# pylint: disable=import-error,no-name-in-module +from .aerbackend import AerBackend +from .backend_utils import (cpp_execute, available_methods, + MAX_QUBITS_STATEVECTOR) +# pylint: disable=import-error, no-name-in-module from .controller_wrappers import qasm_controller_execute logger = logging.getLogger(__name__) @@ -29,34 +31,41 @@ class QasmSimulator(AerBackend): """ Noisy quantum circuit simulator backend. + **Configurable Options** + The `QasmSimulator` supports multiple simulation methods and - configurable options for each simulation method. These options are - specified in a dictionary which may be passed to the simulator using - the ``backend_options`` kwarg for :meth:`QasmSimulator.run` or - ``qiskit.execute``. + configurable options for each simulation method. These may be set using the + appropriate kwargs during initialization. They can also be set of updated + using the :meth:`set_options` method. - The default behavior chooses a simulation method automatically based on - the input circuit and noise model. A custom method can be specified using the - ``"method"`` field in ``backend_options`` as illustrated in the following - example. Available simulation methods and additional backend options are - listed below. + Run-time options may also be specified as kwargs using the :meth:`run` method. + These will not be stored in the backend and will only apply to that execution. + They will also override any previously set options. - **Example** + For example, to configure a density matrix simulator with a custom noise + model to use for every execution .. code-block:: python - backend = QasmSimulator() - backend_options = {"method": "statevector"} + noise_model = NoiseModel.from_backend(backend) + backend = QasmSimulator(method='density_matrix', + noise_model=noise_model) - # Circuit execution - job = execute(circuits, backend, backend_options=backend_options) + **Simulating an IBMQ Backend** + + The simulator can be automatically configured to mimic an IBMQ backend using + the :meth:`from_backend` method. This will configure the simulator to use the + basic device :class:`NoiseModel` for that backend, and the same basis gates + and coupling map. + + .. code-block:: python - # Qobj execution - job = backend.run(qobj, backend_options=backend_options) + backend = QasmSimulator.from_backend(backend) - **Simulation method** + **Simulation Method Option** - Available simulation methods are: + The simulation method is set using the ``method`` kwarg. + Supported simulation methods are: * ``"statevector"``: A dense statevector simulation that can sample measurement outcomes from *ideal* circuits with all measurements at @@ -95,36 +104,33 @@ class QasmSimulator(AerBackend): automatically for each circuit based on the circuit instructions, number of qubits, and noise model. - **Backend options** + **Additional Backend Options** - The following backend options may be used with in the - ``backend_options`` kwarg for :meth:`QasmSimulator.run` or - ``qiskit.execute``: + The following simulator specific backend options are supported - * ``"method"`` (str): Set the simulation method. See backend methods - for additional information (Default: "automatic"). + * ``method`` (str): Set the simulation method (Default: ``"automatic"``). - * ``"precision"`` (str): Set the floating point precision for - certain simulation methods to either "single" or "double" - precision (default: "double"). + * ``precision`` (str): Set the floating point precision for + certain simulation methods to either ``"single"`` or ``"double"`` + precision (default: ``"double"``). - * ``"zero_threshold"`` (double): Sets the threshold for truncating + * ``zero_threshold`` (double): Sets the threshold for truncating small values to zero in the result data (Default: 1e-10). - * ``"validation_threshold"`` (double): Sets the threshold for checking + * ``validation_threshold`` (double): Sets the threshold for checking if initial states are valid (Default: 1e-8). - * ``"max_parallel_threads"`` (int): Sets the maximum number of CPU + * ``max_parallel_threads`` (int): Sets the maximum number of CPU cores used by OpenMP for parallelization. If set to 0 the maximum will be set to the number of CPU cores (Default: 0). - * ``"max_parallel_experiments"`` (int): Sets the maximum number of + * ``max_parallel_experiments`` (int): Sets the maximum number of qobj experiments that may be executed in parallel up to the max_parallel_threads value. If set to 1 parallel circuit execution will be disabled. If set to 0 the maximum will be automatically set to max_parallel_threads (Default: 1). - * ``"max_parallel_shots"`` (int): Sets the maximum number of + * ``max_parallel_shots`` (int): Sets the maximum number of shots that may be executed in parallel during each experiment execution, up to the max_parallel_threads value. If set to 1 parallel shot execution will be disabled. If set to 0 the @@ -132,18 +138,18 @@ class QasmSimulator(AerBackend): Note that this cannot be enabled at the same time as parallel experiment execution (Default: 0). - * ``"max_memory_mb"`` (int): Sets the maximum size of memory + * ``max_memory_mb`` (int): Sets the maximum size of memory to store a state vector. If a state vector needs more, an error is thrown. In general, a state vector of n-qubits uses 2^n complex values (16 Bytes). If set to 0, the maximum will be automatically set to half the system memory size (Default: 0). - * ``"optimize_ideal_threshold"`` (int): Sets the qubit threshold for + * ``optimize_ideal_threshold`` (int): Sets the qubit threshold for applying circuit optimization passes on ideal circuits. Passes include gate fusion and truncation of unused qubits (Default: 5). - * ``"optimize_noise_threshold"`` (int): Sets the qubit threshold for + * ``optimize_noise_threshold`` (int): Sets the qubit threshold for applying circuit optimization passes on ideal circuits. Passes include gate fusion and truncation of unused qubits (Default: 12). @@ -151,7 +157,7 @@ class QasmSimulator(AerBackend): These backend options only apply when using the ``"statevector"`` simulation method: - * ``"statevector_parallel_threshold"`` (int): Sets the threshold that + * ``statevector_parallel_threshold`` (int): Sets the threshold that the number of qubits must be greater than to enable OpenMP parallelization for matrix multiplication during execution of an experiment. If parallel circuit or shot execution is enabled @@ -159,7 +165,7 @@ class QasmSimulator(AerBackend): max_parallel_threads. Note that setting this too low can reduce performance (Default: 14). - * ``"statevector_sample_measure_opt"`` (int): Sets the threshold that + * ``statevector_sample_measure_opt`` (int): Sets the threshold that the number of qubits must be greater than to enable a large qubit optimized implementation of measurement sampling. Note that setting this two low can reduce performance (Default: 10) @@ -167,7 +173,7 @@ class QasmSimulator(AerBackend): These backend options only apply when using the ``"stabilizer"`` simulation method: - * ``"stabilizer_max_snapshot_probabilities"`` (int): set the maximum + * ``stabilizer_max_snapshot_probabilities`` (int): set the maximum qubit number for the `~qiskit.providers.aer.extensions.SnapshotProbabilities` instruction (Default: 32). @@ -175,14 +181,14 @@ class QasmSimulator(AerBackend): These backend options only apply when using the ``"extended_stabilizer"`` simulation method: - * ``"extended_stabilizer_measure_sampling"`` (bool): Enable measure + * ``extended_stabilizer_measure_sampling`` (bool): Enable measure sampling optimization on supported circuits. This prevents the simulator from re-running the measure monte-carlo step for each shot. Enabling measure sampling may reduce accuracy of the measurement counts if the output distribution is strongly peaked (Default: False). - * ``"extended_stabilizer_mixing_time"`` (int): Set how long the + * ``extended_stabilizer_mixing_time`` (int): Set how long the monte-carlo method runs before performing measurements. If the output distribution is strongly peaked, this can be decreased alongside setting extended_stabilizer_disable_measurement_opt @@ -193,49 +199,45 @@ class QasmSimulator(AerBackend): smaller error needs more memory and computational time (Default: 0.05). - * ``"extended_stabilizer_norm_estimation_samples"`` (int): Number of + * ``extended_stabilizer_norm_estimation_samples`` (int): Number of samples used to compute the correct normalization for a statevector snapshot (Default: 100). - * ``"extended_stabilizer_parallel_threshold"`` (int): Set the minimum + * ``extended_stabilizer_parallel_threshold`` (int): Set the minimum size of the extended stabilizer decomposition before we enable OpenMP parallelization. If parallel circuit or shot execution is enabled this will only use unallocated CPU cores up to max_parallel_threads (Default: 100). - These backend options apply in circuit optimization passes: - - * ``"fusion_enable"`` (bool): Enable fusion optimization in circuit - optimization passes [Default: True] - * ``"fusion_verbose"`` (bool): Output gates generated in fusion optimization - into metadata [Default: False] - * ``"fusion_max_qubit"`` (int): Maximum number of qubits for a operation generated - in a fusion optimization [Default: 5] - * ``"fusion_threshold"`` (int): Threshold that number of qubits must be greater - than or equal to enable fusion optimization [Default: 20] - These backend options only apply when using the ``"matrix_product_state"`` simulation method: - * ``"matrix_product_state_max_bond_dimension"`` (int): Sets a limit + * ``matrix_product_state_max_bond_dimension`` (int): Sets a limit on the number of Schmidt coefficients retained at the end of the svd algorithm. Coefficients beyond this limit will be discarded. (Default: None, i.e., no limit on the bond dimension). - * ``"matrix_product_state_truncation_threshold"`` (double): + * ``matrix_product_state_truncation_threshold`` (double): Discard the smallest coefficients for which the sum of their squares is smaller than this threshold. (Default: 1e-16). - """ + These backend options apply in circuit optimization passes: - MAX_QUBIT_MEMORY = int( - log2(local_hardware_info()['memory'] * (1024**3) / 16)) + * ``fusion_enable`` (bool): Enable fusion optimization in circuit + optimization passes [Default: True] + * ``fusion_verbose`` (bool): Output gates generated in fusion optimization + into metadata [Default: False] + * ``fusion_max_qubit`` (int): Maximum number of qubits for a operation generated + in a fusion optimization [Default: 5] + * ``fusion_threshold`` (int): Threshold that number of qubits must be greater + than or equal to enable fusion optimization [Default: 20] + """ - DEFAULT_CONFIGURATION = { + _DEFAULT_CONFIGURATION = { 'backend_name': 'qasm_simulator', 'backend_version': __version__, - 'n_qubits': MAX_QUBIT_MEMORY, + 'n_qubits': MAX_QUBITS_STATEVECTOR, 'url': 'https://github.com/Qiskit/qiskit-aer', 'simulator': True, 'local': True, @@ -243,27 +245,121 @@ class QasmSimulator(AerBackend): 'open_pulse': False, 'memory': True, 'max_shots': int(1e6), - 'description': 'A C++ simulator with realistic noise for QASM Qobj files', + 'description': 'A C++ QasmQobj simulator with noise', 'coupling_map': None, 'basis_gates': [ - 'u1', 'u2', 'u3', 'p', 'r', 'rx', 'ry', 'rz', 'id', 'x', 'y', - 'z', 'h', 's', 'sdg', 'sx', 't', 'tdg', 'swap', 'cx', 'cy', - 'cz', 'csx', 'cp', 'cu1', 'cu2', 'cu3', 'rxx', 'ryy', 'rzz', - 'rzx', 'ccx', 'cswap', 'mcx', 'mcy', 'mcz', 'mcsx', 'mcp', - 'mcu1', 'mcu2', 'mcu3', 'mcrx', 'mcry', 'mcrz', 'mcr', - 'mcswap', 'unitary', 'diagonal', 'multiplexer', 'initialize', - 'kraus', 'superop', 'roerror', 'delay' + 'u1', 'u2', 'u3', 'p', 'r', 'rx', 'ry', 'rz', 'id', 'x', + 'y', 'z', 'h', 's', 'sdg', 'sx', 't', 'tdg', 'swap', 'cx', + 'cy', 'cz', 'csx', 'cp', 'cu1', 'cu2', 'cu3', 'rxx', 'ryy', + 'rzz', 'rzx', 'ccx', 'cswap', 'mcx', 'mcy', 'mcz', 'mcsx', + 'mcp', 'mcu1', 'mcu2', 'mcu3', 'mcrx', 'mcry', 'mcrz', + 'mcr', 'mcswap', 'unitary', 'diagonal', 'multiplexer', + 'initialize', 'kraus', 'roerror', 'delay' ], 'gates': [] } - def __init__(self, configuration=None, provider=None): - super().__init__( - qasm_controller_execute(), - QasmBackendConfiguration.from_dict(self.DEFAULT_CONFIGURATION), - provider=provider) + _AVAILABLE_METHODS = None + + def __init__(self, + configuration=None, + properties=None, + provider=None, + **backend_options): + + self._controller = qasm_controller_execute() + + # Update available methods for class + if QasmSimulator._AVAILABLE_METHODS is None: + QasmSimulator._AVAILABLE_METHODS = available_methods( + self._controller, [ + 'automatic', 'statevector', 'statevector_gpu', + 'statevector_thrust', 'density_matrix', + 'density_matrix_gpu', 'density_matrix_thrust', + 'stabilizer', 'matrix_product_state', 'extended_stabilizer' + ]) + + if configuration is None: + configuration = self._method_configuration() + super().__init__(configuration, + properties=properties, + available_methods=QasmSimulator._AVAILABLE_METHODS, + provider=provider, + backend_options=backend_options) + + @classmethod + def from_backend(cls, backend, **options): + """Initialize simulator from backend.""" + # pylint: disable=import-outside-toplevel + # Avoid cyclic import + from ..noise.noise_model import NoiseModel + + # Get configuration and properties from backend + configuration = copy.copy(backend.configuration()) + properties = copy.copy(backend.properties()) + + # Customize configuration name + name = configuration.backend_name + configuration.backend_name = 'qasm_simulator({})'.format(name) + + # Use automatic noise model if none is provided + if 'noise_model' not in options: + noise_model = NoiseModel.from_backend(backend) + if not noise_model.is_ideal(): + options['noise_model'] = noise_model + + # Initialize simulator + sim = cls(configuration=configuration, + properties=properties, + **options) + return sim + + def _execute(self, qobj): + """Execute a qobj on the backend. + + Args: + qobj (QasmQobj): simulator input. + + Returns: + dict: return a dictionary of results. + """ + return cpp_execute(self._controller, qobj) + + def _set_option(self, key, value): + """Set the simulation method and update configuration. - def _validate(self, qobj, backend_options, noise_model): + Args: + key (str): key to update + value (any): value to update. + + Raises: + AerError: if key is 'method' and val isn't in available methods. + """ + # If key is noise_model we also change the simulator config + # to use the noise_model basis gates by default. + if key == 'noise_model' and value is not None: + self._set_configuration_option('basis_gates', value.basis_gates) + + # If key is method we update our configurations + if key == 'method': + method_config = self._method_configuration(value) + self._set_configuration_option('description', method_config.description) + self._set_configuration_option('backend_name', method_config.backend_name) + self._set_configuration_option('n_qubits', method_config.n_qubits) + + # Take intersection of method basis gates and noise model basis gates + # if there is a noise model which has already set the basis gates + basis_gates = method_config.basis_gates + if 'noise_model' in self.options: + noise_basis_gates = self.options['noise_model'].basis_gates + basis_gates = list( + set(basis_gates).intersection(noise_basis_gates)) + self._set_configuration_option('basis_gates', basis_gates) + + # Set all other options from AerBackend + super()._set_option(key, value) + + def _validate(self, qobj): """Semantic validations of the qobj which cannot be done via schemas. Warn if no measurements in circuit with classical registers. @@ -285,3 +381,56 @@ def _validate(self, qobj, backend_options, noise_model): 'No measurements in circuit "%s": ' 'count data will return all zeros.', experiment.header.name) + + @staticmethod + def _method_configuration(method=None): + """Return QasmBackendConfiguration.""" + # Default configuration + config = QasmBackendConfiguration.from_dict( + QasmSimulator._DEFAULT_CONFIGURATION) + + # Statevector methods + if method in ['statevector', 'statevector_gpu', 'statevector_thrust']: + config.description = 'A C++ QasmQobj statevector simulator with noise' + + # Density Matrix methods + elif method in [ + 'density_matrix', 'density_matrix_gpu', 'density_matrix_thrust' + ]: + config.n_qubits = config.n_qubits // 2 + config.description = 'A C++ QasmQobj density matrix simulator with noise' + config.basis_gates = [ + 'u1', 'u2', 'u3', 'p', 'r', 'rx', 'ry', 'rz', 'id', 'x', + 'y', 'z', 'h', 's', 'sdg', 'sx', 't', 'tdg', 'swap', 'cx', + 'cy', 'cz', 'csx', 'cp', 'cu1', 'cu2', 'cu3', 'rxx', 'ryy', + 'rzz', 'rzx', 'ccx', 'unitary', 'diagonal', 'kraus', 'superop' + 'roerror', 'delay' + ] + + # Matrix product state method + elif method == 'matrix_product_state': + config.description = 'A C++ QasmQobj matrix product state simulator with noise' + config.basis_gates = [ + 'u1', 'u2', 'u3', 'cx', 'cz', 'id', 'x', 'y', 'z', 'h', 's', + 'sdg', 't', 'tdg', 'swap', 'ccx', 'unitary', 'roerror', 'delay' + ] + + # Stabilizer method + elif method == 'stabilizer': + config.n_qubits = 5000 # TODO: estimate from memory + config.description = 'A C++ QasmQobj Clifford stabilizer simulator with noise' + config.basis_gates = [ + 'id', 'x', 'y', 'z', 'h', 's', 'sdg', 'cx', 'cy', 'cz', + 'swap', 'roerror', 'delay' + ] + + # Extended stabilizer method + elif method == 'extended_stabilizer': + config.n_qubits = 63 # TODO: estimate from memory + config.description = 'A C++ QasmQobj ranked stabilizer simulator with noise' + config.basis_gates = [ + 'cx', 'cz', 'id', 'x', 'y', 'z', 'h', 's', 'sdg', 'swap', + 'u0', 'u1', 'ccx', 'ccz', 'roerror', 'delay' + ] + + return config diff --git a/qiskit/providers/aer/backends/statevector_simulator.py b/qiskit/providers/aer/backends/statevector_simulator.py index 20733023c7..f03ceab0ae 100644 --- a/qiskit/providers/aer/backends/statevector_simulator.py +++ b/qiskit/providers/aer/backends/statevector_simulator.py @@ -9,19 +9,20 @@ # 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. - """ Qiskit Aer statevector simulator backend. """ import logging -from math import log2 from qiskit.util import local_hardware_info from qiskit.providers.models import QasmBackendConfiguration -from .aerbackend import AerBackend + from ..aererror import AerError from ..version import __version__ -# pylint: disable=import-error,no-name-in-module +from .aerbackend import AerBackend +from .backend_utils import (cpp_execute, available_methods, + MAX_QUBITS_STATEVECTOR) +# pylint: disable=import-error, no-name-in-module from .controller_wrappers import statevector_controller_execute # Logger @@ -31,35 +32,58 @@ class StatevectorSimulator(AerBackend): """Ideal quantum circuit statevector simulator - **Backend options** + **Configurable Options** + + The `StatevectorSimulator` supports CPU and GPU simulation methods and + additional configurable options. These may be set using the appropriate kwargs + during initialization. They can also be set of updated using the + :meth:`set_options` method. + + Run-time options may also be specified as kwargs using the :meth:`run` method. + These will not be stored in the backend and will only apply to that execution. + They will also override any previously set options. + + For example, to configure a a single-precision simulator - The following backend options may be used with in the - ``backend_options`` kwarg for :meth:`StatevectorSimulator.run` or - ``qiskit.execute``. + .. code-block:: python - * ``"zero_threshold"`` (double): Sets the threshold for truncating + backend = StatevectorSimulator(precision='single') + + **Backend Options** + + The following configurable backend options are supported + + * ``method`` (str): Set the simulation method supported methods are + ``"statevector"`` for CPU simulation, and ``"statevector_gpu"`` + for GPU simulation (Default: ``"statevector"``). + + * ``precision`` (str): Set the floating point precision for + certain simulation methods to either ``"single"`` or ``"double"`` + precision (default: ``"double"``). + + * ``zero_threshold`` (double): Sets the threshold for truncating small values to zero in the result data (Default: 1e-10). - * ``"validation_threshold"`` (double): Sets the threshold for checking + * ``validation_threshold`` (double): Sets the threshold for checking if the initial statevector is valid (Default: 1e-8). - * ``"max_parallel_threads"`` (int): Sets the maximum number of CPU + * ``max_parallel_threads`` (int): Sets the maximum number of CPU cores used by OpenMP for parallelization. If set to 0 the maximum will be set to the number of CPU cores (Default: 0). - * ``"max_parallel_experiments"`` (int): Sets the maximum number of + * ``max_parallel_experiments`` (int): Sets the maximum number of qobj experiments that may be executed in parallel up to the max_parallel_threads value. If set to 1 parallel circuit execution will be disabled. If set to 0 the maximum will be automatically set to max_parallel_threads (Default: 1). - * ``"max_memory_mb"`` (int): Sets the maximum size of memory + * ``max_memory_mb`` (int): Sets the maximum size of memory to store a state vector. If a state vector needs more, an error is thrown. In general, a state vector of n-qubits uses 2^n complex values (16 Bytes). If set to 0, the maximum will be automatically set to half the system memory size (Default: 0). - * ``"statevector_parallel_threshold"`` (int): Sets the threshold that + * ``statevector_parallel_threshold`` (int): Sets the threshold that "n_qubits" must be greater than to enable OpenMP parallelization for matrix multiplication during execution of an experiment. If parallel circuit or shot execution is enabled @@ -68,12 +92,10 @@ class StatevectorSimulator(AerBackend): performance (Default: 14). """ - MAX_QUBIT_MEMORY = int(log2(local_hardware_info()['memory'] * (1024 ** 3) / 16)) - - DEFAULT_CONFIGURATION = { + _DEFAULT_CONFIGURATION = { 'backend_name': 'statevector_simulator', 'backend_version': __version__, - 'n_qubits': MAX_QUBIT_MEMORY, + 'n_qubits': MAX_QUBITS_STATEVECTOR, 'url': 'https://github.com/Qiskit/qiskit-aer', 'simulator': True, 'local': True, @@ -81,30 +103,63 @@ class StatevectorSimulator(AerBackend): 'open_pulse': False, 'memory': True, 'max_shots': int(1e6), # Note that this backend will only ever - # perform a single shot. This value is just - # so that the default shot value for execute - # will not raise an error when trying to run - # a simulation + # perform a single shot. This value is just + # so that the default shot value for execute + # will not raise an error when trying to run + # a simulation 'description': 'A C++ statevector simulator for QASM Qobj files', 'coupling_map': None, 'basis_gates': [ - 'u1', 'u2', 'u3', 'p', 'r', 'rx', 'ry', 'rz', 'id', 'x', 'y', - 'z', 'h', 's', 'sdg', 'sx', 't', 'tdg', 'swap', 'cx', 'cy', - 'cz', 'csx', 'cp', 'cu1', 'cu2', 'cu3', 'rxx', 'ryy', 'rzz', - 'rzx', 'ccx', 'cswap', 'mcx', 'mcy', 'mcz', 'mcsx', 'mcp', - 'mcu1', 'mcu2', 'mcu3', 'mcrx', 'mcry', 'mcrz', 'mcr', - 'mcswap', 'unitary', 'diagonal', 'multiplexer', 'initialize', - 'kraus', 'roerror', 'delay' + 'u1', 'u2', 'u3', 'p', 'r', 'rx', 'ry', 'rz', 'id', 'x', + 'y', 'z', 'h', 's', 'sdg', 'sx', 't', 'tdg', 'swap', 'cx', + 'cy', 'cz', 'csx', 'cp', 'cu1', 'cu2', 'cu3', 'rxx', 'ryy', + 'rzz', 'rzx', 'ccx', 'cswap', 'mcx', 'mcy', 'mcz', 'mcsx', + 'mcp', 'mcu1', 'mcu2', 'mcu3', 'mcrx', 'mcry', 'mcrz', + 'mcr', 'mcswap', 'unitary', 'diagonal', 'multiplexer', + 'initialize', 'kraus', 'roerror', 'delay' ], 'gates': [] } - def __init__(self, configuration=None, provider=None): - super().__init__(statevector_controller_execute(), - QasmBackendConfiguration.from_dict(self.DEFAULT_CONFIGURATION), - provider=provider) + # Cache available methods + _AVAILABLE_METHODS = None + + def __init__(self, + configuration=None, + properties=None, + provider=None, + **backend_options): + + self._controller = statevector_controller_execute() + + if StatevectorSimulator._AVAILABLE_METHODS is None: + StatevectorSimulator._AVAILABLE_METHODS = available_methods( + self._controller, [ + 'automatic', 'statevector', 'statevector_gpu', + 'statevector_thrust' + ]) + if configuration is None: + configuration = QasmBackendConfiguration.from_dict( + StatevectorSimulator._DEFAULT_CONFIGURATION) + super().__init__( + configuration, + properties=properties, + available_methods=StatevectorSimulator._AVAILABLE_METHODS, + provider=provider, + backend_options=backend_options) + + def _execute(self, qobj): + """Execute a qobj on the backend. + + Args: + qobj (QasmQobj): simulator input. + + Returns: + dict: return a dictionary of results. + """ + return cpp_execute(self._controller, qobj) - def _validate(self, qobj, backend_options, noise_model): + def _validate(self, qobj): """Semantic validations of the qobj which cannot be done via schemas. Some of these may later move to backend schemas. @@ -112,7 +167,7 @@ def _validate(self, qobj, backend_options, noise_model): 2. Check number of qubits will fit in local memory. """ name = self.name() - if noise_model is not None: + if getattr(qobj.config, 'noise_model', None) is not None: raise AerError("{} does not support noise.".format(name)) n_qubits = qobj.config.n_qubits @@ -120,7 +175,8 @@ def _validate(self, qobj, backend_options, noise_model): if n_qubits > max_qubits: raise AerError( 'Number of qubits ({}) is greater than max ({}) for "{}" with {} GB system memory.' - .format(n_qubits, max_qubits, name, int(local_hardware_info()['memory']))) + .format(n_qubits, max_qubits, name, + int(local_hardware_info()['memory']))) if qobj.config.shots != 1: logger.info('"%s" only supports 1 shot. Setting shots=1.', name) @@ -129,7 +185,7 @@ def _validate(self, qobj, backend_options, noise_model): for experiment in qobj.experiments: exp_name = experiment.header.name if getattr(experiment.config, 'shots', 1) != 1: - logger.info('"%s" only supports 1 shot. ' - 'Setting shots=1 for circuit "%s".', - name, exp_name) + logger.info( + '"%s" only supports 1 shot. ' + 'Setting shots=1 for circuit "%s".', name, exp_name) experiment.config.shots = 1 diff --git a/qiskit/providers/aer/backends/unitary_simulator.py b/qiskit/providers/aer/backends/unitary_simulator.py index c667c51393..f671d65150 100644 --- a/qiskit/providers/aer/backends/unitary_simulator.py +++ b/qiskit/providers/aer/backends/unitary_simulator.py @@ -16,14 +16,15 @@ """ import logging -from math import log2, sqrt from qiskit.util import local_hardware_info from qiskit.providers.models import QasmBackendConfiguration -from .aerbackend import AerBackend from ..aererror import AerError from ..version import __version__ -# pylint: disable=import-error,no-name-in-module +from .aerbackend import AerBackend +from .backend_utils import (cpp_execute, available_methods, + MAX_QUBITS_STATEVECTOR) +# pylint: disable=import-error, no-name-in-module from .controller_wrappers import unitary_controller_execute # Logger @@ -33,11 +34,34 @@ class UnitarySimulator(AerBackend): """Ideal quantum circuit unitary simulator. - **Backend options** + **Configurable Options** + + The `UnitarySimulator` supports CPU and GPU simulation methods and + additional configurable options. These may be set using the appropriate kwargs + during initialization. They can also be set of updated using the + :meth:`set_options` method. + + Run-time options may also be specified as kwargs using the :meth:`run` method. + These will not be stored in the backend and will only apply to that execution. + They will also override any previously set options. + + For example, to configure a a single-precision simulator + + .. code-block:: python + + backend = UnitarySimulator(precision='single') + + **Backend Options** + + The following configurable backend options are supported + + * ``method`` (str): Set the simulation method supported methods are + ``"unitary"`` for CPU simulation, and ``"untiary_gpu"`` + for GPU simulation (Default: ``"unitary"``). - The following backend options may be used with in the - ``backend_options`` kwarg for :meth:`UnitarySimulator.run` or - ``qiskit.execute``. + * ``precision`` (str): Set the floating point precision for + certain simulation methods to either ``"single"`` or ``"double"`` + precision (default: ``"double"``). * ``"initial_unitary"`` (matrix_like): Sets a custom initial unitary matrix for the simulation instead of identity (Default: None). @@ -74,15 +98,11 @@ class UnitarySimulator(AerBackend): performance (Default: 14). """ - MAX_QUBIT_MEMORY = int( - log2(sqrt(local_hardware_info()['memory'] * (1024**3) / 16))) - - DEFAULT_CONFIGURATION = { + _DEFAULT_CONFIGURATION = { 'backend_name': 'unitary_simulator', 'backend_version': __version__, - 'n_qubits': MAX_QUBIT_MEMORY, - 'url': - 'https://github.com/Qiskit/qiskit-aer', + 'n_qubits': MAX_QUBITS_STATEVECTOR // 2, + 'url': 'https://github.com/Qiskit/qiskit-aer', 'simulator': True, 'local': True, 'conditional': False, @@ -96,22 +116,53 @@ class UnitarySimulator(AerBackend): 'description': 'A C++ unitary simulator for QASM Qobj files', 'coupling_map': None, 'basis_gates': [ - 'u1', 'u2', 'u3', 'p', 'r', 'rx', 'ry', 'rz', 'id', 'x', 'y', - 'z', 'h', 's', 'sdg', 'sx', 't', 'tdg', 'swap', 'cx', 'cy', - 'cz', 'csx', 'cp', 'cu1', 'cu2', 'cu3', 'rxx', 'ryy', 'rzz', - 'rzx', 'ccx', 'cswap', 'mcx', 'mcy', 'mcz', 'mcsx', 'mcp', - 'mcu1', 'mcu2', 'mcu3', 'mcrx', 'mcry', 'mcrz', 'mcr', - 'mcswap', 'unitary', 'diagonal', 'multiplexer', 'delay' + 'u1', 'u2', 'u3', 'p', 'r', 'rx', 'ry', 'rz', 'id', 'x', + 'y', 'z', 'h', 's', 'sdg', 'sx', 't', 'tdg', 'swap', 'cx', + 'cy', 'cz', 'csx', 'cp', 'cu1', 'cu2', 'cu3', 'rxx', 'ryy', + 'rzz', 'rzx', 'ccx', 'cswap', 'mcx', 'mcy', 'mcz', 'mcsx', + 'mcp', 'mcu1', 'mcu2', 'mcu3', 'mcrx', 'mcry', 'mcrz', + 'mcr', 'mcswap', 'unitary', 'diagonal', 'multiplexer', 'delay' ], 'gates': [] } - def __init__(self, configuration=None, provider=None): - super().__init__(unitary_controller_execute(), - QasmBackendConfiguration.from_dict(self.DEFAULT_CONFIGURATION), - provider=provider) + _AVAILABLE_METHODS = None + + def __init__(self, + configuration=None, + properties=None, + provider=None, + **backend_options): + + self._controller = unitary_controller_execute() + + if UnitarySimulator._AVAILABLE_METHODS is None: + UnitarySimulator._AVAILABLE_METHODS = available_methods( + self._controller, + ['automatic', 'unitary', 'unitary_gpu', 'unitary_thrust']) + + if configuration is None: + configuration = QasmBackendConfiguration.from_dict( + UnitarySimulator._DEFAULT_CONFIGURATION) + + super().__init__(configuration, + properties=properties, + available_methods=UnitarySimulator._AVAILABLE_METHODS, + provider=provider, + backend_options=backend_options) + + def _execute(self, qobj): + """Execute a qobj on the backend. + + Args: + qobj (QasmQobj): simulator input. + + Returns: + dict: return a dictionary of results. + """ + return cpp_execute(self._controller, qobj) - def _validate(self, qobj, backend_options, noise_model): + def _validate(self, qobj): """Semantic validations of the qobj which cannot be done via schemas. Some of these may later move to backend schemas. 1. Set shots=1 @@ -119,7 +170,7 @@ def _validate(self, qobj, backend_options, noise_model): 3. Check number of qubits will fit in local memory. """ name = self.name() - if noise_model is not None: + if getattr(qobj.config, 'noise_model', None) is not None: raise AerError("{} does not support noise.".format(name)) n_qubits = qobj.config.n_qubits diff --git a/qiskit/providers/aer/noise/noise_model.py b/qiskit/providers/aer/noise/noise_model.py index d8fd2ad950..4b89f41a46 100644 --- a/qiskit/providers/aer/noise/noise_model.py +++ b/qiskit/providers/aer/noise/noise_model.py @@ -23,7 +23,6 @@ from ..backends.aerbackend import AerJSONEncoder from ..backends.qasm_simulator import QasmSimulator - from .noiseerror import NoiseError from .errors.quantum_error import QuantumError from .errors.readout_error import ReadoutError @@ -89,15 +88,15 @@ class NoiseModel: # Get the default basis gates for the Qiskit Aer Qasm Simulator # this is used to decide what are instructions for a noise model # and what are labels for other named instructions - _QASMSIMULATOR_BASIS_GATES = QasmSimulator.DEFAULT_CONFIGURATION[ - 'basis_gates'] + # NOTE: we exclude kraus, roerror, and initialize instructions here + _QASMSIMULATOR_BASIS_GATES = QasmSimulator._DEFAULT_CONFIGURATION['basis_gates'] # Checks for standard 1-3 qubit instructions _1qubit_instructions = set([ "x90", "u1", "u2", "u3", "U", "id", "x", "y", "z", "h", "s", "sdg", "t", "tdg", "r", "rx", "ry", "rz", "p" ]) - _2qubit_instructions = set(["cx", "cz", "swap", "rxx", "ryy", "rzz", + _2qubit_instructions = set(["cx", "cy", "cz", "swap", "rxx", "ryy", "rzz", "rzx", "cu1", "cu2", "cu3", "cp"]) _3qubit_instructions = set(["ccx", "cswap"]) @@ -301,8 +300,27 @@ def from_backend(cls, backend, noise_model.add_quantum_error(error, name, qubits, warnings=warnings) return noise_model - def __repr__(self): - """Display noise model""" + def is_ideal(self): + """Return True if the noise model has no noise terms.""" + # Get default errors + if self._default_quantum_errors: + return False + if self._default_readout_error: + return False + if self._local_quantum_errors: + return False + if self._local_readout_errors: + return False + if self._nonlocal_quantum_errors: + return False + return True + + def __str__(self): + """Noise model string representation""" + + # Check if noise model is ideal + if self.is_ideal(): + return "NoiseModel: Ideal" # Get default errors default_error_ops = [] @@ -331,27 +349,24 @@ def __repr__(self): self._str2qubits(nq_str))) output = "NoiseModel:" - if default_error_ops == [] and local_error_ops == [] and nonlocal_error_ops == []: - output += " Ideal" - else: - output += "\n Basis gates: {}".format(self.basis_gates) - if self._noise_instructions: - output += "\n Instructions with noise: {}".format( - list(self._noise_instructions)) - if self._noise_qubits: - output += "\n Qubits with noise: {}".format( - list(self._noise_qubits)) - if self._x90_gates: - output += "\n X-90 based single qubit gates: {}".format( - list(self._x90_gates)) - if default_error_ops != []: - output += "\n All-qubits errors: {}".format(default_error_ops) - if local_error_ops != []: - output += "\n Specific qubit errors: {}".format( - local_error_ops) - if nonlocal_error_ops != []: - output += "\n Non-local specific qubit errors: {}".format( - nonlocal_error_ops) + output += "\n Basis gates: {}".format(self.basis_gates) + if self._noise_instructions: + output += "\n Instructions with noise: {}".format( + list(self._noise_instructions)) + if self._noise_qubits: + output += "\n Qubits with noise: {}".format( + list(self._noise_qubits)) + if self._x90_gates: + output += "\n X-90 based single qubit gates: {}".format( + list(self._x90_gates)) + if default_error_ops != []: + output += "\n All-qubits errors: {}".format(default_error_ops) + if local_error_ops != []: + output += "\n Specific qubit errors: {}".format( + local_error_ops) + if nonlocal_error_ops != []: + output += "\n Non-local specific qubit errors: {}".format( + nonlocal_error_ops) return output def __eq__(self, other): @@ -398,7 +413,8 @@ def add_basis_gates(self, instructions, warnings=True): # If the instruction is in the default basis gates for the # QasmSimulator we add it to the basis gates. if name in self._QASMSIMULATOR_BASIS_GATES: - if name not in ['measure', 'reset']: + if name not in ['measure', 'reset', 'initialize', + 'kraus', 'superop', 'roerror']: self._basis_gates.add(name) elif warnings: logger.warning( diff --git a/qiskit/providers/aer/pulse/controllers/digest_pulse_qobj.py b/qiskit/providers/aer/pulse/controllers/digest_pulse_qobj.py index d840bfb29e..e504e75d66 100644 --- a/qiskit/providers/aer/pulse/controllers/digest_pulse_qobj.py +++ b/qiskit/providers/aer/pulse/controllers/digest_pulse_qobj.py @@ -64,7 +64,7 @@ def __init__(self): self.experiments = None -def digest_pulse_qobj(qobj, channels, dt, qubit_list, backend_options=None): +def digest_pulse_qobj(qobj, channels, dt, qubit_list): """ Given a PulseQobj (and other parameters), returns a DigestedPulseQobj containing relevant extracted information @@ -73,7 +73,6 @@ def digest_pulse_qobj(qobj, channels, dt, qubit_list, backend_options=None): channels (OrderedDict): channel dictionary dt (float): pulse sample width qubit_list (list): list of qubits to include - backend_options (dict): dict with options that can override all other parameters Returns: DigestedPulseQobj: digested pulse qobj @@ -83,10 +82,6 @@ def digest_pulse_qobj(qobj, channels, dt, qubit_list, backend_options=None): AerError: for unsupported features or invalid qobj TypeError: for arguments of invalid type """ - - if backend_options is None: - backend_options = {} - digested_qobj = DigestedPulseQobj() qobj_dict = qobj.to_dict() @@ -95,10 +90,6 @@ def digest_pulse_qobj(qobj, channels, dt, qubit_list, backend_options=None): # raises errors for unsupported features _unsupported_errors(qobj_dict) - # override anything in qobj_config that is present in backend_options - for key in backend_options.keys(): - qobj_config[key] = backend_options[key] - if 'memory_slots' not in qobj_config: raise ValueError('Number of memory_slots must be specific in Qobj config') diff --git a/qiskit/providers/aer/pulse/controllers/pulse_controller.py b/qiskit/providers/aer/pulse/controllers/pulse_controller.py index c3a514f9a6..207b0b6a27 100644 --- a/qiskit/providers/aer/pulse/controllers/pulse_controller.py +++ b/qiskit/providers/aer/pulse/controllers/pulse_controller.py @@ -29,13 +29,11 @@ from .pulse_utils import get_ode_rhs_functor -def pulse_controller(qobj, system_model, backend_options): +def pulse_controller(qobj): """ Interprets PulseQobj input, runs simulations, and returns results Parameters: - qobj (qobj): pulse qobj containing a list of pulse schedules - system_model (PulseSystemModel): contains system model information - backend_options (dict): dict of options, which overrides other parameters + qobj (PulseQobj): pulse qobj containing a list of pulse schedules Returns: list: simulation results @@ -44,22 +42,17 @@ def pulse_controller(qobj, system_model, backend_options): ValueError: if input is of incorrect format Exception: for invalid ODE options """ - pulse_sim_desc = PulseSimDescription() pulse_de_model = PulseInternalDEModel() - if backend_options is None: - backend_options = {} - - noise_model = backend_options.get('noise_model', None) - - # post warnings for unsupported features - _unsupported_warnings(noise_model) + config = qobj.config # ############################### # ### Extract model parameters # ############################### + system_model = config.system_model + # Get qubit list and number qubit_list = system_model.subsystem_list if qubit_list is None: @@ -84,8 +77,8 @@ def pulse_controller(qobj, system_model, backend_options): estates = [qobj_gen.state(state) for state in ham_model._estates.T[:]] # initial state set here - if 'initial_state' in backend_options: - pulse_sim_desc.initial_state = Qobj(backend_options['initial_state']) + if hasattr(config, 'initial_state'): + pulse_sim_desc.initial_state = Qobj(config.initial_state) else: pulse_sim_desc.initial_state = estates[0] @@ -96,6 +89,11 @@ def pulse_controller(qobj, system_model, backend_options): pulse_de_model.dt = system_model.dt # Parse noise + noise_model = getattr(config, 'noise_model', None) + + # post warnings for unsupported features + _unsupported_warnings(noise_model) + if noise_model: noise = NoiseParser(noise_dict=noise_model, dim_osc=dim_osc, dim_qub=dim_qub) noise.parse() @@ -110,8 +108,7 @@ def pulse_controller(qobj, system_model, backend_options): digested_qobj = digest_pulse_qobj(qobj, pulse_de_model.channels, system_model.dt, - qubit_list, - backend_options) + qubit_list) # extract simulation-description level qobj content pulse_sim_desc.shots = digested_qobj.shots @@ -133,12 +130,14 @@ def pulse_controller(qobj, system_model, backend_options): # if it wasn't specified in the PulseQobj, draw from system_model if qubit_lo_freq is None: - qubit_lo_freq = system_model._qubit_freq_est + default_freq = getattr(config, 'qubit_freq_est', [np.inf]) + if default_freq != [np.inf]: + qubit_lo_freq = default_freq - # if still None draw from the Hamiltonian + # if still None, or is the placeholder value draw from the Hamiltonian if qubit_lo_freq is None: qubit_lo_freq = system_model.hamiltonian.get_qubit_lo_from_drift() - warn('Warning: qubit_lo_freq was not specified in PulseQobj or in PulseSystemModel, ' + + warn('Warning: qubit_lo_freq was not specified in PulseQobj and there is no default, ' 'so it is beign automatically determined from the drift Hamiltonian.') pulse_de_model.freqs = system_model.calculate_channel_frequencies(qubit_lo_freq=qubit_lo_freq) @@ -147,14 +146,15 @@ def pulse_controller(qobj, system_model, backend_options): # ### Parse backend_options # # solver-specific information should be extracted in the solver # ############################### - pulse_sim_desc.seed = int(backend_options['seed']) if 'seed' in backend_options else None - pulse_sim_desc.q_level_meas = int(backend_options.get('q_level_meas', 1)) + + pulse_sim_desc.seed = int(config.seed) if hasattr(config, 'seed') else None + pulse_sim_desc.q_level_meas = int(getattr(config, 'q_level_meas', 1)) # solver options allowed_solver_options = ['atol', 'rtol', 'nsteps', 'max_step', 'num_cpus', 'norm_tol', 'norm_steps', 'method'] - solver_options = backend_options.get('solver_options', {}) + solver_options = getattr(config, 'solver_options', {}) for key in solver_options: if key not in allowed_solver_options: raise Exception('Invalid solver_option: {}'.format(key)) @@ -203,7 +203,12 @@ def pulse_controller(qobj, system_model, backend_options): else run_monte_carlo_experiments) exp_results, exp_times = run_experiments(pulse_sim_desc, pulse_de_model, solver_options) - return format_exp_results(exp_results, exp_times, pulse_sim_desc) + output = { + 'results': format_exp_results(exp_results, exp_times, pulse_sim_desc), + 'success': True, + 'qobj_id': qobj.qobj_id + } + return output def format_exp_results(exp_results, exp_times, pulse_sim_desc): @@ -288,7 +293,6 @@ def format_exp_results(exp_results, exp_times, pulse_sim_desc): results['data']['memory'] = results['data']['memory'][0] all_results.append(results) - return all_results diff --git a/qiskit/providers/aer/pulse/system_models/pulse_system_model.py b/qiskit/providers/aer/pulse/system_models/pulse_system_model.py index 1e02d1c0ab..77582e8ffc 100644 --- a/qiskit/providers/aer/pulse/system_models/pulse_system_model.py +++ b/qiskit/providers/aer/pulse/system_models/pulse_system_model.py @@ -30,8 +30,6 @@ class PulseSystemModel(): * ``"hamiltonian"``: a :class:`HamiltonianModel` object representing the Hamiltonian of the system. - * ``"qubit_freq_est"`` and ``"meas_freq_est"``: optional default values for - qubit and measurement frequencies. * ``"u_channel_lo"``: A description of :class:`ControlChannel` local oscillator frequencies in terms of qubit local oscillator frequencies. * ``"control_channel_labels"``: Optional list of identifying information for @@ -55,8 +53,6 @@ class PulseSystemModel(): """ def __init__(self, hamiltonian=None, - qubit_freq_est=None, - meas_freq_est=None, u_channel_lo=None, control_channel_labels=None, subsystem_list=None, @@ -65,10 +61,6 @@ def __init__(self, Args: hamiltonian (HamiltonianModel): The Hamiltonian of the system. - qubit_freq_est (list): list of qubit lo frequencies defaults to be used in simulation - if none are specified in the PulseQobj. - meas_freq_est (list): list of qubit meas frequencies defaults to be used in simulation - if none are specified in the PulseQobj. u_channel_lo (list): list of ControlChannel frequency specifications. control_channel_labels (list): list of labels for control channels, which can be of any type. @@ -78,10 +70,6 @@ def __init__(self, AerError: if hamiltonian is not None or a HamiltonianModel """ - # default type values - self._qubit_freq_est = qubit_freq_est - self._meas_freq_est = meas_freq_est - # necessary values if hamiltonian is not None and not isinstance(hamiltonian, HamiltonianModel): raise AerError("hamiltonian must be a HamiltonianModel object") @@ -110,23 +98,24 @@ def from_backend(cls, backend, subsystem_list=None): raise AerError("{} is not a Qiskit backend".format(backend)) # get relevant information from backend - defaults = backend.defaults() config = backend.configuration() if not config.open_pulse: raise AerError('{} is not an open pulse backend'.format(backend)) - # draw defaults - qubit_freq_est = getattr(defaults, 'qubit_freq_est', None) - meas_freq_est = getattr(defaults, 'meas_freq_est', None) + return cls.from_config(config, subsystem_list) + + @classmethod + def from_config(cls, configuration, subsystem_list=None): + """Construct a model from configuration and defaults.""" # draw from configuration # if no subsystem_list, use all for device - subsystem_list = subsystem_list or list(range(config.n_qubits)) - ham_string = config.hamiltonian + subsystem_list = subsystem_list or list(range(configuration.n_qubits)) + ham_string = configuration.hamiltonian hamiltonian = HamiltonianModel.from_dict(ham_string, subsystem_list) - u_channel_lo = getattr(config, 'u_channel_lo', None) - dt = getattr(config, 'dt', None) + u_channel_lo = getattr(configuration, 'u_channel_lo', None) + dt = getattr(configuration, 'dt', None) control_channel_labels = [None] * len(u_channel_lo) # populate control_channel_dict @@ -163,8 +152,6 @@ def from_backend(cls, backend, subsystem_list=None): control_channel_labels[u_idx] = {'driven_q': drive_idx, 'freq': u_string} return cls(hamiltonian=hamiltonian, - qubit_freq_est=qubit_freq_est, - meas_freq_est=meas_freq_est, u_channel_lo=u_channel_lo, control_channel_labels=control_channel_labels, subsystem_list=subsystem_list, @@ -190,8 +177,7 @@ def calculate_channel_frequencies(self, qubit_lo_freq=None): Args: qubit_lo_freq (list or None): list of qubit linear - oscillator drive frequencies. If None these will be calculated - using self._qubit_freq_est. + oscillator drive frequencies. Returns: OrderedDict: a dictionary of channel frequencies. @@ -200,10 +186,7 @@ def calculate_channel_frequencies(self, qubit_lo_freq=None): ValueError: If channel or u_channel_lo are invalid. """ if not qubit_lo_freq: - if not self._qubit_freq_est: - raise ValueError("No qubit_lo_freq to use.") - - qubit_lo_freq = self._qubit_freq_est + raise ValueError("qubit_lo_freq is a required function parameter.") if self.u_channel_lo is None: raise ValueError("{} has no u_channel_lo.".format(self.__class__.__name__)) diff --git a/releasenotes/notes/configurable-backends-a55cd6a39a0a1561.yaml b/releasenotes/notes/configurable-backends-a55cd6a39a0a1561.yaml new file mode 100644 index 0000000000..6b91dd9ca3 --- /dev/null +++ b/releasenotes/notes/configurable-backends-a55cd6a39a0a1561.yaml @@ -0,0 +1,35 @@ +--- +features: + - | + Make simulator backends configurable. This allows setting persistant options + such as simulation method and noise model for each simulator backend object. + + The :class:`~qiskit.providers.aer.QasmSimulator` and + :class:`~qiskit.providers.aer.PulseSimulator` can also be configured from + an :class:`~qiskit.providers.ibmq.IBMQBackend` backend object using the + `:meth:`~qiskit.providers.aer.QasmSimulator.from_backend` method. + For the :class:`~qiskit.providers.aer.QasmSimulator` this will configure the coupling map, + basis gates, and basic device noise model based on the backend configuration and + properties. For the :class:`~qiskit.providers.aer.PulseSimulator` the system model + and defaults will be configured automatically from the backend configuration, properties and + defaults. + + A benefit is that a :class:`~qiskit.providers.aer.PulseSimulator` instance configured from + a backend better serves as a drop-in replacement to the original backend, making it easier to + swap in and out a simulator and real backend, e.g. when testing code on a simulator before + using a real backend. + For example, in the following code-block, the :class:`~qiskit.providers.aer.PulseSimulator` is + instantiated from the ``FakeArmonk()`` backend. All configuration and default data is copied + into the simulator instance, and so when it is passed as an argument to ``assemble``, + it behaves as if the original backend was supplied (e.g. defaults from ``FakeArmonk`` will be + present and used by ``assemble``). + + .. code-block:: python + + armonk_sim = qiskit.providers.aer.PulseSimulator.from_backend(FakeArmonk()) + pulse_qobj = assemble(schedules, backend=armonk_sim) + armonk_sim.run(pulse_qobj) + + While the above example is small, the demonstrated 'drop-in replacement' behavior should + greatly improve the usability in more complicated work-flows, e.g. when calibration experiments + are constructed using backend attributes. diff --git a/test/benchmark/fusion_benchmarks.py b/test/benchmark/fusion_benchmarks.py index dd8e52b95d..490df2b89f 100644 --- a/test/benchmark/fusion_benchmarks.py +++ b/test/benchmark/fusion_benchmarks.py @@ -50,7 +50,8 @@ def qft_circuit(num_qubit, use_cu1): 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() + result = self.backend.run(self.circuit[(num_qubit, use_cu1)], + fusion_enable=fusion_enable).result() if result.status != 'COMPLETED': raise QiskitError("Simulation failed. Status: " + result.status) @@ -105,6 +106,6 @@ def build_model_circuit_kak(width, depth, seed=None): 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() + result = self.backend.run(qobj, fusion_enable=fusion_enable).result() if result.status != 'COMPLETED': raise QiskitError("Simulation failed. Status: " + result.status) diff --git a/test/benchmark/randomized_benchmarking.py b/test/benchmark/randomized_benchmarking.py index 3c4789043e..5069c2760b 100644 --- a/test/benchmark/randomized_benchmarking.py +++ b/test/benchmark/randomized_benchmarking.py @@ -87,7 +87,7 @@ def time_run_rb_circuit(self, _, simulator_method, noise_model): 'noise_model': noise_model(), } job = self.sim_backend.run(self.qobj, - backend_options=backend_options) + **backend_options) job.result() def peakmem_run_rb_circuit(self, _, simulator_method, noise_model): @@ -96,5 +96,5 @@ def peakmem_run_rb_circuit(self, _, simulator_method, noise_model): 'noise_model': noise_model(), } job = self.sim_backend.run(self.qobj, - backend_options=backend_options) + **backend_options) job.result() diff --git a/test/terra/backends/qasm_simulator/qasm_algorithms.py b/test/terra/backends/qasm_simulator/qasm_algorithms.py index 453e8f6bf0..e7fc5c98d7 100644 --- a/test/terra/backends/qasm_simulator/qasm_algorithms.py +++ b/test/terra/backends/qasm_simulator/qasm_algorithms.py @@ -34,7 +34,7 @@ def test_grovers_default_basis_gates(self): final_measure=True, allow_sampling=True) targets = ref_algorithms.grovers_counts(shots) job = execute(circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -45,7 +45,7 @@ def test_teleport_default_basis_gates(self): circuits = ref_algorithms.teleport_circuit() targets = ref_algorithms.teleport_counts(shots) job = execute(circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -72,7 +72,7 @@ def test_grovers_waltz_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -87,7 +87,7 @@ def test_teleport_waltz_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -110,7 +110,7 @@ def test_grovers_minimal_basis_gates(self): targets = ref_algorithms.grovers_counts(shots) job = execute( circuits, self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -122,7 +122,7 @@ def test_teleport_minimal_basis_gates(self): targets = ref_algorithms.teleport_counts(shots) job = execute( circuits, self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) diff --git a/test/terra/backends/qasm_simulator/qasm_cliffords.py b/test/terra/backends/qasm_simulator/qasm_cliffords.py index 26a5aa760b..a3808e946e 100644 --- a/test/terra/backends/qasm_simulator/qasm_cliffords.py +++ b/test/terra/backends/qasm_simulator/qasm_cliffords.py @@ -35,7 +35,7 @@ def test_h_gate_deterministic_default_basis_gates(self): final_measure=True) targets = ref_1q_clifford.h_gate_counts_deterministic(shots) job = execute(circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -47,7 +47,7 @@ def test_h_gate_nondeterministic_default_basis_gates(self): final_measure=True) targets = ref_1q_clifford.h_gate_counts_nondeterministic(shots) job = execute(circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -76,7 +76,7 @@ def test_z_gate_deterministic_default_basis_gates(self): final_measure=True) targets = ref_1q_clifford.z_gate_counts_deterministic(shots) job = execute(circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -91,7 +91,7 @@ def test_y_gate_deterministic_default_basis_gates(self): final_measure=True) targets = ref_1q_clifford.y_gate_counts_deterministic(shots) job = execute(circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -106,7 +106,7 @@ def test_s_gate_deterministic_default_basis_gates(self): final_measure=True) targets = ref_1q_clifford.s_gate_counts_deterministic(shots) job = execute(circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -121,7 +121,7 @@ def test_s_gate_nondeterministic_default_basis_gates(self): circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -139,7 +139,7 @@ def test_sdg_gate_deterministic_default_basis_gates(self): circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -151,7 +151,7 @@ def test_sdg_gate_nondeterministic_default_basis_gates(self): final_measure=True) targets = ref_1q_clifford.sdg_gate_counts_nondeterministic(shots) job = execute(circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -166,7 +166,7 @@ def test_cx_gate_deterministic_default_basis_gates(self): final_measure=True) targets = ref_2q_clifford.cx_gate_counts_deterministic(shots) job = execute(circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -178,7 +178,7 @@ def test_cx_gate_nondeterministic_default_basis_gates(self): final_measure=True) targets = ref_2q_clifford.cx_gate_counts_nondeterministic(shots) job = execute(circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -193,7 +193,7 @@ def test_cz_gate_deterministic_default_basis_gates(self): final_measure=True) targets = ref_2q_clifford.cz_gate_counts_deterministic(shots) job = execute(circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -205,7 +205,7 @@ def test_cz_gate_nondeterministic_default_basis_gates(self): final_measure=True) targets = ref_2q_clifford.cz_gate_counts_nondeterministic(shots) job = execute(circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -220,7 +220,7 @@ def test_swap_gate_deterministic_default_basis_gates(self): final_measure=True) targets = ref_2q_clifford.swap_gate_counts_deterministic(shots) job = execute(circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -232,7 +232,7 @@ def test_swap_gate_nondeterministic_default_basis_gates(self): final_measure=True) targets = ref_2q_clifford.swap_gate_counts_nondeterministic(shots) job = execute(circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -258,7 +258,7 @@ def test_h_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -274,7 +274,7 @@ def test_h_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -293,7 +293,7 @@ def test_x_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -313,7 +313,7 @@ def test_z_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -326,7 +326,7 @@ def test_z_gate_deterministic_minimal_basis_gates(self): targets = ref_1q_clifford.z_gate_counts_deterministic(shots) job = execute( circuits, self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -341,7 +341,7 @@ def test_y_gate_deterministic_default_basis_gates(self): final_measure=True) targets = ref_1q_clifford.y_gate_counts_deterministic(shots) job = execute(circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -357,7 +357,7 @@ def test_y_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -376,7 +376,7 @@ def test_s_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -392,7 +392,7 @@ def test_s_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -426,7 +426,7 @@ def test_sdg_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -445,7 +445,7 @@ def test_cx_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -494,7 +494,7 @@ def test_cz_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -513,7 +513,7 @@ def test_swap_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -529,7 +529,7 @@ def test_swap_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -553,7 +553,7 @@ def test_h_gate_deterministic_minimal_basis_gates(self): targets = ref_1q_clifford.h_gate_counts_deterministic(shots) job = execute( circuits, self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -566,7 +566,7 @@ def test_h_gate_nondeterministic_minimal_basis_gates(self): targets = ref_1q_clifford.h_gate_counts_nondeterministic(shots) job = execute( circuits, self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -598,7 +598,7 @@ def test_z_gate_deterministic_minimal_basis_gates(self): targets = ref_1q_clifford.z_gate_counts_deterministic(shots) job = execute( circuits, self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -615,7 +615,7 @@ def test_y_gate_deterministic_minimal_basis_gates(self): targets = ref_1q_clifford.y_gate_counts_deterministic(shots) job = execute( circuits, self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -632,7 +632,7 @@ def test_s_gate_deterministic_minimal_basis_gates(self): targets = ref_1q_clifford.s_gate_counts_deterministic(shots) job = execute( circuits, self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -645,7 +645,7 @@ def test_s_gate_nondeterministic_minimal_basis_gates(self): targets = ref_1q_clifford.s_gate_counts_nondeterministic(shots) job = execute( circuits, self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -661,7 +661,7 @@ def test_sdg_gate_deterministic_minimal_basis_gates(self): targets = ref_1q_clifford.sdg_gate_counts_deterministic(shots) job = execute( circuits, self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -674,7 +674,7 @@ def test_sdg_gate_nondeterministic_minimal_basis_gates(self): targets = ref_1q_clifford.sdg_gate_counts_nondeterministic(shots) job = execute( circuits, self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -690,7 +690,7 @@ def test_cx_gate_deterministic_minimal_basis_gates(self): targets = ref_2q_clifford.cx_gate_counts_deterministic(shots) job = execute( circuits, self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -703,7 +703,7 @@ def test_cx_gate_nondeterministic_minimal_basis_gates(self): targets = ref_2q_clifford.cx_gate_counts_nondeterministic(shots) job = execute( circuits, self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -719,7 +719,7 @@ def test_cz_gate_deterministic_minimal_basis_gates(self): targets = ref_2q_clifford.cz_gate_counts_deterministic(shots) job = execute( circuits, self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -732,7 +732,7 @@ def test_cz_gate_nondeterministic_minimal_basis_gates(self): targets = ref_2q_clifford.cz_gate_counts_nondeterministic(shots) job = execute( circuits, self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -748,7 +748,7 @@ def test_swap_gate_deterministic_minimal_basis_gates(self): targets = ref_2q_clifford.swap_gate_counts_deterministic(shots) job = execute( circuits, self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -761,7 +761,7 @@ def test_swap_gate_nondeterministic_minimal_basis_gates(self): targets = ref_2q_clifford.swap_gate_counts_nondeterministic(shots) job = execute( circuits, self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) diff --git a/test/terra/backends/qasm_simulator/qasm_conditional.py b/test/terra/backends/qasm_simulator/qasm_conditional.py index a8dca33160..7772e5db17 100644 --- a/test/terra/backends/qasm_simulator/qasm_conditional.py +++ b/test/terra/backends/qasm_simulator/qasm_conditional.py @@ -35,7 +35,7 @@ def test_conditional_gates_1bit(self): targets = ref_conditionals.conditional_counts_1bit(shots) qobj = assemble(circuits, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( - qobj, backend_options=self.BACKEND_OPTS).result() + qobj, **self.BACKEND_OPTS).result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -47,7 +47,7 @@ def test_conditional_gates_2bit(self): targets = ref_conditionals.conditional_counts_2bit(shots) qobj = assemble(circuits, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( - qobj, backend_options=self.BACKEND_OPTS).result() + qobj, **self.BACKEND_OPTS).result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -69,7 +69,7 @@ def test_conditional_unitary_1bit(self): targets = ref_conditionals.conditional_counts_1bit(shots) qobj = assemble(circuits, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( - qobj, backend_options=self.BACKEND_OPTS).result() + qobj, **self.BACKEND_OPTS).result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -81,7 +81,7 @@ def test_conditional_unitary_2bit(self): targets = ref_conditionals.conditional_counts_2bit(shots) qobj = assemble(circuits, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( - qobj, backend_options=self.BACKEND_OPTS).result() + qobj, **self.BACKEND_OPTS).result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -103,7 +103,7 @@ def test_conditional_unitary_1bit(self): targets = ref_conditionals.conditional_counts_1bit(shots) qobj = assemble(circuits, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( - qobj, backend_options=self.BACKEND_OPTS).result() + qobj, **self.BACKEND_OPTS).result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -115,7 +115,7 @@ def test_conditional_kraus_2bit(self): targets = ref_conditionals.conditional_counts_2bit(shots) qobj = assemble(circuits, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( - qobj, backend_options=self.BACKEND_OPTS).result() + qobj, **self.BACKEND_OPTS).result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -137,7 +137,7 @@ def test_conditional_superop_1bit(self): targets = ref_conditionals.conditional_counts_1bit(shots) qobj = assemble(circuits, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( - qobj, backend_options=self.BACKEND_OPTS).result() + qobj, **self.BACKEND_OPTS).result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -149,6 +149,6 @@ def test_conditional_superop_2bit(self): targets = ref_conditionals.conditional_counts_2bit(shots) qobj = assemble(circuits, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( - qobj, backend_options=self.BACKEND_OPTS).result() + qobj, **self.BACKEND_OPTS).result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) diff --git a/test/terra/backends/qasm_simulator/qasm_delay_measure.py b/test/terra/backends/qasm_simulator/qasm_delay_measure.py index 17e7be1c7b..7725977111 100644 --- a/test/terra/backends/qasm_simulator/qasm_delay_measure.py +++ b/test/terra/backends/qasm_simulator/qasm_delay_measure.py @@ -54,7 +54,7 @@ def test_delay_measure_enable(self): backend_options['optimize_ideal_threshold'] = 0 result = self.SIMULATOR.run( qobj, - backend_options=backend_options).result() + **backend_options).result() self.assertSuccess(result) metadata = result.results[0].metadata self.assertTrue(metadata.get('measure_sampling')) @@ -65,7 +65,7 @@ def test_delay_measure_enable(self): backend_options['optimize_ideal_threshold'] = 0 result = self.SIMULATOR.run( qobj, - backend_options=backend_options).result() + **backend_options).result() self.assertSuccess(result) metadata = result.results[0].metadata self.assertTrue(metadata.get('measure_sampling')) @@ -76,7 +76,7 @@ def test_delay_measure_enable(self): backend_options['optimize_ideal_threshold'] = 0 result = self.SIMULATOR.run( qobj, - backend_options=backend_options).result() + **backend_options).result() self.assertSuccess(result) metadata = result.results[0].metadata self.assertFalse(metadata.get('measure_sampling')) @@ -95,7 +95,7 @@ def test_delay_measure_verbose(self): result = self.SIMULATOR.run( qobj, - backend_options=backend_options).result() + **backend_options).result() self.assertSuccess(result) metadata = result.results[0].metadata self.assertIn('delay_measure_verbose', metadata) @@ -108,7 +108,7 @@ def test_delay_measure_verbose(self): result = self.SIMULATOR.run( qobj, - backend_options=backend_options).result() + **backend_options).result() self.assertSuccess(result) metadata = result.results[0].metadata self.assertNotIn('delay_measure_verbose', metadata) @@ -121,7 +121,7 @@ def test_delay_measure_verbose(self): result = self.SIMULATOR.run( qobj, - backend_options=backend_options).result() + **backend_options).result() self.assertSuccess(result) metadata = result.results[0].metadata self.assertNotIn('delay_measure_verbose', metadata) diff --git a/test/terra/backends/qasm_simulator/qasm_fusion.py b/test/terra/backends/qasm_simulator/qasm_fusion.py index 0dfa0c94e7..cac29d67e2 100644 --- a/test/terra/backends/qasm_simulator/qasm_fusion.py +++ b/test/terra/backends/qasm_simulator/qasm_fusion.py @@ -102,7 +102,7 @@ def test_fusion_theshold(self): circuit.measure_all() qobj = assemble(circuit, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( - qobj, backend_options=backend_options).result() + qobj, **backend_options).result() self.assertSuccess(result) meta = self.fusion_metadata(result) self.assertFalse(meta.get('applied', False)) @@ -114,7 +114,7 @@ def test_fusion_theshold(self): circuit.measure_all() qobj = assemble(circuit, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( - qobj, backend_options=backend_options).result() + qobj, **backend_options).result() self.assertSuccess(result) meta = self.fusion_metadata(result) self.assertTrue(meta.get('applied', False)) @@ -126,7 +126,7 @@ def test_fusion_theshold(self): circuit.measure_all() qobj = assemble(circuit, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( - qobj, backend_options=backend_options).result() + qobj, **backend_options).result() self.assertSuccess(result) meta = self.fusion_metadata(result) self.assertTrue(meta.get('applied', False)) @@ -141,7 +141,7 @@ def test_fusion_verbose(self): with self.subTest(msg='verbose enabled'): backend_options = self.fusion_options(enabled=True, verbose=True, threshold=1) result = self.SIMULATOR.run( - qobj, backend_options=backend_options).result() + qobj, **backend_options).result() # Assert fusion applied succesfully self.assertSuccess(result) meta = self.fusion_metadata(result) @@ -153,7 +153,7 @@ def test_fusion_verbose(self): with self.subTest(msg='verbose disabled'): backend_options = self.fusion_options(enabled=True, verbose=False, threshold=1) result = self.SIMULATOR.run( - qobj, backend_options=backend_options).result() + qobj, **backend_options).result() # Assert fusion applied succesfully self.assertSuccess(result) meta = self.fusion_metadata(result) @@ -165,7 +165,7 @@ def test_fusion_verbose(self): with self.subTest(msg='verbose default'): backend_options = self.fusion_options(enabled=True, threshold=1) result = self.SIMULATOR.run( - qobj, backend_options=backend_options).result() + qobj, **backend_options).result() # Assert fusion applied succesfully self.assertSuccess(result) @@ -191,7 +191,7 @@ def test_kraus_noise_fusion(self): backend_options = self.fusion_options(enabled=True, threshold=1) result = self.SIMULATOR.run(qobj, noise_model=noise_model, - backend_options=backend_options).result() + **backend_options).result() meta = self.fusion_metadata(result) if backend_options.get('method') in ['density_matrix', 'density_matrix_thrust', @@ -221,7 +221,7 @@ def test_non_kraus_noise_fusion(self): backend_options = self.fusion_options(enabled=True, threshold=1) result = self.SIMULATOR.run(qobj, noise_model=noise_model, - backend_options=backend_options).result() + **backend_options).result() meta = self.fusion_metadata(result) if backend_options.get('method') in ['density_matrix', 'density_matrix_thrust', @@ -249,7 +249,7 @@ def test_control_fusion(self): with self.subTest(msg='fusion enabled'): backend_options = self.fusion_options(enabled=True, threshold=1) result = self.SIMULATOR.run( - qobj, backend_options=backend_options).result() + qobj, **backend_options).result() meta = self.fusion_metadata(result) self.assertSuccess(result) @@ -258,7 +258,7 @@ def test_control_fusion(self): with self.subTest(msg='fusion disabled'): backend_options = backend_options = self.fusion_options(enabled=False, threshold=1) result = self.SIMULATOR.run( - qobj, backend_options=backend_options).result() + qobj, **backend_options).result() meta = self.fusion_metadata(result) self.assertSuccess(result) @@ -268,7 +268,7 @@ def test_control_fusion(self): backend_options = self.fusion_options() result = self.SIMULATOR.run( - qobj, backend_options=backend_options).result() + qobj, **backend_options).result() meta = self.fusion_metadata(result) self.assertSuccess(result) @@ -341,12 +341,12 @@ def test_fusion_operations(self): backend_options = self.fusion_options(enabled=False, threshold=1) result_disabled = self.SIMULATOR.run( - qobj, backend_options=backend_options).result() + qobj, **backend_options).result() meta_disabled = self.fusion_metadata(result_disabled) backend_options = self.fusion_options(enabled=True, threshold=1) result_enabled = self.SIMULATOR.run( - qobj, backend_options=backend_options).result() + qobj, **backend_options).result() meta_enabled = self.fusion_metadata(result_enabled) self.assertTrue(getattr(result_disabled, 'success', 'False')) @@ -374,12 +374,12 @@ def test_fusion_qv(self): backend_options = self.fusion_options(enabled=False, threshold=1) result_disabled = self.SIMULATOR.run( - qobj, backend_options=backend_options).result() + qobj, **backend_options).result() meta_disabled = self.fusion_metadata(result_disabled) backend_options = self.fusion_options(enabled=True, threshold=1) result_enabled = self.SIMULATOR.run( - qobj, backend_options=backend_options).result() + qobj, **backend_options).result() meta_enabled = self.fusion_metadata(result_enabled) self.assertTrue(getattr(result_disabled, 'success', 'False')) @@ -407,12 +407,12 @@ def test_fusion_qft(self): backend_options = self.fusion_options(enabled=False, threshold=1) result_disabled = self.SIMULATOR.run( - qobj, backend_options=backend_options).result() + qobj, **backend_options).result() meta_disabled = self.fusion_metadata(result_disabled) backend_options = self.fusion_options(enabled=True, threshold=1) result_enabled = self.SIMULATOR.run( - qobj, backend_options=backend_options).result() + qobj, **backend_options).result() meta_enabled = self.fusion_metadata(result_enabled) self.assertTrue(getattr(result_disabled, 'success', 'False')) diff --git a/test/terra/backends/qasm_simulator/qasm_initialize.py b/test/terra/backends/qasm_simulator/qasm_initialize.py index 6bb2353f89..376764caa9 100644 --- a/test/terra/backends/qasm_simulator/qasm_initialize.py +++ b/test/terra/backends/qasm_simulator/qasm_initialize.py @@ -42,7 +42,7 @@ def test_initialize_wrapper_1(self): [ circuits.extend(ref_initialize.initialize_circuits_w_1(init_state)) for init_state in init_states ] qobj = assemble(circuits, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( - qobj, backend_options=self.BACKEND_OPTS).result() + qobj, **self.BACKEND_OPTS).result() self.assertSuccess(result) # --------------------------------------------------------------------- @@ -62,7 +62,7 @@ def test_initialize_wrapper_2(self): [ circuits.extend(ref_initialize.initialize_circuits_w_2(init_state)) for init_state in init_states ] qobj = assemble(circuits, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( - qobj, backend_options=self.BACKEND_OPTS).result() + qobj, **self.BACKEND_OPTS).result() self.assertSuccess(result) # --------------------------------------------------------------------- @@ -77,7 +77,7 @@ def test_initialize_1(self): targets = ref_initialize.initialize_counts_1(shots) qobj = assemble(circuits, self.SIMULATOR, shots=shots) opts = self.BACKEND_OPTS.copy() - result = self.SIMULATOR.run(qobj, backend_options=opts).result() + result = self.SIMULATOR.run(qobj, **opts).result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -90,7 +90,7 @@ def test_initialize_2(self): targets = ref_initialize.initialize_counts_2(shots) qobj = assemble(circuits, self.SIMULATOR, shots=shots) opts = self.BACKEND_OPTS.copy() - result = self.SIMULATOR.run(qobj, backend_options=opts).result() + result = self.SIMULATOR.run(qobj, **opts).result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -101,6 +101,6 @@ def test_initialize_sampling_opt(self): targets = ref_initialize.initialize_counts_sampling_optimization(shots) qobj = assemble(circuits, self.SIMULATOR, shots=shots) opts = self.BACKEND_OPTS.copy() - result = self.SIMULATOR.run(qobj, backend_options=opts).result() + result = self.SIMULATOR.run(qobj, **opts).result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) diff --git a/test/terra/backends/qasm_simulator/qasm_measure.py b/test/terra/backends/qasm_simulator/qasm_measure.py index 55a674c559..4357d101fb 100644 --- a/test/terra/backends/qasm_simulator/qasm_measure.py +++ b/test/terra/backends/qasm_simulator/qasm_measure.py @@ -38,7 +38,7 @@ def test_measure_deterministic_with_sampling(self): target_memory = ref_measure.measure_memory_deterministic(shots) qobj = assemble(circuits, self.SIMULATOR, shots=shots, memory=True) result = self.SIMULATOR.run( - qobj, backend_options=self.BACKEND_OPTS).result() + qobj, **self.BACKEND_OPTS).result() self.assertSuccess(result) self.compare_counts(result, circuits, target_counts, delta=0) self.compare_memory(result, circuits, target_memory) @@ -53,7 +53,7 @@ def test_measure_deterministic_without_sampling(self): target_memory = ref_measure.measure_memory_deterministic(shots) qobj = assemble(circuits, self.SIMULATOR, shots=shots, memory=True) result = self.SIMULATOR.run( - qobj, backend_options=self.BACKEND_OPTS).result() + qobj, **self.BACKEND_OPTS).result() self.assertSuccess(result) self.compare_counts(result, circuits, target_counts, delta=0) self.compare_memory(result, circuits, target_memory) @@ -67,7 +67,7 @@ def test_measure_nondeterministic_with_sampling(self): targets = ref_measure.measure_counts_nondeterministic(shots) qobj = assemble(circuits, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( - qobj, backend_options=self.BACKEND_OPTS).result() + qobj, **self.BACKEND_OPTS).result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) # Test sampling was enabled @@ -83,7 +83,7 @@ def test_measure_nondeterministic_without_sampling(self): targets = ref_measure.measure_counts_nondeterministic(shots) qobj = assemble(circuits, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( - qobj, backend_options=self.BACKEND_OPTS).result() + qobj, **self.BACKEND_OPTS).result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) self.compare_result_metadata(result, circuits, "measure_sampling", False) @@ -103,7 +103,7 @@ def test_measure_sampling_with_readouterror(self): qobj = assemble(circuits, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( qobj, noise_model=noise_model, - backend_options=self.BACKEND_OPTS).result() + **self.BACKEND_OPTS).result() self.assertSuccess(result) self.compare_result_metadata(result, circuits, "measure_sampling", True) @@ -126,7 +126,7 @@ def test_measure_sampling_with_quantum_noise(self): qobj = assemble(circuits, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( qobj, noise_model=noise_model, - backend_options=self.BACKEND_OPTS).result() + **self.BACKEND_OPTS).result() self.assertSuccess(result) sampling = (self.BACKEND_OPTS.get("method", "automatic").startswith("density_matrix")) self.compare_result_metadata(result, circuits, "measure_sampling", sampling) @@ -150,7 +150,7 @@ def test_measure_deterministic_multi_qubit_with_sampling(self): target_memory = ref_measure.multiqubit_measure_memory_deterministic(shots) qobj = assemble(circuits, self.SIMULATOR, shots=shots, memory=True) result = self.SIMULATOR.run( - qobj, backend_options=self.BACKEND_OPTS).result() + qobj, **self.BACKEND_OPTS).result() self.assertSuccess(result) self.compare_counts(result, circuits, target_counts, delta=0) self.compare_memory(result, circuits, target_memory) @@ -165,7 +165,7 @@ def test_measure_deterministic_multi_qubit_without_sampling(self): target_memory = ref_measure.multiqubit_measure_memory_deterministic(shots) qobj = assemble(circuits, self.SIMULATOR, shots=shots, memory=True) result = self.SIMULATOR.run( - qobj, backend_options=self.BACKEND_OPTS).result() + qobj, **self.BACKEND_OPTS).result() self.compare_counts(result, circuits, target_counts, delta=0) self.compare_memory(result, circuits, target_memory) self.compare_result_metadata(result, circuits, "measure_sampling", False) @@ -178,7 +178,7 @@ def test_measure_nondeterministic_multi_qubit_with_sampling(self): targets = ref_measure.multiqubit_measure_counts_nondeterministic(shots) qobj = assemble(circuits, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( - qobj, backend_options=self.BACKEND_OPTS).result() + qobj, **self.BACKEND_OPTS).result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) self.compare_result_metadata(result, circuits, "measure_sampling", True) @@ -191,7 +191,7 @@ def test_measure_nondeterministic_multi_qubit_without_sampling(self): targets = ref_measure.multiqubit_measure_counts_nondeterministic(shots) qobj = assemble(circuits, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( - qobj, backend_options=self.BACKEND_OPTS).result() + qobj, **self.BACKEND_OPTS).result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) self.compare_result_metadata(result, circuits, "measure_sampling", False) diff --git a/test/terra/backends/qasm_simulator/qasm_method.py b/test/terra/backends/qasm_simulator/qasm_method.py index 7dc016d856..fb20e7026e 100644 --- a/test/terra/backends/qasm_simulator/qasm_method.py +++ b/test/terra/backends/qasm_simulator/qasm_method.py @@ -42,7 +42,7 @@ def test_backend_method_clifford_circuits(self): qobj = assemble(circuits, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( - qobj, backend_options=self.BACKEND_OPTS).result() + qobj, **self.BACKEND_OPTS).result() success = getattr(result, 'success', False) self.assertTrue(success) # Check simulation method @@ -76,8 +76,8 @@ def test_backend_method_clifford_circuits_and_reset_noise(self): qobj = assemble(circuits, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run(qobj, - backend_options=self.BACKEND_OPTS, - noise_model=noise_model).result() + noise_model=noise_model, + **self.BACKEND_OPTS).result() success = getattr(result, 'success', False) self.assertTrue(success) # Check simulation method @@ -101,7 +101,7 @@ def test_backend_method_clifford_circuits_and_pauli_noise(self): final_measure=True) qobj = assemble(circuits, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( - qobj, backend_options=self.BACKEND_OPTS).result() + qobj, **self.BACKEND_OPTS).result() success = getattr(result, 'success', False) self.assertTrue(success) # Check simulation method @@ -125,8 +125,8 @@ def test_backend_method_clifford_circuits_and_unitary_noise(self): final_measure=True) qobj = assemble(circuits, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run(qobj, - backend_options=self.BACKEND_OPTS, - noise_model=noise_model).result() + noise_model=noise_model, + **self.BACKEND_OPTS).result() success = getattr(result, 'success', False) # Check simulation method method = self.BACKEND_OPTS.get('method', 'automatic') @@ -156,8 +156,8 @@ def test_backend_method_clifford_circuits_and_kraus_noise(self): qobj = assemble(circuits, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run(qobj, - backend_options=self.BACKEND_OPTS, - noise_model=noise_model).result() + noise_model=noise_model, + **self.BACKEND_OPTS).result() success = getattr(result, 'success', False) # Check simulation method method = self.BACKEND_OPTS.get('method', 'automatic') @@ -184,7 +184,7 @@ def test_backend_method_nonclifford_circuits(self): qobj = assemble(circuits, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( - qobj, backend_options=self.BACKEND_OPTS).result() + qobj, **self.BACKEND_OPTS).result() success = getattr(result, 'success', False) # Check simulation method method = self.BACKEND_OPTS.get('method', 'automatic') @@ -222,8 +222,8 @@ def test_backend_method_nonclifford_circuit_and_reset_noise(self): qobj = assemble(circuits, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run(qobj, - backend_options=self.BACKEND_OPTS, - noise_model=noise_model).result() + noise_model=noise_model, + **self.BACKEND_OPTS).result() success = getattr(result, 'success', False) # Check simulation method method = self.BACKEND_OPTS.get('method', 'automatic') @@ -253,8 +253,8 @@ def test_backend_method_nonclifford_circuit_and_pauli_noise(self): qobj = assemble(circuits, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run(qobj, - backend_options=self.BACKEND_OPTS, - noise_model=noise_model).result() + noise_model=noise_model, + **self.BACKEND_OPTS).result() success = getattr(result, 'success', False) # Check simulation method method = self.BACKEND_OPTS.get('method', 'automatic') @@ -283,8 +283,8 @@ def test_backend_method_nonclifford_circuit_and_unitary_noise(self): qobj = assemble(circuits, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run(qobj, - backend_options=self.BACKEND_OPTS, - noise_model=noise_model).result() + noise_model=noise_model, + **self.BACKEND_OPTS).result() success = getattr(result, 'success', False) # Check simulation method method = self.BACKEND_OPTS.get('method', 'automatic') @@ -314,8 +314,8 @@ def test_backend_method_nonclifford_circuit_and_kraus_noise(self): qobj = assemble(circuits, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run(qobj, - backend_options=self.BACKEND_OPTS, - noise_model=noise_model).result() + noise_model=noise_model, + **self.BACKEND_OPTS).result() success = getattr(result, 'success', False) # Check simulation method method = self.BACKEND_OPTS.get('method', 'automatic') diff --git a/test/terra/backends/qasm_simulator/qasm_multiplexer.py b/test/terra/backends/qasm_simulator/qasm_multiplexer.py index 3e93b1c00e..11e2c72662 100644 --- a/test/terra/backends/qasm_simulator/qasm_multiplexer.py +++ b/test/terra/backends/qasm_simulator/qasm_multiplexer.py @@ -33,7 +33,7 @@ def test_multiplexer_cx_gate_deterministic(self): circuits = ref_multiplexer.multiplexer_cx_gate_circuits_deterministic( final_measure=True) targets = ref_multiplexer.multiplexer_cx_gate_counts_deterministic(shots) - job = execute(circuits, self.SIMULATOR, shots=shots, backend_options=self.BACKEND_OPTS) + job = execute(circuits, self.SIMULATOR, shots=shots, **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -44,7 +44,7 @@ def test_multiplexer_cx_gate_nondeterministic(self): circuits = ref_multiplexer.multiplexer_cx_gate_circuits_nondeterministic( final_measure=True) targets = ref_multiplexer.multiplexer_cx_gate_counts_nondeterministic(shots) - job = execute(circuits, self.SIMULATOR, shots=shots, backend_options=self.BACKEND_OPTS) + job = execute(circuits, self.SIMULATOR, shots=shots, **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -60,7 +60,7 @@ def test_multiplexer_cxx_gate_deterministic(self): targets = ref_multiplexer.multiplexer_ccx_gate_counts_deterministic( shots) job = execute(circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -73,7 +73,7 @@ def test_multiplexer_cxx_gate_nondeterministic(self): targets = ref_multiplexer.multiplexer_ccx_gate_counts_nondeterministic( shots) job = execute(circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) diff --git a/test/terra/backends/qasm_simulator/qasm_noise.py b/test/terra/backends/qasm_simulator/qasm_noise.py index ebd6ef5221..cf76401d40 100644 --- a/test/terra/backends/qasm_simulator/qasm_noise.py +++ b/test/terra/backends/qasm_simulator/qasm_noise.py @@ -42,8 +42,7 @@ def test_readout_noise(self): qobj = assemble(circuit, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( qobj, - backend_options=self.BACKEND_OPTS, - noise_model=noise_model).result() + noise_model=noise_model, **self.BACKEND_OPTS).result() self.assertSuccess(result) self.compare_counts(result, [circuit], [target], delta=0.05 * shots) @@ -66,8 +65,7 @@ def test_pauli_gate_noise(self): qobj = assemble(circuit, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( qobj, - backend_options=self.BACKEND_OPTS, - noise_model=noise_model).result() + noise_model=noise_model, **self.BACKEND_OPTS).result() self.assertSuccess(result) self.compare_counts(result, [circuit], [target], delta=0.05 * shots) @@ -83,8 +81,7 @@ def test_pauli_reset_noise(self): qobj = assemble(circuit, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( qobj, - backend_options=self.BACKEND_OPTS, - noise_model=noise_model).result() + noise_model=noise_model, **self.BACKEND_OPTS).result() self.assertSuccess(result) self.compare_counts(result, [circuit], [target], delta=0.05 * shots) @@ -100,8 +97,7 @@ def test_pauli_measure_noise(self): qobj = assemble(circuit, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( qobj, - backend_options=self.BACKEND_OPTS, - noise_model=noise_model).result() + noise_model=noise_model, **self.BACKEND_OPTS).result() self.assertSuccess(result) self.compare_counts(result, [circuit], [target], delta=0.05 * shots) @@ -124,8 +120,8 @@ def test_reset_gate_noise(self): qobj = assemble(circuit, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( qobj, - backend_options=self.BACKEND_OPTS, - noise_model=noise_model).result() + noise_model=noise_model, + **self.BACKEND_OPTS).result() self.assertSuccess(result) self.compare_counts(result, [circuit], [target], delta=0.05 * shots) @@ -148,7 +144,7 @@ def test_kraus_gate_noise(self): qobj = assemble(circuit, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( qobj, - backend_options=self.BACKEND_OPTS, - noise_model=noise_model).result() + noise_model=noise_model, + **self.BACKEND_OPTS).result() self.assertSuccess(result) self.compare_counts(result, [circuit], [target], delta=0.05 * shots) diff --git a/test/terra/backends/qasm_simulator/qasm_noncliffords.py b/test/terra/backends/qasm_simulator/qasm_noncliffords.py index 594004c399..eaa6d87ad2 100644 --- a/test/terra/backends/qasm_simulator/qasm_noncliffords.py +++ b/test/terra/backends/qasm_simulator/qasm_noncliffords.py @@ -34,7 +34,7 @@ def test_t_gate_deterministic_default_basis_gates(self): final_measure=True) targets = ref_non_clifford.t_gate_counts_deterministic(shots) job = execute(circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -46,7 +46,7 @@ def test_t_gate_nondeterministic_default_basis_gates(self): final_measure=True) targets = ref_non_clifford.t_gate_counts_nondeterministic(shots) job = execute(circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -61,7 +61,7 @@ def test_tdg_gate_deterministic_default_basis_gates(self): final_measure=True) targets = ref_non_clifford.tdg_gate_counts_deterministic(shots) job = execute(circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -73,7 +73,7 @@ def test_tdg_gate_nondeterministic_default_basis_gates(self): final_measure=True) targets = ref_non_clifford.tdg_gate_counts_nondeterministic(shots) job = execute(circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -94,7 +94,7 @@ def test_ccx_gate_deterministic_default_basis_gates(self): final_measure=True) targets = ref_non_clifford.ccx_gate_counts_deterministic(shots) job = execute(circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -106,7 +106,7 @@ def test_ccx_gate_nondeterministic_default_basis_gates(self): final_measure=True) targets = ref_non_clifford.ccx_gate_counts_nondeterministic(shots) job = execute(circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -126,7 +126,7 @@ def test_cswap_gate_deterministic_default_basis_gates(self): final_measure=True) targets = ref_non_clifford.cswap_gate_counts_deterministic(shots) job = execute(circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -137,7 +137,7 @@ def test_cswap_gate_nondeterministic_default_basis_gates(self): final_measure=True) targets = ref_non_clifford.cswap_gate_counts_nondeterministic(shots) job = execute(circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -152,7 +152,7 @@ def test_cu1_gate_nondeterministic_default_basis_gates(self): final_measure=True) targets = ref_non_clifford.cu1_gate_counts_nondeterministic(shots) job = execute(circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -167,7 +167,7 @@ def test_cu3_gate_deterministic_default_basis_gates(self): final_measure=True) targets = ref_non_clifford.cu3_gate_counts_deterministic(shots) job = execute(circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -192,7 +192,7 @@ def test_t_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -207,7 +207,7 @@ def test_t_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -225,7 +225,7 @@ def test_tdg_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -240,7 +240,7 @@ def test_tdg_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -258,7 +258,7 @@ def test_ccx_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -273,7 +273,7 @@ def test_ccx_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -291,7 +291,7 @@ def test_cswap_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -306,7 +306,7 @@ def test_cswap_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -324,7 +324,7 @@ def test_cu1_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -342,7 +342,7 @@ def test_cu3_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -381,7 +381,7 @@ def test_t_gate_nondeterministic_minimal_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -399,7 +399,7 @@ def test_tdg_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -414,7 +414,7 @@ def test_tdg_gate_nondeterministic_minimal_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -432,7 +432,7 @@ def test_ccx_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -447,7 +447,7 @@ def test_ccx_gate_nondeterministic_minimal_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.1 * shots) @@ -465,7 +465,7 @@ def test_cu1_gate_nondeterministic_minimal_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.1 * shots) @@ -483,7 +483,7 @@ def test_cswap_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -498,7 +498,7 @@ def test_cswap_gate_nondeterministic_minimal_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.1 * shots) @@ -516,7 +516,7 @@ def test_cu3_gate_deterministic_default_basis_gates(self): self.SIMULATOR, shots=shots, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) diff --git a/test/terra/backends/qasm_simulator/qasm_reset.py b/test/terra/backends/qasm_simulator/qasm_reset.py index 73af99ea8a..c235dfde39 100644 --- a/test/terra/backends/qasm_simulator/qasm_reset.py +++ b/test/terra/backends/qasm_simulator/qasm_reset.py @@ -36,7 +36,7 @@ def test_reset_deterministic(self): targets = ref_reset.reset_counts_deterministic(shots) qobj = assemble(circuits, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( - qobj, backend_options=self.BACKEND_OPTS).result() + qobj, **self.BACKEND_OPTS).result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -50,7 +50,7 @@ def test_reset_nondeterministic(self): targets = ref_reset.reset_counts_nondeterministic(shots) qobj = assemble(circuits, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( - qobj, backend_options=self.BACKEND_OPTS).result() + qobj, **self.BACKEND_OPTS).result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -61,7 +61,7 @@ def test_reset_sampling_opt(self): targets = ref_reset.reset_counts_sampling_optimization(shots) qobj = assemble(circuits, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( - qobj, backend_options=self.BACKEND_OPTS).result() + qobj, **self.BACKEND_OPTS).result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -72,6 +72,6 @@ def test_repeated_resets(self): targets = ref_reset.reset_counts_repeated(shots) qobj = assemble(circuits, self.SIMULATOR, shots=shots) result = self.SIMULATOR.run( - qobj, backend_options=self.BACKEND_OPTS).result() + qobj, **self.BACKEND_OPTS).result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) diff --git a/test/terra/backends/qasm_simulator/qasm_snapshot.py b/test/terra/backends/qasm_simulator/qasm_snapshot.py index 12f40075dd..ea1f482edf 100644 --- a/test/terra/backends/qasm_simulator/qasm_snapshot.py +++ b/test/terra/backends/qasm_simulator/qasm_snapshot.py @@ -74,7 +74,7 @@ def test_snapshot_statevector_pre_measure_det(self): post_measure=False) qobj = assemble(circuits, self.SIMULATOR, shots=shots) - job = self.SIMULATOR.run(qobj, backend_options=self.BACKEND_OPTS) + job = self.SIMULATOR.run(qobj, **self.BACKEND_OPTS) result = job.result() success = getattr(result, 'success', False) method = self.BACKEND_OPTS.get('method', 'automatic') @@ -104,7 +104,7 @@ def test_snapshot_statevector_pre_measure_nondet(self): post_measure=False) qobj = assemble(circuits, self.SIMULATOR, shots=shots) - job = self.SIMULATOR.run(qobj, backend_options=self.BACKEND_OPTS) + job = self.SIMULATOR.run(qobj, **self.BACKEND_OPTS) result = job.result() success = getattr(result, 'success', False) method = self.BACKEND_OPTS.get('method', 'automatic') @@ -137,7 +137,7 @@ def test_snapshot_statevector_post_measure_det(self): post_measure=True) qobj = assemble(circuits, self.SIMULATOR, memory=True, shots=shots) - job = self.SIMULATOR.run(qobj, backend_options=self.BACKEND_OPTS) + job = self.SIMULATOR.run(qobj, **self.BACKEND_OPTS) result = job.result() success = getattr(result, 'success', False) method = self.BACKEND_OPTS.get('method', 'automatic') @@ -167,7 +167,7 @@ def test_snapshot_statevector_post_measure_nondet(self): post_measure=True) qobj = assemble(circuits, self.SIMULATOR, memory=True, shots=shots) - job = self.SIMULATOR.run(qobj, backend_options=self.BACKEND_OPTS) + job = self.SIMULATOR.run(qobj, **self.BACKEND_OPTS) result = job.result() success = getattr(result, 'success', False) method = self.BACKEND_OPTS.get('method', 'automatic') @@ -226,7 +226,7 @@ def test_snapshot_stabilizer_pre_measure_det(self): post_measure=False) qobj = assemble(circuits, self.SIMULATOR, shots=shots) - job = self.SIMULATOR.run(qobj, backend_options=self.BACKEND_OPTS) + job = self.SIMULATOR.run(qobj, **self.BACKEND_OPTS) result = job.result() success = getattr(result, 'success', False) method = self.BACKEND_OPTS.get('method', 'automatic') @@ -257,7 +257,7 @@ def test_snapshot_stabilizer_pre_measure_nondet(self): post_measure=False) qobj = assemble(circuits, self.SIMULATOR, shots=shots) - job = self.SIMULATOR.run(qobj, backend_options=self.BACKEND_OPTS) + job = self.SIMULATOR.run(qobj, **self.BACKEND_OPTS) result = job.result() success = getattr(result, 'success', False) method = self.BACKEND_OPTS.get('method', 'automatic') @@ -291,7 +291,7 @@ def test_snapshot_stabilizer_post_measure_det(self): post_measure=True) qobj = assemble(circuits, self.SIMULATOR, memory=True, shots=shots) - job = self.SIMULATOR.run(qobj, backend_options=self.BACKEND_OPTS) + job = self.SIMULATOR.run(qobj, **self.BACKEND_OPTS) result = job.result() success = getattr(result, 'success', False) method = self.BACKEND_OPTS.get('method', 'automatic') @@ -322,7 +322,7 @@ def test_snapshot_stabilizer_post_measure_nondet(self): post_measure=True) qobj = assemble(circuits, self.SIMULATOR, memory=True, shots=shots) - job = self.SIMULATOR.run(qobj, backend_options=self.BACKEND_OPTS) + job = self.SIMULATOR.run(qobj, **self.BACKEND_OPTS) result = job.result() success = getattr(result, 'success', False) method = self.BACKEND_OPTS.get('method', 'automatic') @@ -380,7 +380,7 @@ def test_density_matrix_snapshot_ideal(self): tmp = circ.copy() tmp.append(Snapshot(label, 'density_matrix', num_qubits), squbits) result = execute(tmp, self.SIMULATOR, - backend_options=self.BACKEND_OPTS).result() + **self.BACKEND_OPTS).result() if method not in QasmSnapshotDensityMatrixTests.SUPPORTED_QASM_METHODS: self.assertFalse(result.success) else: @@ -436,7 +436,7 @@ def test_snapshot_probabilities_pre_measure(self): circuits = snapshot_probabilities_circuits(post_measure=False) qobj = assemble(circuits, self.SIMULATOR, shots=shots) - job = self.SIMULATOR.run(qobj, backend_options=self.BACKEND_OPTS) + job = self.SIMULATOR.run(qobj, **self.BACKEND_OPTS) result = job.result() success = getattr(result, 'success', False) method = self.BACKEND_OPTS.get('method', 'automatic') @@ -469,7 +469,7 @@ def test_snapshot_probabilities_post_measure(self): circuits = snapshot_probabilities_circuits(post_measure=True) qobj = assemble(circuits, self.SIMULATOR, shots=shots) - job = self.SIMULATOR.run(qobj, backend_options=self.BACKEND_OPTS) + job = self.SIMULATOR.run(qobj, **self.BACKEND_OPTS) result = job.result() success = getattr(result, 'success', False) method = self.BACKEND_OPTS.get('method', 'automatic') @@ -529,7 +529,7 @@ def test_snapshot_expval_pauli_pre_measure(self): circuits = snapshot_expval_circuits(pauli=True, post_measure=False) qobj = assemble(circuits, self.SIMULATOR, shots=shots) - job = self.SIMULATOR.run(qobj, backend_options=self.BACKEND_OPTS) + job = self.SIMULATOR.run(qobj, **self.BACKEND_OPTS) result = job.result() success = getattr(result, 'success', False) method = self.BACKEND_OPTS.get('method', 'automatic') @@ -563,7 +563,7 @@ def test_snapshot_expval_pauli_post_measure(self): circuits = snapshot_expval_circuits(pauli=True, post_measure=True) qobj = assemble(circuits, self.SIMULATOR, shots=shots) - job = self.SIMULATOR.run(qobj, backend_options=self.BACKEND_OPTS) + job = self.SIMULATOR.run(qobj, **self.BACKEND_OPTS) result = job.result() success = getattr(result, 'success', False) method = self.BACKEND_OPTS.get('method', 'automatic') @@ -623,7 +623,7 @@ def general_test(self, pauli, num_qubits=None, seed=None): qc.snapshot_expectation_value('final', [(1, pauli)], pauli_qubits) qobj = assemble(qc) result = self.SIMULATOR.run( - qobj, backend_options=self.BACKEND_OPTS).result() + qobj, **self.BACKEND_OPTS).result() self.assertSuccess(result) snapshots = result.data(0).get('snapshots', {}) self.assertIn('expectation_value', snapshots) @@ -691,7 +691,7 @@ def test_snapshot_expval_matrix_pre_measure(self): circuits = snapshot_expval_circuits(pauli=False, post_measure=False) qobj = assemble(circuits, self.SIMULATOR, shots=shots) - job = self.SIMULATOR.run(qobj, backend_options=self.BACKEND_OPTS) + job = self.SIMULATOR.run(qobj, **self.BACKEND_OPTS) result = job.result() success = getattr(result, 'success', False) method = self.BACKEND_OPTS.get('method', 'automatic') @@ -725,7 +725,7 @@ def test_snapshot_expval_matrix_post_measure(self): circuits = snapshot_expval_circuits(pauli=False, post_measure=True) qobj = assemble(circuits, self.SIMULATOR, shots=shots) - job = self.SIMULATOR.run(qobj, backend_options=self.BACKEND_OPTS) + job = self.SIMULATOR.run(qobj, **self.BACKEND_OPTS) result = job.result() success = getattr(result, 'success', False) method = self.BACKEND_OPTS.get('method', 'automatic') diff --git a/test/terra/backends/qasm_simulator/qasm_standard_gates.py b/test/terra/backends/qasm_simulator/qasm_standard_gates.py index f03f3e2eb2..4d8c578acd 100644 --- a/test/terra/backends/qasm_simulator/qasm_standard_gates.py +++ b/test/terra/backends/qasm_simulator/qasm_standard_gates.py @@ -134,7 +134,7 @@ def test_gate_statevector(self, gate_cls, num_params): self.SIMULATOR, basis_gates=basis_gates, shots=1, - backend_options=backend_options).result() + **backend_options).result() # Check results success = getattr(result, 'success', False) @@ -181,7 +181,7 @@ def test_gate_density_matrix(self, gate_cls, num_params): self.SIMULATOR, basis_gates=basis_gates, shots=1, - backend_options=backend_options).result() + **backend_options).result() # Check results success = getattr(result, 'success', False) diff --git a/test/terra/backends/qasm_simulator/qasm_thread_management.py b/test/terra/backends/qasm_simulator/qasm_thread_management.py index 861f1e1023..0d08d4b51c 100644 --- a/test/terra/backends/qasm_simulator/qasm_thread_management.py +++ b/test/terra/backends/qasm_simulator/qasm_thread_management.py @@ -101,7 +101,7 @@ def test_max_memory_settings(self): # Test defaults opts = self.backend_options_parallel() result = execute(circuit, self.SIMULATOR, shots=shots, - backend_options=opts).result() + **opts).result() max_mem_result = result.metadata.get('max_memory_mb') self.assertGreaterEqual(max_mem_result, int(system_memory / 2), msg="Default 'max_memory_mb' is too small.") @@ -113,7 +113,7 @@ def test_max_memory_settings(self): opts = self.backend_options_parallel() opts['max_memory_mb'] = max_mem_target result = execute(circuit, self.SIMULATOR, shots=shots, - backend_options=opts).result() + **opts).result() max_mem_result = result.metadata.get('max_memory_mb') self.assertEqual(max_mem_result, max_mem_target, msg="Custom 'max_memory_mb' is not being set correctly.") @@ -124,7 +124,7 @@ def available_threads(self): result = execute(self.dummy_circuit(1), self.SIMULATOR, shots=1, - backend_options=opts).result() + **opts).result() return self.threads_used(result)[0]['total'] @requires_omp @@ -140,7 +140,7 @@ def test_parallel_thread_defaults(self): result = execute(self.dummy_circuit(1), self.SIMULATOR, shots=10*max_threads, - backend_options=opts).result() + **opts).result() for threads in self.threads_used(result): target = { 'experiments': 1, @@ -157,7 +157,7 @@ def test_parallel_thread_defaults(self): self.SIMULATOR, shots=10*max_threads, noise_model=self.dummy_noise_model(), - backend_options=opts).result() + **opts).result() for threads in self.threads_used(result): target = { 'experiments': 1, @@ -173,7 +173,7 @@ def test_parallel_thread_defaults(self): result = execute(self.measure_in_middle_circuit(1), self.SIMULATOR, shots=10*max_threads, - backend_options=opts).result() + **opts).result() for threads in self.threads_used(result): target = { 'experiments': 1, @@ -189,7 +189,7 @@ def test_parallel_thread_defaults(self): result = execute(max_threads*[self.dummy_circuit(1)], self.SIMULATOR, shots=10*max_threads, - backend_options=opts).result() + **opts).result() for threads in self.threads_used(result): target = { 'experiments': 1, @@ -206,7 +206,7 @@ def test_parallel_thread_defaults(self): self.SIMULATOR, shots=10*max_threads, noise_model=self.dummy_noise_model(), - backend_options=opts).result() + **opts).result() for threads in self.threads_used(result): target = { 'experiments': 1, @@ -223,7 +223,7 @@ def test_parallel_thread_defaults(self): self.SIMULATOR, shots=10*max_threads, noise_model=self.dummy_noise_model(), - backend_options=opts).result() + **opts).result() for threads in self.threads_used(result): target = { 'experiments': 1, @@ -257,7 +257,7 @@ def test_parallel_thread_assignment_priority(self): result = execute(self.dummy_circuit(1), self.SIMULATOR, shots=10*max_threads, - backend_options=opts).result() + **opts).result() for threads in self.threads_used(result): target = { 'experiments': 1, @@ -274,7 +274,7 @@ def test_parallel_thread_assignment_priority(self): self.SIMULATOR, shots=10*max_threads, noise_model=self.dummy_noise_model(), - backend_options=opts).result() + **opts).result() for threads in self.threads_used(result): target = { 'experiments': 1, @@ -290,7 +290,7 @@ def test_parallel_thread_assignment_priority(self): result = execute(self.measure_in_middle_circuit(1), self.SIMULATOR, shots=10*max_threads, - backend_options=opts).result() + **opts).result() for threads in self.threads_used(result): target = { 'experiments': 1, @@ -306,7 +306,7 @@ def test_parallel_thread_assignment_priority(self): result = execute(max_threads*[self.dummy_circuit(1)], self.SIMULATOR, shots=10*max_threads, - backend_options=opts).result() + **opts).result() for threads in self.threads_used(result): target = { 'experiments': max_threads, @@ -323,7 +323,7 @@ def test_parallel_thread_assignment_priority(self): self.SIMULATOR, shots=10*max_threads, noise_model=self.dummy_noise_model(), - backend_options=opts).result() + **opts).result() for threads in self.threads_used(result): target = { 'experiments': max_threads, @@ -340,7 +340,7 @@ def test_parallel_thread_assignment_priority(self): self.SIMULATOR, shots=10*max_threads, noise_model=self.dummy_noise_model(), - backend_options=opts).result() + **opts).result() for threads in self.threads_used(result): target = { 'experiments': max_threads, @@ -363,7 +363,7 @@ def test_parallel_experiment_thread_assignment(self): result = execute(self.dummy_circuit(1), self.SIMULATOR, shots=10*max_threads, - backend_options=opts).result() + **opts).result() for threads in self.threads_used(result): target = { 'experiments': 1, @@ -378,7 +378,7 @@ def test_parallel_experiment_thread_assignment(self): result = execute(max_threads*[self.dummy_circuit(1)], self.SIMULATOR, shots=10*max_threads, - backend_options=opts).result() + **opts).result() for threads in self.threads_used(result): target = { 'experiments': max_threads, @@ -394,7 +394,7 @@ def test_parallel_experiment_thread_assignment(self): self.SIMULATOR, shots=10*max_threads, noise_model=self.dummy_noise_model(), - backend_options=opts).result() + **opts).result() for threads in self.threads_used(result): target = { 'experiments': max_threads, @@ -410,7 +410,7 @@ def test_parallel_experiment_thread_assignment(self): self.SIMULATOR, shots=10*max_threads, noise_model=self.dummy_noise_model(), - backend_options=opts).result() + **opts).result() for threads in self.threads_used(result): target = { 'experiments': max_threads, @@ -429,7 +429,7 @@ def test_parallel_experiment_thread_assignment(self): result = execute(2 * [circuit], self.SIMULATOR, shots=10*max_threads, - backend_options=opts).result() + **opts).result() for threads in self.threads_used(result): target = { 'experiments': 1, @@ -452,7 +452,7 @@ def test_parallel_shot_thread_assignment(self): result = execute(self.dummy_circuit(1), self.SIMULATOR, shots=10*max_threads, - backend_options=opts).result() + **opts).result() for threads in self.threads_used(result): target = { 'experiments': 1, @@ -467,7 +467,7 @@ def test_parallel_shot_thread_assignment(self): result = execute(max_threads*[self.dummy_circuit(1)], self.SIMULATOR, shots=10*max_threads, - backend_options=opts).result() + **opts).result() for threads in self.threads_used(result): target = { 'experiments': 1, @@ -483,7 +483,7 @@ def test_parallel_shot_thread_assignment(self): self.SIMULATOR, shots=10*max_threads, noise_model=self.dummy_noise_model(), - backend_options=opts).result() + **opts).result() for threads in self.threads_used(result): target = { 'experiments': 1, @@ -499,7 +499,7 @@ def test_parallel_shot_thread_assignment(self): self.SIMULATOR, shots=10*max_threads, noise_model=self.dummy_noise_model(), - backend_options=opts).result() + **opts).result() for threads in self.threads_used(result): target = { 'experiments': 1, @@ -518,7 +518,7 @@ def test_parallel_shot_thread_assignment(self): result = execute(2 * [circuit], self.SIMULATOR, shots=10*max_threads, - backend_options=opts).result() + **opts).result() for threads in self.threads_used(result): target = { 'experiments': 1, @@ -545,7 +545,7 @@ def _test_qasm_explicit_parallelization(self): result = execute( circuit, self.SIMULATOR, shots=shots, - backend_options=backend_opts).result() + **backend_opts).result() if result.metadata['omp_enabled']: self.assertEqual( result.metadata['parallel_experiments'], diff --git a/test/terra/backends/qasm_simulator/qasm_truncate.py b/test/terra/backends/qasm_simulator/qasm_truncate.py index e128f21bf0..b28a59e304 100644 --- a/test/terra/backends/qasm_simulator/qasm_truncate.py +++ b/test/terra/backends/qasm_simulator/qasm_truncate.py @@ -161,7 +161,7 @@ def test_truncate_ideal_sparse_circuit(self): result = execute(circuit, qasm_sim, shots=100, - backend_options=backend_options).result() + **backend_options).result() metadata = result.results[0].metadata self.assertTrue('truncate_qubits' in metadata, msg="truncate_qubits must work.") active_qubits = sorted(metadata['truncate_qubits'].get('active_qubits', [])) @@ -193,7 +193,7 @@ def test_truncate_nonlocal_noise(self): qasm_sim, shots=100, noise_model=noise_model, - backend_options=backend_options).result() + **backend_options).result() metadata = result.results[0].metadata self.assertTrue('truncate_qubits' in metadata, msg="truncate_qubits must work.") active_qubits = sorted(metadata['truncate_qubits'].get('active_qubits', [])) @@ -217,7 +217,7 @@ def test_truncate(self): noise_model=NoiseModel.from_backend(self.device_properties()), shots=100, coupling_map=[[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 0]], # 10-qubit device - backend_options=backend_options).result() + **backend_options).result() self.assertTrue('truncate_qubits' in result.to_dict()['results'][0]['metadata'], msg="truncate_qubits must work.") @@ -236,7 +236,7 @@ def test_no_truncate(self): noise_model=NoiseModel.from_backend(self.device_properties()), shots=100, coupling_map=[[1, 0], [1, 2], [1, 3], [2, 0], [2, 1], [2, 3], [3, 0], [3, 1], [3, 2]], # 4-qubit device - backend_options=backend_options).result() + **backend_options).result() self.assertFalse('truncate_qubits' in result.to_dict()['results'][0]['metadata'], msg="truncate_qubits must work.") @@ -257,7 +257,7 @@ def test_truncate_disable(self): noise_model=NoiseModel.from_backend(self.device_properties()), shots=100, coupling_map=[[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 0]], # 10-qubit device - backend_options=backend_options).result() + **backend_options).result() self.assertFalse('truncate_qubits' in result.to_dict()['results'][0]['metadata'], msg="truncate_qubits must not work.") \ No newline at end of file diff --git a/test/terra/backends/qasm_simulator/qasm_unitary_gate.py b/test/terra/backends/qasm_simulator/qasm_unitary_gate.py index 7c1ce0bd57..7c855d90e8 100644 --- a/test/terra/backends/qasm_simulator/qasm_unitary_gate.py +++ b/test/terra/backends/qasm_simulator/qasm_unitary_gate.py @@ -40,7 +40,7 @@ def test_unitary_gate(self): targets = ref_unitary_gate.unitary_gate_counts_deterministic( shots) result = execute(circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS).result() + **self.BACKEND_OPTS).result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -50,7 +50,7 @@ def test_random_unitary_gate(self): circuits = ref_unitary_gate.unitary_random_gate_circuits_nondeterministic(final_measure=True) targets = ref_unitary_gate.unitary_random_gate_counts_nondeterministic(shots) result = execute(circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS).result() + **self.BACKEND_OPTS).result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -73,6 +73,6 @@ def test_diagonal_gate(self): targets = ref_diagonal_gate.diagonal_gate_counts_deterministic( shots) result = execute(circuits, self.SIMULATOR, shots=shots, - backend_options=self.BACKEND_OPTS).result() + **self.BACKEND_OPTS).result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) diff --git a/test/terra/backends/statevector_simulator/statevector_basics.py b/test/terra/backends/statevector_simulator/statevector_basics.py index be2c403274..05532310ba 100644 --- a/test/terra/backends/statevector_simulator/statevector_basics.py +++ b/test/terra/backends/statevector_simulator/statevector_basics.py @@ -43,7 +43,7 @@ def test_initialize_1(self): circuits = ref_initialize.initialize_circuits_1(final_measure=False) targets = ref_initialize.initialize_statevector_1() qobj = assemble(circuits, shots=1) - sim_job = self.SIMULATOR.run(qobj, backend_options=self.BACKEND_OPTS) + sim_job = self.SIMULATOR.run(qobj, **self.BACKEND_OPTS) result = sim_job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -53,7 +53,7 @@ def test_initialize_2(self): circuits = ref_initialize.initialize_circuits_2(final_measure=False) targets = ref_initialize.initialize_statevector_2() qobj = assemble(circuits, shots=1) - sim_job = self.SIMULATOR.run(qobj, backend_options=self.BACKEND_OPTS) + sim_job = self.SIMULATOR.run(qobj, **self.BACKEND_OPTS) result = sim_job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -70,7 +70,7 @@ def test_reset_deterministic(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -85,7 +85,7 @@ def test_reset_nondeterministic(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -101,7 +101,7 @@ def test_measure(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -117,7 +117,7 @@ def test_conditional_gate_1bit(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -130,7 +130,7 @@ def test_conditional_unitary_1bit(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -143,7 +143,7 @@ def test_conditional_gate_2bit(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) @@ -157,7 +157,7 @@ def test_conditional_unitary_2bit(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -173,7 +173,7 @@ def test_h_gate_deterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -187,7 +187,7 @@ def test_h_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -201,7 +201,7 @@ def test_h_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -214,7 +214,7 @@ def test_h_gate_nondeterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -228,7 +228,7 @@ def test_h_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -242,7 +242,7 @@ def test_h_gate_nondeterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -258,7 +258,7 @@ def test_x_gate_deterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -272,7 +272,7 @@ def test_x_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -286,7 +286,7 @@ def test_x_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -302,7 +302,7 @@ def test_z_gate_deterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -316,7 +316,7 @@ def test_z_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -330,7 +330,7 @@ def test_z_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -346,7 +346,7 @@ def test_y_gate_deterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -360,7 +360,7 @@ def test_y_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -374,7 +374,7 @@ def test_y_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -390,7 +390,7 @@ def test_s_gate_deterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -404,7 +404,7 @@ def test_s_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -418,7 +418,7 @@ def test_s_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -431,7 +431,7 @@ def test_s_gate_nondeterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -445,7 +445,7 @@ def test_s_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -459,7 +459,7 @@ def test_s_gate_nondeterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -475,7 +475,7 @@ def test_sdg_gate_deterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -489,7 +489,7 @@ def test_sdg_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -503,7 +503,7 @@ def test_sdg_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -516,7 +516,7 @@ def test_sdg_gate_nondeterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -530,7 +530,7 @@ def test_sdg_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -544,7 +544,7 @@ def test_sdg_gate_nondeterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -560,7 +560,7 @@ def test_cx_gate_deterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -574,7 +574,7 @@ def test_cx_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -588,7 +588,7 @@ def test_cx_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -601,7 +601,7 @@ def test_cx_gate_nondeterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -615,7 +615,7 @@ def test_cx_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -629,7 +629,7 @@ def test_cx_gate_nondeterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -645,7 +645,7 @@ def test_cz_gate_deterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -659,7 +659,7 @@ def test_cz_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -673,7 +673,7 @@ def test_cz_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -686,7 +686,7 @@ def test_cz_gate_nondeterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -700,7 +700,7 @@ def test_cz_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -714,7 +714,7 @@ def test_cz_gate_nondeterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -730,7 +730,7 @@ def test_swap_gate_deterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -744,7 +744,7 @@ def test_swap_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -758,7 +758,7 @@ def test_swap_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -771,7 +771,7 @@ def test_swap_gate_nondeterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -785,7 +785,7 @@ def test_swap_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -799,7 +799,7 @@ def test_swap_gate_nondeterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -815,7 +815,7 @@ def test_t_gate_deterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -829,7 +829,7 @@ def test_t_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -843,7 +843,7 @@ def test_t_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -856,7 +856,7 @@ def test_t_gate_nondeterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -870,7 +870,7 @@ def test_t_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -884,7 +884,7 @@ def test_t_gate_nondeterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -900,7 +900,7 @@ def test_tdg_gate_deterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -914,7 +914,7 @@ def test_tdg_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -928,7 +928,7 @@ def test_tdg_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -941,7 +941,7 @@ def test_tdg_gate_nondeterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -955,7 +955,7 @@ def test_tdg_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -969,7 +969,7 @@ def test_tdg_gate_nondeterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -985,7 +985,7 @@ def test_ccx_gate_deterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -999,7 +999,7 @@ def test_ccx_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -1013,7 +1013,7 @@ def test_ccx_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -1026,7 +1026,7 @@ def test_ccx_gate_nondeterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -1040,7 +1040,7 @@ def test_ccx_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -1054,7 +1054,7 @@ def test_ccx_gate_nondeterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -1070,7 +1070,7 @@ def test_unitary_gate(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -1083,7 +1083,7 @@ def test_diagonal_gate(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -1099,7 +1099,7 @@ def test_cu1_gate_nondeterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -1113,7 +1113,7 @@ def test_cu1_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -1127,7 +1127,7 @@ def test_cu1_gate_nondeterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -1144,7 +1144,7 @@ def test_cswap_gate_deterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -1158,7 +1158,7 @@ def test_cswap_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -1172,7 +1172,7 @@ def test_cswap_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -1185,7 +1185,7 @@ def test_cswap_gate_nondeterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -1199,7 +1199,7 @@ def test_cswap_gate_nondeterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -1213,7 +1213,7 @@ def test_cswap_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -1230,7 +1230,7 @@ def test_cu3_gate_deterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -1244,7 +1244,7 @@ def test_cu3_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -1258,7 +1258,7 @@ def test_cu3_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_statevector(result, circuits, targets) @@ -1275,7 +1275,7 @@ def test_qobj_global_phase(self): targets = ref_1q_clifford.h_gate_statevector_nondeterministic() qobj = assemble(transpile(circuits, self.SIMULATOR), - shots=1, backend_options=self.BACKEND_OPTS) + shots=1, **self.BACKEND_OPTS) # Set global phases for i, _ in enumerate(circuits): global_phase = (-1) ** i * (pi / 4) diff --git a/test/terra/backends/statevector_simulator/statevector_fusion.py b/test/terra/backends/statevector_simulator/statevector_fusion.py index 73bf3c818d..ed547ace5a 100644 --- a/test/terra/backends/statevector_simulator/statevector_fusion.py +++ b/test/terra/backends/statevector_simulator/statevector_fusion.py @@ -50,7 +50,7 @@ def test_fusion_theshold(self): circuit = transpile(circuit, self.SIMULATOR) qobj = assemble([circuit], shots=1) result = self.SIMULATOR.run( - qobj, backend_options=backend_options).result() + qobj, **backend_options).result() meta = self.fusion_metadata(result) self.assertSuccess(result) @@ -61,7 +61,7 @@ def test_fusion_theshold(self): circuit = transpile(circuit, self.SIMULATOR) qobj = assemble([circuit], shots=1) result = self.SIMULATOR.run( - qobj, backend_options=backend_options).result() + qobj, **backend_options).result() meta = self.fusion_metadata(result) self.assertSuccess(result) @@ -72,7 +72,7 @@ def test_fusion_theshold(self): circuit = transpile(circuit, self.SIMULATOR) qobj = assemble([circuit], shots=1) result = self.SIMULATOR.run( - qobj, backend_options=backend_options).result() + qobj, **backend_options).result() meta = self.fusion_metadata(result) self.assertSuccess(result) @@ -88,7 +88,7 @@ def test_fusion_disable(self): with self.subTest(msg='test fusion enable'): backend_options = self.fusion_options(enabled=True, threshold=1) result = self.SIMULATOR.run( - qobj, backend_options=backend_options).result() + qobj, **backend_options).result() meta = self.fusion_metadata(result) self.assertSuccess(result) @@ -97,7 +97,7 @@ def test_fusion_disable(self): with self.subTest(msg='test fusion disable'): backend_options = self.fusion_options(enabled=False, threshold=1) result = self.SIMULATOR.run( - qobj, backend_options=backend_options).result() + qobj, **backend_options).result() meta = self.fusion_metadata(result) self.assertSuccess(result) @@ -112,12 +112,12 @@ def test_fusion_output(self): options_disabled = self.fusion_options(enabled=False, threshold=1) result_disabled = self.SIMULATOR.run( - qobj, backend_options=options_disabled).result() + qobj, **options_disabled).result() self.assertSuccess(result_disabled) options_enabled = self.fusion_options(enabled=True, threshold=1) result_enabled = self.SIMULATOR.run( - qobj, backend_options=options_enabled).result() + qobj, **options_enabled).result() self.assertSuccess(result_enabled) sv_no_fusion = Statevector(result_disabled.get_statevector(0)) diff --git a/test/terra/backends/test_config_pulse_simulator.py b/test/terra/backends/test_config_pulse_simulator.py new file mode 100644 index 0000000000..43d3311408 --- /dev/null +++ b/test/terra/backends/test_config_pulse_simulator.py @@ -0,0 +1,338 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2018, 2019, 2020. +# +# 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. +""" +Configurable PulseSimulator Tests +""" + +import sys +import unittest +import warnings +import numpy as np +from test.terra import common + +from qiskit.test.mock.backends.armonk.fake_armonk import FakeArmonk +from qiskit.test.mock.backends.athens.fake_athens import FakeAthens + +from qiskit.providers.aer.backends import PulseSimulator +from qiskit.pulse import (Schedule, Play, ShiftPhase, SetPhase, Delay, Acquire, + Waveform, DriveChannel, ControlChannel, + AcquireChannel, MemorySlot) +from qiskit.providers.aer.aererror import AerError + +from qiskit.compiler import assemble +from qiskit.providers.aer.pulse.system_models.pulse_system_model import PulseSystemModel +from qiskit.providers.aer.pulse.system_models.hamiltonian_model import HamiltonianModel +from qiskit.providers.models.backendconfiguration import UchannelLO + + +class TestConfigPulseSimulator(common.QiskitAerTestCase): + r"""PulseSimulator tests.""" + + def test_from_backend(self): + """Test that configuration, defaults, and properties are correclty imported.""" + + athens_backend = FakeAthens() + athens_sim = PulseSimulator.from_backend(athens_backend) + + self.assertEqual(athens_backend.properties(), athens_sim.properties()) + # check that configuration is correctly imported + backend_dict = athens_backend.configuration().to_dict() + sim_dict = athens_sim.configuration().to_dict() + for key in sim_dict: + if key == 'backend_name': + self.assertEqual(sim_dict[key], 'pulse_simulator(fake_athens)') + elif key == 'description': + desc = 'A Pulse-based simulator configured from the backend: fake_athens' + self.assertEqual(sim_dict[key], desc) + elif key == 'simulator': + self.assertTrue(sim_dict[key], True) + else: + self.assertEqual(sim_dict[key], backend_dict[key]) + + backend_dict = athens_backend.defaults().to_dict() + sim_dict = athens_sim.defaults().to_dict() + for key in sim_dict: + if key == 'pulse_library': + # need to compare pulse libraries directly due to containing dictionaries + for idx, entry in enumerate(sim_dict[key]): + for entry_key in entry: + if entry_key == 'samples': + self.assertTrue(all(entry[entry_key] == backend_dict[key][idx][entry_key])) + else: + self.assertTrue(entry[entry_key] == backend_dict[key][idx][entry_key]) + else: + self.assertEqual(sim_dict[key], backend_dict[key]) + + def test_from_backend_system_model(self): + """Test that the system model is correctly imported from the backend.""" + + athens_backend = FakeAthens() + athens_sim = PulseSimulator.from_backend(athens_backend) + + # u channel lo + athens_attr = athens_backend.configuration().u_channel_lo + sim_attr = athens_sim.configuration().u_channel_lo + model_attr = athens_sim._system_model.u_channel_lo + self.assertTrue(sim_attr == athens_attr and model_attr == athens_attr) + + # dt + athens_attr = athens_backend.configuration().dt + sim_attr = athens_sim.configuration().dt + model_attr = athens_sim._system_model.dt + self.assertTrue(sim_attr == athens_attr and model_attr == athens_attr) + + def test_set_system_model_options(self): + """Test setting of options that need to be changed in multiple places.""" + + athens_backend = FakeAthens() + athens_sim = PulseSimulator.from_backend(athens_backend) + + # u channel lo + set_attr = [[UchannelLO(0, 1.0 + 0.0j)]] + athens_sim.set_options(u_channel_lo=set_attr) + sim_attr = athens_sim.configuration().u_channel_lo + model_attr = athens_sim._system_model.u_channel_lo + self.assertTrue(sim_attr == set_attr and model_attr == set_attr) + + # dt + set_attr = 5. + athens_sim.set_options(dt=set_attr) + sim_attr = athens_sim.configuration().dt + model_attr = athens_sim._system_model.dt + self.assertTrue(sim_attr == set_attr and model_attr == set_attr) + + def test_set_meas_levels(self): + """Test setting of meas_levels.""" + + athens_backend = FakeAthens() + athens_sim = PulseSimulator.from_backend(athens_backend) + + # test that a warning is thrown when meas_level 0 is attempted to be set + with warnings.catch_warnings(record=True) as w: + # Cause all warnings to always be triggered. + warnings.simplefilter("always") + + athens_sim.set_options(meas_levels=[0,1,2]) + + self.assertEqual(len(w), 1) + self.assertTrue('Measurement level 0 not supported' in str(w[-1].message)) + self.assertEqual(athens_sim.configuration().meas_levels, [1, 2]) + + self.assertTrue(athens_sim.configuration().meas_levels == [1, 2]) + + athens_sim.set_options(meas_levels=[2]) + self.assertTrue(athens_sim.configuration().meas_levels == [2]) + + def test_set_system_model_from_backend(self): + """Test setting system model when constructing from backend.""" + + armonk_backend = FakeArmonk() + system_model = self._system_model_1Q() + + # these are 1q systems so this doesn't make sense but can still be used to test + system_model.u_channel_lo = [[UchannelLO(0, 1.0 + 0.0j)]] + + armonk_sim = None + + # construct backend and catch warning + with warnings.catch_warnings(record=True) as w: + # Cause all warnings to always be triggered. + warnings.simplefilter("always") + + armonk_sim = PulseSimulator.from_backend(backend=armonk_backend, + system_model=system_model) + + self.assertEqual(len(w), 1) + self.assertTrue('inconsistencies' in str(w[-1].message)) + + # check that system model properties have been imported + self.assertEqual(armonk_sim.configuration().dt, system_model.dt) + self.assertEqual(armonk_sim.configuration().u_channel_lo, system_model.u_channel_lo) + + def test_set_system_model_in_constructor(self): + """Test setting system model when constructing.""" + + system_model = self._system_model_1Q() + + # these are 1q systems so this doesn't make sense but can still be used to test + system_model.u_channel_lo = [[UchannelLO(0, 1.0 + 0.0j)]] + + # construct directly + test_sim = None + # construct backend and verify no warnings + with warnings.catch_warnings(record=True) as w: + # Cause all warnings to always be triggered. + warnings.simplefilter("always") + + test_sim = PulseSimulator(system_model=system_model) + + self.assertEqual(len(w), 0) + + # check that system model properties have been imported + self.assertEqual(test_sim.configuration().dt, system_model.dt) + self.assertEqual(test_sim.configuration().u_channel_lo, system_model.u_channel_lo) + + def test_set_system_model_after_construction(self): + """Test setting the system model after construction.""" + + system_model = self._system_model_1Q() + + # these are 1q systems so this doesn't make sense but can still be used to test + system_model.u_channel_lo = [[UchannelLO(0, 1.0 + 0.0j)]] + + # first test setting after construction with no hamiltonian + test_sim = PulseSimulator() + + with warnings.catch_warnings(record=True) as w: + # Cause all warnings to always be triggered. + warnings.simplefilter("always") + + test_sim.set_options(system_model=system_model) + self.assertEqual(len(w), 0) + + # check that system model properties have been imported + self.assertEqual(test_sim._system_model, system_model) + self.assertEqual(test_sim.configuration().dt, system_model.dt) + self.assertEqual(test_sim.configuration().u_channel_lo, system_model.u_channel_lo) + + # next, construct a pulse simulator with a config containing a Hamiltonian and observe + # warnings + armonk_backend = FakeArmonk() + test_sim = PulseSimulator(configuration=armonk_backend.configuration()) + + # add system model and verify warning is raised + with warnings.catch_warnings(record=True) as w: + # Cause all warnings to always be triggered. + warnings.simplefilter("always") + + armonk_sim = test_sim.set_options(system_model=system_model) + + self.assertEqual(len(w), 1) + self.assertTrue('inconsistencies' in str(w[-1].message)) + + self.assertEqual(test_sim.configuration().dt, system_model.dt) + self.assertEqual(test_sim.configuration().u_channel_lo, system_model.u_channel_lo) + + def test_validation_num_acquires(self): + """Test that validation fails if 0 or >1 acquire is given in a schedule.""" + + test_sim = PulseSimulator.from_backend(FakeArmonk()) + + # check that too many acquires results in an error + qobj = assemble([self._1Q_schedule(num_acquires=2)], + backend=test_sim, + meas_level=2, + qubit_lo_freq=[0.], + meas_return='single', + shots=256) + + try: + test_sim.run(qobj).result() + except AerError as error: + self.assertTrue('does not support multiple Acquire' in error.message) + + # check that no acquires results in an error + qobj = assemble([self._1Q_schedule(num_acquires=0)], + backend=test_sim, + meas_level=2, + qubit_lo_freq=[0.], + meas_return='single', + shots=256) + + try: + test_sim.run(qobj).result() + except AerError as error: + self.assertTrue('requires at least one Acquire' in error.message) + + def test_run_simulation_from_backend(self): + """Construct from a backend and run a simulation.""" + armonk_backend = FakeArmonk() + + # manually override parameters to insulate from future changes to FakeArmonk + freq_est = 4.97e9 + drive_est = 6.35e7 + armonk_backend.defaults().qubit_freq_est = [freq_est] + armonk_backend.configuration().hamiltonian['h_str']= ['wq0*0.5*(I0-Z0)', 'omegad0*X0||D0'] + armonk_backend.configuration().hamiltonian['vars'] = {'wq0': 2 * np.pi * freq_est, + 'omegad0': drive_est} + armonk_backend.configuration().hamiltonian['qub'] = {'0': 2} + dt = 2.2222222222222221e-10 + armonk_backend.configuration().dt = dt + + armonk_sim = PulseSimulator.from_backend(armonk_backend) + + total_samples = 250 + amp = np.pi / (drive_est * dt * total_samples) + + sched = self._1Q_schedule(total_samples, amp) + qobj = assemble([sched], + backend=armonk_sim, + meas_level=2, + meas_return='single', + shots=1) + # run and verify that a pi pulse had been done + result = armonk_sim.run(qobj).result() + final_vec = result.get_statevector() + probabilities = np.abs(final_vec)**2 + self.assertTrue(probabilities[0] < 1e-5) + self.assertTrue(probabilities[1] > 1 - 1e-5) + + def _system_model_1Q(self, omega_0=5., r=0.02): + """Constructs a standard model for a 1 qubit system. + + Args: + omega_0 (float): qubit frequency + r (float): drive strength + + Returns: + PulseSystemModel: model for qubit system + """ + + hamiltonian = {} + hamiltonian['h_str'] = [ + '2*np.pi*omega0*0.5*Z0', '2*np.pi*r*0.5*X0||D0' + ] + hamiltonian['vars'] = {'omega0': omega_0, 'r': r} + hamiltonian['qub'] = {'0': 2} + ham_model = HamiltonianModel.from_dict(hamiltonian) + + u_channel_lo = [] + subsystem_list = [0] + dt = 1. + + return PulseSystemModel(hamiltonian=ham_model, + u_channel_lo=u_channel_lo, + subsystem_list=subsystem_list, + dt=dt) + + def _1Q_schedule(self, total_samples=100, amp=1., num_acquires=1): + """Creates a schedule for a single qubit. + + Args: + total_samples (int): number of samples in the drive pulse + amp (complex): amplitude of drive pulse + num_acquires (int): number of acquire instructions to include in the schedule + + Returns: + schedule (pulse schedule): + """ + + schedule = Schedule() + schedule |= Play(Waveform(amp * np.ones(total_samples)), DriveChannel(0)) + for _ in range(num_acquires): + schedule |= Acquire(total_samples, AcquireChannel(0), + MemorySlot(0)) << schedule.duration + return schedule + + +if __name__ == '__main__': + unittest.main() diff --git a/test/terra/backends/test_pulse_simulator.py b/test/terra/backends/test_pulse_simulator.py index 43a7d656cc..11cf93db4a 100644 --- a/test/terra/backends/test_pulse_simulator.py +++ b/test/terra/backends/test_pulse_simulator.py @@ -26,21 +26,22 @@ from qiskit.compiler import assemble from qiskit.quantum_info import state_fidelity -from qiskit.pulse import (Schedule, Play, ShiftPhase, SetPhase, Delay, Acquire, SamplePulse, - DriveChannel, ControlChannel, AcquireChannel, MemorySlot) +from qiskit.pulse import (Schedule, Play, ShiftPhase, SetPhase, Delay, Acquire, + Waveform, DriveChannel, ControlChannel, + AcquireChannel, MemorySlot) from qiskit.providers.aer.pulse.de.DE_Methods import ScipyODE from qiskit.providers.aer.pulse.de.DE_Options import DE_Options from qiskit.providers.aer.pulse.system_models.pulse_system_model import PulseSystemModel from qiskit.providers.aer.pulse.system_models.hamiltonian_model import HamiltonianModel from qiskit.providers.models.backendconfiguration import UchannelLO -from .pulse_sim_independent import (simulate_1q_model, simulate_2q_exchange_model, +from .pulse_sim_independent import (simulate_1q_model, + simulate_2q_exchange_model, simulate_3d_oscillator_model) class TestPulseSimulator(common.QiskitAerTestCase): r"""PulseSimulator tests.""" - def setUp(self): """ Set configuration settings for pulse simulator""" super().setUp() @@ -66,14 +67,17 @@ def test_x_gate(self): r = 0.01 total_samples = 100 - system_model = self._system_model_1Q(omega_0, r) + # initial state and seed + y0 = np.array([1.0, 0.0]) + seed = 9000 + + # set up simulator + pulse_sim = PulseSimulator(system_model=self._system_model_1Q(omega_0, r)) # set up constant pulse for doing a pi pulse schedule = self._1Q_constant_sched(total_samples) - - # set up schedule and qobj qobj = assemble([schedule], - backend=self.backend_sim, + backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], @@ -81,27 +85,22 @@ def test_x_gate(self): memory_slots=1, shots=256) - # set backend backend_options including initial state - y0 = np.array([1.0, 0.0]) - backend_options = {'seed' : 9000, 'initial_state' : y0} - - # run simulation - result = self.backend_sim.run(qobj, - system_model=system_model, - backend_options=backend_options).result() + result = pulse_sim.run(qobj, initial_state=y0, seed=seed).result() pulse_sim_yf = result.get_statevector() # set up and run independent simulation samples = np.ones((total_samples, 1)) - indep_yf = simulate_1q_model(y0, omega_0, r, np.array([omega_0]), samples, 1.) + indep_yf = simulate_1q_model(y0, omega_0, r, np.array([omega_0]), + samples, 1.) # approximate analytic solution - phases = np.exp(-1j * 2 * np.pi * omega_0 * total_samples * np.array([1., -1.]) / 2) + phases = np.exp(-1j * 2 * np.pi * omega_0 * total_samples * + np.array([1., -1.]) / 2) approx_yf = phases * np.array([0., -1j]) # test final state - self.assertGreaterEqual(state_fidelity(pulse_sim_yf, indep_yf), 1-10**-5) + self.assertGreaterEqual(state_fidelity(pulse_sim_yf, indep_yf), 1 - 10**-5) self.assertGreaterEqual(state_fidelity(pulse_sim_yf, approx_yf), 0.99) # test counts @@ -122,14 +121,17 @@ def test_x_gate_rwa(self): r = 0.01 / 2 total_samples = 100 - system_model = self._system_model_1Q(omega_0, r) + # initial state and seed + y0 = np.array([1.0, 0.0]) + seed = 9000 + + # set up simulator + pulse_sim = PulseSimulator(system_model=self._system_model_1Q(omega_0, r)) # set up constant pulse for doing a pi pulse schedule = self._1Q_constant_sched(total_samples) - - # set up schedule and qobj qobj = assemble([schedule], - backend=self.backend_sim, + backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], @@ -137,22 +139,14 @@ def test_x_gate_rwa(self): memory_slots=1, shots=1) - # set backend backend_options including initial state - y0 = np.array([1.0, 0.0]) - backend_options = {'seed' : 9000, 'initial_state' : y0} - - # run simulation - result = self.backend_sim.run(qobj, - system_model=system_model, - backend_options=backend_options).result() + result = pulse_sim.run(qobj, initial_state=y0, seed=seed).result() pulse_sim_yf = result.get_statevector() # expected final state yf = np.array([0., -1j]) # test final state - self.assertGreaterEqual(state_fidelity(pulse_sim_yf, yf), 1-10**-5) - + self.assertGreaterEqual(state_fidelity(pulse_sim_yf, yf), 1 - 10**-5) def test_x_half_gate(self): """Test a schedule for a pi/2 pulse on a 2 level system. Same setup as test_x_gate but @@ -166,14 +160,17 @@ def test_x_half_gate(self): r = 0.01 total_samples = 50 - system_model = self._system_model_1Q(omega_0, r) + # initial state and seed + y0 = np.array([1.0, 0.0]) + seed = 9000 + + # set up simulator + pulse_sim = PulseSimulator(system_model=self._system_model_1Q(omega_0, r)) # set up constant pulse for doing a pi pulse schedule = self._1Q_constant_sched(total_samples) - - # set up schedule and qobj qobj = assemble([schedule], - backend=self.backend_sim, + backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], @@ -181,27 +178,23 @@ def test_x_half_gate(self): memory_slots=1, shots=256) - # set backend backend_options - y0 = np.array([1.0, 0.0]) - backend_options = {'seed' : 9000, 'initial_state' : y0} - - # run simulation - result = self.backend_sim.run(qobj, - system_model=system_model, - backend_options=backend_options).result() + result = pulse_sim.run(qobj, initial_state=y0, seed=seed).result() pulse_sim_yf = result.get_statevector() # set up and run independent simulation samples = np.ones((total_samples, 1)) - indep_yf = simulate_1q_model(y0, omega_0, r, np.array([omega_d]), samples, 1.) + indep_yf = simulate_1q_model(y0, omega_0, r, np.array([omega_d]), + samples, 1.) # approximate analytic solution - phases = np.exp(-1j * 2 * np.pi * omega_0 * total_samples * np.array([1., -1.]) / 2) + phases = np.exp(-1j * 2 * np.pi * omega_0 * total_samples * + np.array([1., -1.]) / 2) approx_yf = phases * (expm(-1j * (np.pi / 4) * self.X) @ y0) # test final state - self.assertGreaterEqual(state_fidelity(pulse_sim_yf, indep_yf), 1-10**-5) + self.assertGreaterEqual(state_fidelity(pulse_sim_yf, indep_yf), + 1 - 10**-5) self.assertGreaterEqual(state_fidelity(pulse_sim_yf, approx_yf), 0.99) # test counts @@ -221,14 +214,17 @@ def test_y_half_gate(self): r = 0.01 total_samples = 50 - system_model = self._system_model_1Q(omega_0, r) + # initial state and seed + y0 = np.array([1.0, 0.0]) + seed = 9000 + + # set up simulator + pulse_sim = PulseSimulator(system_model=self._system_model_1Q(omega_0, r)) # set up constant pulse for doing a pi pulse schedule = self._1Q_constant_sched(total_samples, amp=1j) - - # set up schedule and qobj qobj = assemble([schedule], - backend=self.backend_sim, + backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], @@ -236,27 +232,23 @@ def test_y_half_gate(self): memory_slots=1, shots=256) - # set backend backend_options - y0 = np.array([1.0, 0.0]) - backend_options = {'seed' : 9000, 'initial_state' : y0} - - # run simulation - result = self.backend_sim.run(qobj, - system_model=system_model, - backend_options=backend_options).result() + result = pulse_sim.run(qobj, initial_state=y0, seed=seed).result() pulse_sim_yf = result.get_statevector() # set up and run independent simulation samples = 1j * np.ones((total_samples, 1)) - indep_yf = simulate_1q_model(y0, omega_0, r, np.array([omega_d]), samples, 1.) + indep_yf = simulate_1q_model(y0, omega_0, r, np.array([omega_d]), + samples, 1.) # approximate analytic solution - phases = np.exp(-1j * 2 * np.pi * omega_0 * total_samples * np.array([1., -1.]) / 2) + phases = np.exp(-1j * 2 * np.pi * omega_0 * total_samples * + np.array([1., -1.]) / 2) approx_yf = phases * (expm(-1j * (np.pi / 4) * self.Y) @ y0) # test final state - self.assertGreaterEqual(state_fidelity(pulse_sim_yf, indep_yf), 1-10**-5) + self.assertGreaterEqual(state_fidelity(pulse_sim_yf, indep_yf), + 1 - 10**-5) self.assertGreaterEqual(state_fidelity(pulse_sim_yf, approx_yf), 0.99) # test counts @@ -277,13 +269,20 @@ def test_1Q_noise(self): r = 0.01 total_samples = 100 - system_model = self._system_model_1Q(omega_0, r) + # initial state, seed, and noise model + y0 = np.array([1.0, 0.0]) + seed = 9000 + noise_model = {"qubit": {"0": {"Sm": 1.}}} + + # set up simulator + pulse_sim = PulseSimulator(system_model=self._system_model_1Q(omega_0, r), + noise_model=noise_model) # set up constant pulse for doing a pi pulse schedule = self._1Q_constant_sched(total_samples) qobj = assemble([schedule], - backend=self.backend_sim, + backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], @@ -291,14 +290,7 @@ def test_1Q_noise(self): memory_slots=2, shots=10) - # set seed for simulation, and set noise - y0 = np.array([1., 0.]) - backend_options = {'seed' : 9000, 'initial_state' : y0} - backend_options['noise_model'] = {"qubit": {"0": {"Sm": 1.}}} - - # run simulation - result = self.backend_sim.run(qobj, system_model=system_model, - backend_options=backend_options).result() + result = pulse_sim.run(qobj, initial_state=y0, seed=seed).result() # test results # This level of noise is high enough that all counts should yield 0, @@ -319,14 +311,16 @@ def test_unitary_parallel(self): r = 0.01 total_samples = 50 - system_model = self._system_model_1Q(omega_0, r) + # initial state and seed + y0 = np.array([1.0, 0.0]) + seed = 9000 + + pulse_sim = PulseSimulator(system_model=self._system_model_1Q(omega_0, r)) # set up constant pulse for doing a pi pulse schedule = self._1Q_constant_sched(total_samples) - - # set up schedule and qobj qobj = assemble([schedule, schedule], - backend=self.backend_sim, + backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], @@ -334,13 +328,7 @@ def test_unitary_parallel(self): memory_slots=1, shots=256) - # set backend backend_options - y0 = np.array([1., 0.]) - backend_options = backend_options = {'seed' : 9000, 'initial_state' : y0} - - # run simulation - result = self.backend_sim.run(qobj, system_model=system_model, - backend_options=backend_options).result() + result = pulse_sim.run(qobj, initial_state=y0, seed=seed).result() # test results, checking both runs in parallel counts = result.get_counts() @@ -349,11 +337,11 @@ def test_unitary_parallel(self): self.assertDictAlmostEqual(counts[0], exp_counts0) self.assertDictAlmostEqual(counts[1], exp_counts1) - def test_dt_scaling_x_gate(self): """Test that dt is being used correctly by the solver.""" total_samples = 100 + # do the same thing as test_x_gate, but scale dt and all frequency parameters # define test case for a single scaling def scale_test(scale): @@ -366,15 +354,20 @@ def scale_test(scale): r = 0.01 / scale total_samples = 100 - # set up system model and scale time + # initial state and seed + y0 = np.array([1.0, 0.0]) + seed = 9000 + + + # set up simulator system_model = self._system_model_1Q(omega_0, r) - system_model.dt = system_model.dt * scale + pulse_sim = PulseSimulator(system_model=self._system_model_1Q(omega_0, r)) + pulse_sim.set_options(dt=scale) # set up constant pulse for doing a pi pulse schedule = self._1Q_constant_sched(total_samples) - qobj = assemble([schedule], - backend=self.backend_sim, + backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], @@ -382,28 +375,26 @@ def scale_test(scale): memory_slots=2, shots=256) - # set backend backend_options - y0 = np.array([1., 0.]) - backend_options = {'seed' : 9000, 'initial_state': y0} - - # run simulation - result = self.backend_sim.run(qobj, system_model=system_model, - backend_options=backend_options).result() + result = pulse_sim.run(qobj, initial_state=y0, seed=seed).result() pulse_sim_yf = result.get_statevector() # set up and run independent simulation samples = np.ones((total_samples, 1)) - indep_yf = simulate_1q_model(y0, omega_0, r, np.array([omega_0]), samples, scale) + indep_yf = simulate_1q_model(y0, omega_0, r, np.array([omega_0]), + samples, scale) # approximate analytic solution - phases = np.exp(-1j * 2 * np.pi * omega_0 * total_samples * np.array([1., -1.]) / 2) + phases = np.exp(-1j * 2 * np.pi * omega_0 * total_samples * + np.array([1., -1.]) / 2) approx_yf = phases * np.array([0., -1j]) # test final state - self.assertGreaterEqual(state_fidelity(pulse_sim_yf, indep_yf), 1-10**-5) - self.assertGreaterEqual(state_fidelity(pulse_sim_yf, approx_yf), 0.99) + self.assertGreaterEqual(state_fidelity(pulse_sim_yf, indep_yf), + 1 - 10**-5) + self.assertGreaterEqual(state_fidelity(pulse_sim_yf, approx_yf), + 0.99) counts = result.get_counts() exp_counts = {'1': 256} @@ -426,14 +417,19 @@ def test_arbitrary_constant_drive(self): r_vals = [3 / total_samples, 5 / total_samples, 0.1] phase_vals = [5 * np.pi / 7, 19 * np.pi / 14, np.pi / 4] + # initial state and seed + y0 = np.array([1.0, 0.0]) + seed = 9000 + for i in range(num_tests): with self.subTest(i=i): - system_model = self._system_model_1Q(omega_0, r_vals[i]) - schedule = self._1Q_constant_sched(total_samples, amp=np.exp(-1j * phase_vals[i])) + # set up simulator + pulse_sim = PulseSimulator(system_model=self._system_model_1Q(omega_0, r_vals[i])) + schedule = self._1Q_constant_sched(total_samples, amp=np.exp(-1j *phase_vals[i])) qobj = assemble([schedule], - backend=self.backend_sim, + backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], @@ -441,28 +437,33 @@ def test_arbitrary_constant_drive(self): memory_slots=2, shots=1) - # Run qobj and compare prop to expected result - y0 = np.array([1., 0.]) - backend_options = {'seed' : 9000, 'initial_state' : y0} - result = self.backend_sim.run(qobj, system_model, backend_options).result() - + result = pulse_sim.run(qobj, initial_state=y0, seed=seed).result() pulse_sim_yf = result.get_statevector() + # set up and run independent simulation - samples = np.exp(-1j * phase_vals[i]) * np.ones((total_samples, 1)) + samples = np.exp(-1j * phase_vals[i]) * np.ones( + (total_samples, 1)) - indep_yf = simulate_1q_model(y0, omega_0, r_vals[i], np.array([omega_d_vals[i]]), samples, 1.) + indep_yf = simulate_1q_model(y0, omega_0, r_vals[i], + np.array([omega_d_vals[i]]), + samples, 1.) # approximate analytic solution - phases = np.exp(-1j * 2 * np.pi * omega_d_vals[i] * total_samples * np.array([1., -1.]) / 2) + phases = np.exp(-1j * 2 * np.pi * omega_d_vals[i] * + total_samples * np.array([1., -1.]) / 2) detuning = omega_0 - omega_d_vals[i] amp = np.exp(-1j * phase_vals[i]) - rwa_ham = 2 * np.pi * (detuning * self.Z / 2 + r_vals[i] * np.array([[0, amp.conj()], [amp, 0.]]) / 4) + rwa_ham = 2 * np.pi * ( + detuning * self.Z / 2 + + r_vals[i] * np.array([[0, amp.conj()], [amp, 0.]]) / 4) approx_yf = phases * (expm(-1j * rwa_ham * total_samples) @ y0) # test final state - self.assertGreaterEqual(state_fidelity(pulse_sim_yf, indep_yf), 1-10**-5) - self.assertGreaterEqual(state_fidelity(pulse_sim_yf, approx_yf), 0.99) + self.assertGreaterEqual(state_fidelity(pulse_sim_yf, indep_yf), + 1 - 10**-5) + self.assertGreaterEqual( + state_fidelity(pulse_sim_yf, approx_yf), 0.99) def test_3d_oscillator(self): """Test simulation of a duffing oscillator truncated to 3 dimensions.""" @@ -475,56 +476,56 @@ def test_3d_oscillator(self): # Test pi pulse r = 0.5 / total_samples - system_model = self._system_model_3d_oscillator(freq, anharm, r) - schedule = self._1Q_constant_sched(total_samples) + # set up simulator + system_model = system_model = self._system_model_3d_oscillator(freq, anharm, r) + pulse_sim = PulseSimulator(system_model=system_model) + schedule = self._1Q_constant_sched(total_samples) qobj = assemble([schedule], - backend=self.backend_sim, + backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], qubit_lo_freq=[freq], shots=1) - backend_options = {'seed' : 9000} - result = self.backend_sim.run(qobj, system_model, backend_options).result() + result = pulse_sim.run(qobj).result() pulse_sim_yf = result.get_statevector() - # set up and run independent simulation y0 = np.array([1., 0., 0.]) samples = np.ones((total_samples, 1)) - indep_yf = simulate_3d_oscillator_model(y0, freq, anharm, r, np.array([freq]), samples, 1.) + indep_yf = simulate_3d_oscillator_model(y0, freq, anharm, r, + np.array([freq]), samples, 1.) # test final state - self.assertGreaterEqual(state_fidelity(pulse_sim_yf, indep_yf), 1-10**-5) + self.assertGreaterEqual(state_fidelity(pulse_sim_yf, indep_yf), 1 - 10**-5) + # test with different input state + y0 = np.array([0., 0., 1.]) # Test some irregular value r = 1.49815 / total_samples - system_model = self._system_model_3d_oscillator(freq, anharm, r) - schedule = self._1Q_constant_sched(total_samples) + pulse_sim.set_options(system_model=system_model) + schedule = self._1Q_constant_sched(total_samples) qobj = assemble([schedule], - backend=self.backend_sim, + backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], qubit_lo_freq=[freq], shots=1) - - y0 = np.array([0., 0., 1.]) - backend_options = {'seed' : 9000, 'initial_state' : y0} - - result = self.backend_sim.run(qobj, system_model, backend_options).result() + result = pulse_sim.run(qobj, initial_state=y0).result() pulse_sim_yf = result.get_statevector() samples = np.ones((total_samples, 1)) - indep_yf = simulate_3d_oscillator_model(y0, freq, anharm, r, np.array([freq]), samples, 1.) + indep_yf = simulate_3d_oscillator_model(y0, freq, anharm, r, + np.array([freq]), samples, 1.) # test final state - self.assertGreaterEqual(state_fidelity(pulse_sim_yf, indep_yf), 1-10**-5) + self.assertGreaterEqual(state_fidelity(pulse_sim_yf, indep_yf), 1 - 10**-5) def test_2Q_interaction(self): r"""Test 2 qubit interaction via controlled operations using u channels.""" @@ -536,12 +537,14 @@ def test_2Q_interaction(self): omega_d0 = 0. omega_d1 = 0. - system_model = self._system_model_2Q(j) + y0 = np.kron(np.array([1., 0.]), np.array([0., 1.])) + seed=9000 - schedule = self._2Q_constant_sched(total_samples) + pulse_sim = PulseSimulator(system_model=self._system_model_2Q(j)) + schedule = self._2Q_constant_sched(total_samples) qobj = assemble([schedule], - backend=self.backend_sim, + backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], @@ -549,10 +552,7 @@ def test_2Q_interaction(self): memory_slots=2, shots=1) - y0 = np.kron(np.array([1., 0.]), np.array([0., 1.])) - backend_options = {'seed' : 9000, 'initial_state': y0} - - result = self.backend_sim.run(qobj, system_model, backend_options).result() + result = pulse_sim.run(qobj, initial_state=y0, seed=seed).result() pulse_sim_yf = result.get_statevector() # exact analytic solution @@ -562,9 +562,8 @@ def test_2Q_interaction(self): # run with different initial state y0 = np.kron(np.array([1., 0.]), np.array([1., 0.])) - backend_options = {'seed' : 9000, 'initial_state': y0} - result = self.backend_sim.run(qobj, system_model, backend_options).result() + result = pulse_sim.run(qobj, initial_state=y0, seed=seed).result() pulse_sim_yf = result.get_statevector() # exact analytic solution @@ -572,7 +571,6 @@ def test_2Q_interaction(self): self.assertGreaterEqual(state_fidelity(pulse_sim_yf, yf), 1 - (10**-5)) - def test_subsystem_restriction(self): r"""Test behavior of subsystem_list subsystem restriction""" @@ -583,12 +581,16 @@ def test_subsystem_restriction(self): omega_d = 0. subsystem_list = [0, 2] - system_model = self._system_model_3Q(j, subsystem_list=subsystem_list) + y0 = np.kron(np.array([1., 0.]), np.array([0., 1.])) - schedule = self._3Q_constant_sched(total_samples, u_idx=0, subsystem_list=subsystem_list) + system_model = self._system_model_3Q(j, subsystem_list=subsystem_list) + pulse_sim = PulseSimulator(system_model=system_model) + schedule = self._3Q_constant_sched(total_samples, + u_idx=0, + subsystem_list=subsystem_list) qobj = assemble([schedule], - backend=self.backend_sim, + backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], @@ -596,10 +598,8 @@ def test_subsystem_restriction(self): memory_slots=2, shots=1) - y0 = np.kron(np.array([1., 0.]), np.array([0., 1.])) - backend_options = {'seed' : 9000, 'initial_state': y0} + result = pulse_sim.run(qobj, initial_state=y0).result() - result = self.backend_sim.run(qobj, system_model, backend_options).result() pulse_sim_yf = result.get_statevector() yf = expm(-1j * 0.5 * 2 * np.pi * np.kron(self.X, self.Z) / 4) @ y0 @@ -607,9 +607,8 @@ def test_subsystem_restriction(self): self.assertGreaterEqual(state_fidelity(pulse_sim_yf, yf), 1 - (10**-5)) y0 = np.kron(np.array([1., 0.]), np.array([1., 0.])) - backend_options = {'seed' : 9000, 'initial_state': y0} - result = self.backend_sim.run(qobj, system_model, backend_options).result() + result = pulse_sim.run(qobj, initial_state=y0).result() pulse_sim_yf = result.get_statevector() yf = expm(-1j * 0.5 * 2 * np.pi * np.kron(self.X, self.Z) / 4) @ y0 @@ -619,10 +618,13 @@ def test_subsystem_restriction(self): subsystem_list = [1, 2] system_model = self._system_model_3Q(j, subsystem_list=subsystem_list) - schedule = self._3Q_constant_sched(total_samples, u_idx=1, subsystem_list=subsystem_list) - + y0 = np.kron(np.array([1., 0.]), np.array([0., 1.])) + pulse_sim.set_options(system_model=system_model) + schedule = self._3Q_constant_sched(total_samples, + u_idx=1, + subsystem_list=subsystem_list) qobj = assemble([schedule], - backend=self.backend_sim, + backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], @@ -630,10 +632,7 @@ def test_subsystem_restriction(self): memory_slots=2, shots=1) - y0 = np.kron(np.array([1., 0.]), np.array([0., 1.])) - backend_options = {'seed' : 9000, 'initial_state': y0} - - result = self.backend_sim.run(qobj, system_model, backend_options).result() + result = pulse_sim.run(qobj, initial_state=y0).result() pulse_sim_yf = result.get_statevector() yf = expm(-1j * 0.5 * 2 * np.pi * np.kron(self.X, self.Z) / 4) @ y0 @@ -641,9 +640,9 @@ def test_subsystem_restriction(self): self.assertGreaterEqual(state_fidelity(pulse_sim_yf, yf), 1 - (10**-5)) y0 = np.kron(np.array([1., 0.]), np.array([1., 0.])) - backend_options = {'seed' : 9000, 'initial_state': y0} + pulse_sim.set_options(initial_state=y0) - result = self.backend_sim.run(qobj, system_model, backend_options).result() + result = pulse_sim.run(qobj).result() pulse_sim_yf = result.get_statevector() yf = expm(-1j * 0.5 * 2 * np.pi * np.kron(self.X, self.Z) / 4) @ y0 @@ -656,7 +655,12 @@ def test_simulation_without_variables(self): variables """ - ham_dict = {'h_str': ['np.pi*Z0', '0.02*np.pi*X0||D0'], 'qub': {'0': 2}} + ham_dict = { + 'h_str': ['np.pi*Z0', '0.02*np.pi*X0||D0'], + 'qub': { + '0': 2 + } + } ham_model = HamiltonianModel.from_dict(ham_dict) u_channel_lo = [] @@ -667,12 +671,15 @@ def test_simulation_without_variables(self): u_channel_lo=u_channel_lo, subsystem_list=subsystem_list, dt=dt) + pulse_sim = PulseSimulator(system_model=system_model, + initial_state=np.array([1., 0.]), + seed=9000) # set up schedule and qobj total_samples = 50 schedule = self._1Q_constant_sched(total_samples) qobj = assemble([schedule], - backend=self.backend_sim, + backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], @@ -680,12 +687,8 @@ def test_simulation_without_variables(self): memory_slots=2, shots=256) - # set backend backend_options - backend_options = {'seed' : 9000, 'initial_state' : np.array([1., 0.])} - # run simulation - result = self.backend_sim.run(qobj, system_model=system_model, - backend_options=backend_options).result() + result = pulse_sim.run(qobj).result() # test results counts = result.get_counts() @@ -703,15 +706,20 @@ def test_meas_level_1(self): # Require omega_a*time = pi to implement pi pulse (x gate) # num of samples gives time - r = 1. / (2 * total_samples) + r = 1. / (2 * total_samples) system_model = self._system_model_1Q(omega_0, r) amp = np.exp(-1j * np.pi / 2) schedule = self._1Q_constant_sched(total_samples, amp=amp) + y0=np.array([1.0, 0.0]) + pulse_sim = PulseSimulator(system_model=system_model, + initial_state=y0, + seed=9000) + qobj = assemble([schedule], - backend=self.backend_sim, + backend=pulse_sim, meas_level=1, meas_return='single', meas_map=[[0]], @@ -719,17 +727,16 @@ def test_meas_level_1(self): memory_slots=2, shots=shots) - # set backend backend_options - y0 = np.array([1.0, 0.0]) - backend_options = {'seed' : 9000, 'initial_state' : y0} - result = self.backend_sim.run(qobj, system_model, backend_options).result() + result = pulse_sim.run(qobj).result() pulse_sim_yf = result.get_statevector() samples = amp * np.ones((total_samples, 1)) - indep_yf = simulate_1q_model(y0, omega_0, r, np.array([omega_d]), samples, 1.) + indep_yf = simulate_1q_model(y0, omega_0, r, np.array([omega_d]), + samples, 1.) # test final state - self.assertGreaterEqual(state_fidelity(pulse_sim_yf, indep_yf), 1-10**-5) + self.assertGreaterEqual(state_fidelity(pulse_sim_yf, indep_yf), + 1 - 10**-5) # Verify that (about) half the IQ vals have abs val 1 and half have abs val 0 # (use prop for easier comparison) @@ -760,41 +767,47 @@ def test_gaussian_drive(self): # num of samples gives time r = np.pi / total_samples + # initial state and seed + y0 = np.array([1., 0.]) + seed = 9000 + # Test gaussian drive results for a few different sigma gauss_sigmas = [total_samples / 6, total_samples / 3, total_samples] - system_model = self._system_model_1Q(omega_0, r) + # set up pulse simulator + pulse_sim = PulseSimulator(system_model=self._system_model_1Q(omega_0, r)) for gauss_sigma in gauss_sigmas: with self.subTest(gauss_sigma=gauss_sigma): times = 1.0 * np.arange(total_samples) gaussian_samples = np.exp(-times**2 / 2 / gauss_sigma**2) - drive_pulse = SamplePulse(gaussian_samples, name='drive_pulse') + drive_pulse = Waveform(gaussian_samples, name='drive_pulse') # construct schedule schedule = Schedule() schedule |= Play(drive_pulse, DriveChannel(0)) - schedule |= Acquire(1, AcquireChannel(0), MemorySlot(0)) << schedule.duration + schedule |= Acquire(1, AcquireChannel(0), + MemorySlot(0)) << schedule.duration qobj = assemble([schedule], - backend=self.backend_sim, + backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], qubit_lo_freq=[omega_d], memory_slots=2, shots=1) - y0 = np.array([1., 0.]) - backend_options = {'seed' : 9000, 'initial_state' : y0} - result = self.backend_sim.run(qobj, system_model, backend_options).result() + result = pulse_sim.run(qobj, initial_state=y0, seed=seed).result() pulse_sim_yf = result.get_statevector() # run independent simulation - yf = simulate_1q_model(y0, omega_0, r, np.array([omega_d]), gaussian_samples, 1.) + yf = simulate_1q_model(y0, omega_0, r, np.array([omega_d]), + gaussian_samples, 1.) # Check fidelity of statevectors - self.assertGreaterEqual(state_fidelity(pulse_sim_yf, yf), 1-(10**-5)) + self.assertGreaterEqual(state_fidelity(pulse_sim_yf, yf), + 1 - (10**-5)) def test_2Q_exchange(self): r"""Test a more complicated 2q simulation""" @@ -805,18 +818,17 @@ def test_2Q_exchange(self): total_samples = 25 hamiltonian = {} - hamiltonian['h_str'] = ['2*np.pi*v0*0.5*Z0', - '2*np.pi*v1*0.5*Z1', - '2*np.pi*r*0.5*X0||D0', - '2*np.pi*r*0.5*X1||D1', - '2*np.pi*j*0.5*I0*I1', - '2*np.pi*j*0.5*X0*X1', - '2*np.pi*j*0.5*Y0*Y1', - '2*np.pi*j*0.5*Z0*Z1'] - hamiltonian['vars'] = {'v0': q_freqs[0], - 'v1': q_freqs[1], - 'r': r, - 'j': j} + hamiltonian['h_str'] = [ + '2*np.pi*v0*0.5*Z0', '2*np.pi*v1*0.5*Z1', '2*np.pi*r*0.5*X0||D0', + '2*np.pi*r*0.5*X1||D1', '2*np.pi*j*0.5*I0*I1', + '2*np.pi*j*0.5*X0*X1', '2*np.pi*j*0.5*Y0*Y1', '2*np.pi*j*0.5*Z0*Z1' + ] + hamiltonian['vars'] = { + 'v0': q_freqs[0], + 'v1': q_freqs[1], + 'r': r, + 'j': j + } hamiltonian['qub'] = {'0': 2, '1': 2} ham_model = HamiltonianModel.from_dict(hamiltonian) @@ -832,40 +844,43 @@ def test_2Q_exchange(self): # try some random schedule schedule = Schedule() - drive_pulse = SamplePulse(np.ones(total_samples)) + drive_pulse = Waveform(np.ones(total_samples)) schedule += Play(drive_pulse, DriveChannel(0)) schedule |= Play(drive_pulse, DriveChannel(1)) << 2 * total_samples - schedule |= Acquire(total_samples, - AcquireChannel(0), + schedule |= Acquire(total_samples, AcquireChannel(0), MemorySlot(0)) << 3 * total_samples - schedule |= Acquire(total_samples, - AcquireChannel(1), + schedule |= Acquire(total_samples, AcquireChannel(1), MemorySlot(1)) << 3 * total_samples + y0 = np.array([1., 0., 0., 0.]) + pulse_sim = PulseSimulator(system_model=system_model, + initial_state=y0, + seed=9000) + qobj = assemble([schedule], - backend=self.backend_sim, + backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], qubit_lo_freq=q_freqs, memory_slots=2, shots=1000) - y0 = np.array([1., 0., 0., 0.]) - backend_options = {'seed' : 9000, 'initial_state' : y0} - - result = self.backend_sim.run(qobj, system_model, backend_options).result() + result = pulse_sim.run(qobj).result() pulse_sim_yf = result.get_statevector() # set up and run independent simulation - d0_samps = np.concatenate((np.ones(total_samples), np.zeros(2 * total_samples))) - d1_samps = np.concatenate((np.zeros(2 * total_samples), np.ones(total_samples))) + d0_samps = np.concatenate( + (np.ones(total_samples), np.zeros(2 * total_samples))) + d1_samps = np.concatenate( + (np.zeros(2 * total_samples), np.ones(total_samples))) samples = np.array([d0_samps, d1_samps]).transpose() q_freqs = np.array(q_freqs) - yf = simulate_2q_exchange_model(y0, q_freqs, r, j, q_freqs, samples, 1.) + yf = simulate_2q_exchange_model(y0, q_freqs, r, j, q_freqs, samples, + 1.) # Check fidelity of statevectors - self.assertGreaterEqual(state_fidelity(pulse_sim_yf, yf), 1-(10**-5)) + self.assertGreaterEqual(state_fidelity(pulse_sim_yf, yf), 1 - (10**-5)) def test_delay_instruction(self): """Test for delay instruction.""" @@ -891,17 +906,21 @@ def test_delay_instruction(self): # so that the x rotation is transformed into a z rotation. # if delays are not handled correctly this process should fail sched = Schedule() - sched += Play(SamplePulse([0.5]), DriveChannel(1)) + sched += Play(Waveform([0.5]), DriveChannel(1)) sched += Delay(1, DriveChannel(1)) - sched += Play(SamplePulse([-0.5]), DriveChannel(1)) + sched += Play(Waveform([-0.5]), DriveChannel(1)) sched += Delay(1, DriveChannel(0)) - sched += Play(SamplePulse([1.]), DriveChannel(0)) + sched += Play(Waveform([1.]), DriveChannel(0)) sched |= Acquire(1, AcquireChannel(0), MemorySlot(0)) << sched.duration + # Result of schedule should be the unitary -1j*Z, so check rotation of an X eigenstate + pulse_sim = PulseSimulator(system_model=system_model, + initial_state=np.array([1., 1.]) / np.sqrt(2)) + qobj = assemble([sched], - backend=self.backend_sim, + backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], @@ -909,28 +928,25 @@ def test_delay_instruction(self): memory_slots=2, shots=1) - - # Result of schedule should be the unitary -1j*Z, so check rotation of an X eigenstate - backend_options = {'initial_state': np.array([1., 1.]) / np.sqrt(2)} - - results = self.backend_sim.run(qobj, system_model, backend_options).result() + results = pulse_sim.run(qobj).result() statevector = results.get_statevector() expected_vector = np.array([-1j, 1j]) / np.sqrt(2) - self.assertGreaterEqual(state_fidelity(statevector, expected_vector), 1 - (10**-5)) + self.assertGreaterEqual(state_fidelity(statevector, expected_vector), + 1 - (10**-5)) # verify validity of simulation when no delays included sched = Schedule() - sched += Play(SamplePulse([0.5]), DriveChannel(1)) - sched += Play(SamplePulse([-0.5]), DriveChannel(1)) + sched += Play(Waveform([0.5]), DriveChannel(1)) + sched += Play(Waveform([-0.5]), DriveChannel(1)) - sched += Play(SamplePulse([1.]), DriveChannel(0)) + sched += Play(Waveform([1.]), DriveChannel(0)) sched |= Acquire(1, AcquireChannel(0), MemorySlot(0)) << sched.duration qobj = assemble([sched], - backend=self.backend_sim, + backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], @@ -938,15 +954,15 @@ def test_delay_instruction(self): memory_slots=2, shots=1) - backend_options = {'initial_state': np.array([1., 1.]) / np.sqrt(2)} - - results = self.backend_sim.run(qobj, system_model, backend_options).result() + results = pulse_sim.run(qobj).result() statevector = results.get_statevector() - U = expm(1j * np.pi * self.Y /4) @ expm(-1j * np.pi * (self.Y / 4 + self.X / 2)) + U = expm(1j * np.pi * self.Y / 4) @ expm(-1j * np.pi * + (self.Y / 4 + self.X / 2)) expected_vector = U @ np.array([1., 1.]) / np.sqrt(2) - self.assertGreaterEqual(state_fidelity(statevector, expected_vector), 1 - (10**-5)) + self.assertGreaterEqual(state_fidelity(statevector, expected_vector), + 1 - (10**-5)) def test_shift_phase(self): """Test ShiftPhase command.""" @@ -960,53 +976,54 @@ def test_shift_phase(self): # Also do it in multiple phase shifts to test accumulation sched = Schedule() amp1 = 0.12 - sched += Play(SamplePulse([amp1]), DriveChannel(0)) + sched += Play(Waveform([amp1]), DriveChannel(0)) phi1 = 0.12374 * np.pi sched += ShiftPhase(phi1, DriveChannel(0)) amp2 = 0.492 - sched += Play(SamplePulse([amp2]), DriveChannel(0)) + sched += Play(Waveform([amp2]), DriveChannel(0)) phi2 = 0.5839 * np.pi sched += ShiftPhase(phi2, DriveChannel(0)) amp3 = 0.12 + 0.21 * 1j - sched += Play(SamplePulse([amp3]), DriveChannel(0)) + sched += Play(Waveform([amp3]), DriveChannel(0)) sched |= Acquire(1, AcquireChannel(0), MemorySlot(0)) << sched.duration + y0 = np.array([1., 0]) + + pulse_sim = PulseSimulator(system_model=system_model, + initial_state=y0) qobj = assemble([sched], - backend=self.backend_sim, + backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], qubit_lo_freq=[omega_0], memory_slots=2, shots=1) - - y0 = np.array([1., 0]) - backend_options = {'initial_state': y0} - - results = self.backend_sim.run(qobj, system_model, backend_options).result() + results = pulse_sim.run(qobj).result() pulse_sim_yf = results.get_statevector() #run independent simulation - samples = np.array([[amp1], - [amp2 * np.exp(1j * phi1)], + samples = np.array([[amp1], [amp2 * np.exp(1j * phi1)], [amp3 * np.exp(1j * (phi1 + phi2))]]) - indep_yf = simulate_1q_model(y0, omega_0, r, np.array([omega_0]), samples, 1.) + indep_yf = simulate_1q_model(y0, omega_0, r, np.array([omega_0]), + samples, 1.) - self.assertGreaterEqual(state_fidelity(pulse_sim_yf, indep_yf), 1 - (10**-5)) + self.assertGreaterEqual(state_fidelity(pulse_sim_yf, indep_yf), + 1 - (10**-5)) # run another schedule with only a single shift phase to verify sched = Schedule() amp1 = 0.12 - sched += Play(SamplePulse([amp1]), DriveChannel(0)) + sched += Play(Waveform([amp1]), DriveChannel(0)) phi1 = 0.12374 * np.pi sched += ShiftPhase(phi1, DriveChannel(0)) amp2 = 0.492 - sched += Play(SamplePulse([amp2]), DriveChannel(0)) + sched += Play(Waveform([amp2]), DriveChannel(0)) sched |= Acquire(1, AcquireChannel(0), MemorySlot(0)) << sched.duration qobj = assemble([sched], - backend=self.backend_sim, + backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], @@ -1014,17 +1031,16 @@ def test_shift_phase(self): memory_slots=2, shots=1) - y0 = np.array([1., 0]) - backend_options = {'initial_state': y0} - - results = self.backend_sim.run(qobj, system_model, backend_options).result() + results = pulse_sim.run(qobj).result() pulse_sim_yf = results.get_statevector() #run independent simulation samples = np.array([[amp1], [amp2 * np.exp(1j * phi1)]]) - indep_yf = simulate_1q_model(y0, omega_0, r, np.array([omega_0]), samples, 1.) + indep_yf = simulate_1q_model(y0, omega_0, r, np.array([omega_0]), + samples, 1.) - self.assertGreaterEqual(state_fidelity(pulse_sim_yf, indep_yf), 1 - (10**-5)) + self.assertGreaterEqual(state_fidelity(pulse_sim_yf, indep_yf), + 1 - (10**-5)) def test_set_phase(self): """Test SetPhase command. Similar to the ShiftPhase test but includes a mixing of @@ -1038,45 +1054,45 @@ def test_set_phase(self): # intermix shift and set phase instructions to verify absolute v.s. relative changes sched = Schedule() amp1 = 0.12 - sched += Play(SamplePulse([amp1]), DriveChannel(0)) + sched += Play(Waveform([amp1]), DriveChannel(0)) phi1 = 0.12374 * np.pi sched += ShiftPhase(phi1, DriveChannel(0)) amp2 = 0.492 - sched += Play(SamplePulse([amp2]), DriveChannel(0)) + sched += Play(Waveform([amp2]), DriveChannel(0)) phi2 = 0.5839 * np.pi sched += SetPhase(phi2, DriveChannel(0)) amp3 = 0.12 + 0.21 * 1j - sched += Play(SamplePulse([amp3]), DriveChannel(0)) + sched += Play(Waveform([amp3]), DriveChannel(0)) phi3 = 0.1 * np.pi sched += ShiftPhase(phi3, DriveChannel(0)) amp4 = 0.2 + 0.3 * 1j - sched += Play(SamplePulse([amp4]), DriveChannel(0)) + sched += Play(Waveform([amp4]), DriveChannel(0)) sched |= Acquire(1, AcquireChannel(0), MemorySlot(0)) << sched.duration + y0 = np.array([1., 0.]) + pulse_sim = PulseSimulator(system_model=system_model, + initial_state=y0) qobj = assemble([sched], - backend=self.backend_sim, + backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], qubit_lo_freq=[omega_0], memory_slots=2, shots=1) - - y0 = np.array([1., 0.]) - backend_options = {'initial_state': y0} - - results = self.backend_sim.run(qobj, system_model, backend_options).result() + results = pulse_sim.run(qobj).result() pulse_sim_yf = results.get_statevector() #run independent simulation - samples = np.array([[amp1], - [amp2 * np.exp(1j * phi1)], + samples = np.array([[amp1], [amp2 * np.exp(1j * phi1)], [amp3 * np.exp(1j * phi2)], [amp4 * np.exp(1j * (phi2 + phi3))]]) - indep_yf = simulate_1q_model(y0, omega_0, r, np.array([omega_0]), samples, 1.) + indep_yf = simulate_1q_model(y0, omega_0, r, np.array([omega_0]), + samples, 1.) - self.assertGreaterEqual(state_fidelity(pulse_sim_yf, indep_yf), 1 - (10**-5)) + self.assertGreaterEqual(state_fidelity(pulse_sim_yf, indep_yf), + 1 - (10**-5)) def test_set_phase_rwa(self): """Test SetPhase command using an RWA approximate solution.""" @@ -1087,27 +1103,27 @@ def test_set_phase_rwa(self): sched = Schedule() sched += SetPhase(np.pi / 2, DriveChannel(0)) - sched += Play(SamplePulse(np.ones(100)), DriveChannel(0)) + sched += Play(Waveform(np.ones(100)), DriveChannel(0)) sched |= Acquire(1, AcquireChannel(0), MemorySlot(0)) << sched.duration + y0 = np.array([1., 1.]) / np.sqrt(2) + pulse_sim = PulseSimulator(system_model=system_model, + initial_state=y0) qobj = assemble([sched], - backend=self.backend_sim, + backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], qubit_lo_freq=[omega_0], memory_slots=2, shots=1) - - y0 = np.array([1., 1.]) / np.sqrt(2) - backend_options = {'initial_state': y0} - - results = self.backend_sim.run(qobj, system_model, backend_options).result() + results = pulse_sim.run(qobj).result() pulse_sim_yf = results.get_statevector() #run independent simulation - phases = np.exp((-1j * 2 * np.pi * omega_0 * np.array([1, -1]) / 2) * 100) + phases = np.exp( + (-1j * 2 * np.pi * omega_0 * np.array([1, -1]) / 2) * 100) approx_yf = phases * (expm(-1j * (np.pi / 2) * self.Y) @ y0) self.assertGreaterEqual(state_fidelity(pulse_sim_yf, approx_yf), 0.99) @@ -1124,7 +1140,9 @@ def _system_model_1Q(self, omega_0, r): """ hamiltonian = {} - hamiltonian['h_str'] = ['2*np.pi*omega0*0.5*Z0', '2*np.pi*r*0.5*X0||D0'] + hamiltonian['h_str'] = [ + '2*np.pi*omega0*0.5*Z0', '2*np.pi*r*0.5*X0||D0' + ] hamiltonian['vars'] = {'omega0': omega_0, 'r': r} hamiltonian['qub'] = {'0': 2} ham_model = HamiltonianModel.from_dict(hamiltonian) @@ -1150,10 +1168,11 @@ def _1Q_constant_sched(self, total_samples, amp=1.): """ # set up constant pulse for doing a pi pulse - drive_pulse = SamplePulse(amp * np.ones(total_samples)) + drive_pulse = Waveform(amp * np.ones(total_samples)) schedule = Schedule() schedule |= Play(drive_pulse, DriveChannel(0)) - schedule |= Acquire(total_samples, AcquireChannel(0), MemorySlot(0)) << schedule.duration + schedule |= Acquire(total_samples, AcquireChannel(0), + MemorySlot(0)) << schedule.duration return schedule @@ -1169,13 +1188,15 @@ def _system_model_2Q(self, j): """ hamiltonian = {} - hamiltonian['h_str'] = ['a*X0||D0', 'a*X0||D1', '2*np.pi*j*0.25*(Z0*X1)||U0'] + hamiltonian['h_str'] = [ + 'a*X0||D0', 'a*X0||D1', '2*np.pi*j*0.25*(Z0*X1)||U0' + ] hamiltonian['vars'] = {'a': 0, 'j': j} hamiltonian['qub'] = {'0': 2, '1': 2} ham_model = HamiltonianModel.from_dict(hamiltonian) # set the U0 to have frequency of drive channel 0 - u_channel_lo = [[UchannelLO(0, 1.0+0.0j)]] + u_channel_lo = [[UchannelLO(0, 1.0 + 0.0j)]] subsystem_list = [0, 1] dt = 1. @@ -1184,7 +1205,6 @@ def _system_model_2Q(self, j): subsystem_list=subsystem_list, dt=dt) - def _2Q_constant_sched(self, total_samples, amp=1., u_idx=0): """Creates a runnable schedule with a single pulse on a U channel for two qubits. @@ -1198,15 +1218,16 @@ def _2Q_constant_sched(self, total_samples, amp=1., u_idx=0): """ # set up constant pulse for doing a pi pulse - drive_pulse = SamplePulse(amp * np.ones(total_samples)) + drive_pulse = Waveform(amp * np.ones(total_samples)) schedule = Schedule() schedule |= Play(drive_pulse, ControlChannel(u_idx)) - schedule |= Acquire(total_samples, AcquireChannel(0), MemorySlot(0)) << total_samples - schedule |= Acquire(total_samples, AcquireChannel(1), MemorySlot(1)) << total_samples + schedule |= Acquire(total_samples, AcquireChannel(0), + MemorySlot(0)) << total_samples + schedule |= Acquire(total_samples, AcquireChannel(1), + MemorySlot(1)) << total_samples return schedule - def _system_model_3Q(self, j, subsystem_list=[0, 2]): """Constructs a model for a 3 qubit system, with the goal that the restriction to [0, 2] and to qubits [1, 2] is the same as in _system_model_2Q @@ -1220,13 +1241,17 @@ def _system_model_3Q(self, j, subsystem_list=[0, 2]): """ hamiltonian = {} - hamiltonian['h_str'] = ['2*np.pi*j*0.25*(Z0*X2)||U0', '2*np.pi*j*0.25*(Z1*X2)||U1'] + hamiltonian['h_str'] = [ + '2*np.pi*j*0.25*(Z0*X2)||U0', '2*np.pi*j*0.25*(Z1*X2)||U1' + ] hamiltonian['vars'] = {'j': j} hamiltonian['qub'] = {'0': 2, '1': 2, '2': 2} - ham_model = HamiltonianModel.from_dict(hamiltonian, subsystem_list=subsystem_list) + ham_model = HamiltonianModel.from_dict(hamiltonian, + subsystem_list=subsystem_list) # set the U0 to have frequency of drive channel 0 - u_channel_lo = [[UchannelLO(0, 1.0 + 0.0j)], [UchannelLO(0, 1.0 + 0.0j)]] + u_channel_lo = [[UchannelLO(0, 1.0 + 0.0j)], + [UchannelLO(0, 1.0 + 0.0j)]] dt = 1. return PulseSystemModel(hamiltonian=ham_model, @@ -1234,7 +1259,11 @@ def _system_model_3Q(self, j, subsystem_list=[0, 2]): subsystem_list=subsystem_list, dt=dt) - def _3Q_constant_sched(self, total_samples, amp=1., u_idx=0, subsystem_list=[0, 2]): + def _3Q_constant_sched(self, + total_samples, + amp=1., + u_idx=0, + subsystem_list=[0, 2]): """Creates a runnable schedule for the 3Q system after the system is restricted to 2 qubits. @@ -1249,12 +1278,11 @@ def _3Q_constant_sched(self, total_samples, amp=1., u_idx=0, subsystem_list=[0, """ # set up constant pulse for doing a pi pulse - drive_pulse = SamplePulse(amp * np.ones(total_samples)) + drive_pulse = Waveform(amp * np.ones(total_samples)) schedule = Schedule() schedule |= Play(drive_pulse, ControlChannel(u_idx)) for idx in subsystem_list: - schedule |= Acquire(total_samples, - AcquireChannel(idx), + schedule |= Acquire(total_samples, AcquireChannel(idx), MemorySlot(idx)) << total_samples return schedule @@ -1271,10 +1299,10 @@ def _system_model_3d_oscillator(self, freq, anharm, r): PulseSystemModel: model for oscillator system """ hamiltonian = {} - hamiltonian['h_str'] = ['np.pi*(2*v-alpha)*O0', - 'np.pi*alpha*O0*O0', - '2*np.pi*r*X0||D0'] - hamiltonian['vars'] = {'v' : freq, 'alpha': anharm, 'r': r} + hamiltonian['h_str'] = [ + 'np.pi*(2*v-alpha)*O0', 'np.pi*alpha*O0*O0', '2*np.pi*r*X0||D0' + ] + hamiltonian['vars'] = {'v': freq, 'alpha': anharm, 'r': r} hamiltonian['qub'] = {'0': 3} ham_model = HamiltonianModel.from_dict(hamiltonian) @@ -1287,5 +1315,6 @@ def _system_model_3d_oscillator(self, freq, anharm, r): subsystem_list=subsystem_list, dt=dt) + if __name__ == '__main__': unittest.main() diff --git a/test/terra/backends/test_qasm_simulator_extended_stabilizer.py b/test/terra/backends/test_qasm_simulator_extended_stabilizer.py index c9e239a2f4..d21f8e03cb 100644 --- a/test/terra/backends/test_qasm_simulator_extended_stabilizer.py +++ b/test/terra/backends/test_qasm_simulator_extended_stabilizer.py @@ -55,7 +55,7 @@ def test_reset_deterministic(self): circuits = ref_reset.reset_circuits_deterministic(final_measure=True) qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_reset.reset_counts_deterministic(shots) - job = QasmSimulator().run(qobj, backend_options=self.BACKEND_OPTS) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -69,7 +69,7 @@ def test_reset_nondeterministic(self): final_measure=True) qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_reset.reset_counts_nondeterministic(shots) - job = QasmSimulator().run(qobj, backend_options=self.BACKEND_OPTS_SAMPLING) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS_SAMPLING) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -84,7 +84,7 @@ def test_measure_deterministic_with_sampling(self): allow_sampling=True) qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_measure.measure_counts_deterministic(shots) - job = QasmSimulator().run(qobj, backend_options=self.BACKEND_OPTS_SAMPLING) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS_SAMPLING) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -96,7 +96,7 @@ def test_measure_deterministic_without_sampling(self): allow_sampling=False) qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_measure.measure_counts_deterministic(shots) - job = QasmSimulator().run(qobj, backend_options=self.BACKEND_OPTS) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -108,7 +108,7 @@ def test_measure_nondeterministic_with_sampling(self): allow_sampling=True) qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_measure.measure_counts_nondeterministic(shots) - job = QasmSimulator().run(qobj, backend_options=self.BACKEND_OPTS_SAMPLING) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS_SAMPLING) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -120,7 +120,7 @@ def test_measure_nondeterministic_without_sampling(self): allow_sampling=False) qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_measure.measure_counts_nondeterministic(shots) - job = QasmSimulator().run(qobj, backend_options=self.BACKEND_OPTS) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -135,7 +135,7 @@ def test_measure_deterministic_multi_qubit_with_sampling(self): allow_sampling=True) targets = ref_measure.multiqubit_measure_counts_deterministic(shots) qobj = assemble(circuits, QasmSimulator(), shots=shots) - job = QasmSimulator().run(qobj, backend_options=self.BACKEND_OPTS_SAMPLING) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS_SAMPLING) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -147,7 +147,7 @@ def test_measure_deterministic_multi_qubit_without_sampling(self): allow_sampling=False) targets = ref_measure.multiqubit_measure_counts_deterministic(shots) qobj = assemble(circuits, QasmSimulator(), shots=shots) - job = QasmSimulator().run(qobj, backend_options=self.BACKEND_OPTS) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -159,7 +159,7 @@ def test_measure_nondeterministic_multi_qubit_with_sampling(self): allow_sampling=True) targets = ref_measure.multiqubit_measure_counts_nondeterministic(shots) qobj = assemble(circuits, QasmSimulator(), shots=shots) - job = QasmSimulator().run(qobj, backend_options=self.BACKEND_OPTS_SAMPLING) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS_SAMPLING) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -171,7 +171,7 @@ def test_measure_nondeterministic_multi_qubit_without_sampling(self): allow_sampling=False) targets = ref_measure.multiqubit_measure_counts_nondeterministic(shots) qobj = assemble(circuits, QasmSimulator(), shots=shots) - job = QasmSimulator().run(qobj, backend_options=self.BACKEND_OPTS) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -186,7 +186,7 @@ def test_conditional_1bit(self): final_measure=True) qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_conditionals.conditional_counts_1bit(shots) - job = QasmSimulator().run(qobj, backend_options=self.BACKEND_OPTS_SAMPLING) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS_SAMPLING) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -198,7 +198,7 @@ def test_conditional_2bit(self): final_measure=True) qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_conditionals.conditional_counts_2bit(shots) - job = QasmSimulator().run(qobj, backend_options=self.BACKEND_OPTS_SAMPLING) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS_SAMPLING) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -213,7 +213,7 @@ def test_h_gate_deterministic_default_basis_gates(self): final_measure=True) qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_1q_clifford.h_gate_counts_deterministic(shots) - job = QasmSimulator().run(qobj, backend_options=self.BACKEND_OPTS_SAMPLING) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS_SAMPLING) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -225,7 +225,7 @@ def test_h_gate_nondeterministic_default_basis_gates(self): final_measure=True) qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_1q_clifford.h_gate_counts_nondeterministic(shots) - job = QasmSimulator().run(qobj, backend_options=self.BACKEND_OPTS_SAMPLING) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS_SAMPLING) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -240,7 +240,7 @@ def test_x_gate_deterministic_default_basis_gates(self): final_measure=True) qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_1q_clifford.x_gate_counts_deterministic(shots) - job = QasmSimulator().run(qobj, backend_options=self.BACKEND_OPTS_SAMPLING) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS_SAMPLING) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -255,7 +255,7 @@ def test_z_gate_deterministic_default_basis_gates(self): final_measure=True) qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_1q_clifford.z_gate_counts_deterministic(shots) - job = QasmSimulator().run(qobj, backend_options=self.BACKEND_OPTS_SAMPLING) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS_SAMPLING) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -270,7 +270,7 @@ def test_y_gate_deterministic_default_basis_gates(self): final_measure=True) qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_1q_clifford.y_gate_counts_deterministic(shots) - job = QasmSimulator().run(qobj, backend_options=self.BACKEND_OPTS_SAMPLING) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS_SAMPLING) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -285,7 +285,7 @@ def test_s_gate_deterministic_default_basis_gates(self): final_measure=True) qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_1q_clifford.s_gate_counts_deterministic(shots) - job = QasmSimulator().run(qobj, backend_options=self.BACKEND_OPTS_SAMPLING) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS_SAMPLING) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -297,7 +297,7 @@ def test_s_gate_nondeterministic_default_basis_gates(self): final_measure=True) qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_1q_clifford.s_gate_counts_nondeterministic(shots) - job = QasmSimulator().run(qobj, backend_options=self.BACKEND_OPTS_SAMPLING) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS_SAMPLING) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -312,7 +312,7 @@ def test_sdg_gate_deterministic_default_basis_gates(self): final_measure=True) qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_1q_clifford.sdg_gate_counts_deterministic(shots) - job = QasmSimulator().run(qobj, backend_options=self.BACKEND_OPTS_SAMPLING) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS_SAMPLING) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -324,7 +324,7 @@ def test_sdg_gate_nondeterministic_default_basis_gates(self): final_measure=True) qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_1q_clifford.sdg_gate_counts_nondeterministic(shots) - job = QasmSimulator().run(qobj, backend_options=self.BACKEND_OPTS_SAMPLING) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS_SAMPLING) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -339,7 +339,7 @@ def test_cx_gate_deterministic_default_basis_gates(self): final_measure=True) qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_2q_clifford.cx_gate_counts_deterministic(shots) - job = QasmSimulator().run(qobj, backend_options=self.BACKEND_OPTS_SAMPLING) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS_SAMPLING) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -351,7 +351,7 @@ def test_cx_gate_nondeterministic_default_basis_gates(self): final_measure=True) qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_2q_clifford.cx_gate_counts_nondeterministic(shots) - job = QasmSimulator().run(qobj, backend_options=self.BACKEND_OPTS_SAMPLING) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS_SAMPLING) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -366,7 +366,7 @@ def test_cz_gate_deterministic_default_basis_gates(self): final_measure=True) qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_2q_clifford.cz_gate_counts_deterministic(shots) - job = QasmSimulator().run(qobj, backend_options=self.BACKEND_OPTS_SAMPLING) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS_SAMPLING) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -378,7 +378,7 @@ def test_cz_gate_nondeterministic_default_basis_gates(self): final_measure=True) qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_2q_clifford.cz_gate_counts_nondeterministic(shots) - job = QasmSimulator().run(qobj, backend_options=self.BACKEND_OPTS_SAMPLING) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS_SAMPLING) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -393,7 +393,7 @@ def test_swap_gate_deterministic_default_basis_gates(self): final_measure=True) qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_2q_clifford.swap_gate_counts_deterministic(shots) - job = QasmSimulator().run(qobj, backend_options=self.BACKEND_OPTS_SAMPLING) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS_SAMPLING) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0) @@ -405,7 +405,7 @@ def test_swap_gate_nondeterministic_default_basis_gates(self): final_measure=True) qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_2q_clifford.swap_gate_counts_nondeterministic(shots) - job = QasmSimulator().run(qobj, backend_options=self.BACKEND_OPTS_SAMPLING) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS_SAMPLING) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -420,7 +420,7 @@ def test_t_gate_deterministic_default_basis_gates(self): final_measure=True) qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_non_clifford.t_gate_counts_deterministic(shots) - job = QasmSimulator().run(qobj, backend_options=self.BACKEND_OPTS) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.1 * shots) @@ -434,7 +434,7 @@ def test_t_gate_nondeterministic_default_basis_gates(self): targets = ref_non_clifford.t_gate_counts_nondeterministic(shots) opts = self.BACKEND_OPTS.copy() opts["extended_stabilizer_mixing_time"] = 50 - job = QasmSimulator().run(qobj, backend_options=opts) + job = QasmSimulator().run(qobj, **opts) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.1 * shots) @@ -449,7 +449,7 @@ def test_tdg_gate_deterministic_default_basis_gates(self): final_measure=True) qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_non_clifford.tdg_gate_counts_deterministic(shots) - job = QasmSimulator().run(qobj, backend_options=self.BACKEND_OPTS) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) @@ -464,7 +464,7 @@ def test_tdg_gate_nondeterministic_default_basis_gates(self): targets = ref_non_clifford.tdg_gate_counts_nondeterministic(shots) opts = self.BACKEND_OPTS.copy() opts["extended_stabilizer_mixing_time"] = 50 - job = QasmSimulator().run(qobj, backend_options=opts) + job = QasmSimulator().run(qobj, **opts) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.1 * shots) @@ -481,7 +481,7 @@ def test_ccx_gate_deterministic_default_basis_gates(self): targets = ref_non_clifford.ccx_gate_counts_deterministic(shots) opts = self.BACKEND_OPTS.copy() opts["extended_stabilizer_mixing_time"] = 100 - job = QasmSimulator().run(qobj, backend_options=opts) + job = QasmSimulator().run(qobj, **opts) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) @@ -495,7 +495,7 @@ def test_ccx_gate_nondeterministic_default_basis_gates(self): targets = ref_non_clifford.ccx_gate_counts_nondeterministic(shots) opts = self.BACKEND_OPTS.copy() opts["extended_stabilizer_mixing_time"] = 100 - job = QasmSimulator().run(qobj, backend_options=opts) + job = QasmSimulator().run(qobj, **opts) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.10 * shots) @@ -512,7 +512,7 @@ def test_grovers_default_basis_gates(self): targets = ref_algorithms.grovers_counts(shots) opts = self.BACKEND_OPTS.copy() opts["extended_stabilizer_mixing_time"] = 100 - job = QasmSimulator().run(qobj, backend_options=opts) + job = QasmSimulator().run(qobj, **opts) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.1 * shots) @@ -523,7 +523,7 @@ def test_teleport_default_basis_gates(self): circuits = ref_algorithms.teleport_circuit() qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_algorithms.teleport_counts(shots) - job = QasmSimulator().run(qobj, backend_options=self.BACKEND_OPTS) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) diff --git a/test/terra/backends/unitary_simulator/unitary_basics.py b/test/terra/backends/unitary_simulator/unitary_basics.py index 187e84bc7c..1ec3109af8 100644 --- a/test/terra/backends/unitary_simulator/unitary_basics.py +++ b/test/terra/backends/unitary_simulator/unitary_basics.py @@ -42,7 +42,7 @@ def test_h_gate_deterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -56,7 +56,7 @@ def test_h_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -70,7 +70,7 @@ def test_h_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -83,7 +83,7 @@ def test_h_gate_nondeterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -97,7 +97,7 @@ def test_h_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -111,7 +111,7 @@ def test_h_gate_nondeterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -127,7 +127,7 @@ def test_x_gate_deterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -141,7 +141,7 @@ def test_x_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -155,7 +155,7 @@ def test_x_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -171,7 +171,7 @@ def test_z_gate_deterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -185,7 +185,7 @@ def test_z_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -199,7 +199,7 @@ def test_z_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -215,7 +215,7 @@ def test_y_gate_deterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -229,7 +229,7 @@ def test_y_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -243,7 +243,7 @@ def test_y_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -259,7 +259,7 @@ def test_s_gate_deterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -273,7 +273,7 @@ def test_s_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -287,7 +287,7 @@ def test_s_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -300,7 +300,7 @@ def test_s_gate_nondeterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -314,7 +314,7 @@ def test_s_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -328,7 +328,7 @@ def test_s_gate_nondeterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -344,7 +344,7 @@ def test_sdg_gate_deterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -358,7 +358,7 @@ def test_sdg_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -372,7 +372,7 @@ def test_sdg_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -385,7 +385,7 @@ def test_sdg_gate_nondeterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -399,7 +399,7 @@ def test_sdg_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -413,7 +413,7 @@ def test_sdg_gate_nondeterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -429,7 +429,7 @@ def test_cx_gate_deterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -443,7 +443,7 @@ def test_cx_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -457,7 +457,7 @@ def test_cx_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -470,7 +470,7 @@ def test_cx_gate_nondeterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -484,7 +484,7 @@ def test_cx_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -498,7 +498,7 @@ def test_cx_gate_nondeterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -514,7 +514,7 @@ def test_cz_gate_deterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -528,7 +528,7 @@ def test_cz_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -542,7 +542,7 @@ def test_cz_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -555,7 +555,7 @@ def test_cz_gate_nondeterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -569,7 +569,7 @@ def test_cz_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -583,7 +583,7 @@ def test_cz_gate_nondeterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -600,7 +600,7 @@ def test_cu1_gate_nondeterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -614,7 +614,7 @@ def test_cu1_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -628,7 +628,7 @@ def test_cu1_gate_nondeterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -644,7 +644,7 @@ def test_cu3_gate_deterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -658,7 +658,7 @@ def test_cu3_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -672,7 +672,7 @@ def test_cu3_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -688,7 +688,7 @@ def test_cswap_gate_deterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary( @@ -705,7 +705,7 @@ def test_swap_gate_deterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -719,7 +719,7 @@ def test_swap_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -733,7 +733,7 @@ def test_swap_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -746,7 +746,7 @@ def test_swap_gate_nondeterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -760,7 +760,7 @@ def test_swap_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -774,7 +774,7 @@ def test_swap_gate_nondeterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -790,7 +790,7 @@ def test_t_gate_deterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -804,7 +804,7 @@ def test_t_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -818,7 +818,7 @@ def test_t_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -831,7 +831,7 @@ def test_t_gate_nondeterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -845,7 +845,7 @@ def test_t_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -859,7 +859,7 @@ def test_t_gate_nondeterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -875,7 +875,7 @@ def test_tdg_gate_deterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -889,7 +889,7 @@ def test_tdg_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -903,7 +903,7 @@ def test_tdg_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -916,7 +916,7 @@ def test_tdg_gate_nondeterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -930,7 +930,7 @@ def test_tdg_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -944,7 +944,7 @@ def test_tdg_gate_nondeterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -960,7 +960,7 @@ def test_ccx_gate_deterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -974,7 +974,7 @@ def test_ccx_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -988,7 +988,7 @@ def test_ccx_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -1001,7 +1001,7 @@ def test_ccx_gate_nondeterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -1015,7 +1015,7 @@ def test_ccx_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -1029,7 +1029,7 @@ def test_ccx_gate_nondeterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -1045,7 +1045,7 @@ def test_unitary_gate(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -1058,7 +1058,7 @@ def test_diagonal_gate(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -1072,7 +1072,7 @@ def test_cswap_gate_deterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -1086,7 +1086,7 @@ def test_cswap_gate_deterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -1099,7 +1099,7 @@ def test_cswap_gate_nondeterministic_default_basis_gates(self): job = execute(circuits, self.SIMULATOR, shots=1, - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -1113,7 +1113,7 @@ def test_cswap_gate_nondeterministic_minimal_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -1127,7 +1127,7 @@ def test_cswap_gate_nondeterministic_waltz_basis_gates(self): self.SIMULATOR, shots=1, basis_gates=['u1', 'u2', 'u3', 'cx'], - backend_options=self.BACKEND_OPTS) + **self.BACKEND_OPTS) result = job.result() self.assertSuccess(result) self.compare_unitary(result, circuits, targets) @@ -1144,7 +1144,7 @@ def test_qobj_global_phase(self): targets = ref_1q_clifford.h_gate_unitary_nondeterministic() qobj = assemble(transpile(circuits, self.SIMULATOR), - shots=1, backend_options=self.BACKEND_OPTS) + shots=1, **self.BACKEND_OPTS) # Set global phases for i, _ in enumerate(circuits): global_phase = (-1) ** i * (pi / 4) diff --git a/test/terra/backends/unitary_simulator/unitary_fusion.py b/test/terra/backends/unitary_simulator/unitary_fusion.py index dbee2645b3..5b4f4af319 100644 --- a/test/terra/backends/unitary_simulator/unitary_fusion.py +++ b/test/terra/backends/unitary_simulator/unitary_fusion.py @@ -50,7 +50,7 @@ def test_fusion_theshold(self): circuit = transpile(circuit, self.SIMULATOR) qobj = assemble([circuit], shots=1) result = self.SIMULATOR.run( - qobj, backend_options=backend_options).result() + qobj, **backend_options).result() meta = self.fusion_metadata(result) self.assertSuccess(result) @@ -61,7 +61,7 @@ def test_fusion_theshold(self): circuit = transpile(circuit, self.SIMULATOR) qobj = assemble([circuit], shots=1) result = self.SIMULATOR.run( - qobj, backend_options=backend_options).result() + qobj, **backend_options).result() meta = self.fusion_metadata(result) self.assertSuccess(result) @@ -72,7 +72,7 @@ def test_fusion_theshold(self): circuit = transpile(circuit, self.SIMULATOR) qobj = assemble([circuit], shots=1) result = self.SIMULATOR.run( - qobj, backend_options=backend_options).result() + qobj, **backend_options).result() meta = self.fusion_metadata(result) self.assertSuccess(result) @@ -88,7 +88,7 @@ def test_fusion_disable(self): with self.subTest(msg='test fusion enable'): backend_options = self.fusion_options(enabled=True, threshold=1) result = self.SIMULATOR.run( - qobj, backend_options=backend_options).result() + qobj, **backend_options).result() meta = self.fusion_metadata(result) self.assertSuccess(result) @@ -97,7 +97,7 @@ def test_fusion_disable(self): with self.subTest(msg='test fusion disable'): backend_options = self.fusion_options(enabled=False, threshold=1) result = self.SIMULATOR.run( - qobj, backend_options=backend_options).result() + qobj, **backend_options).result() meta = self.fusion_metadata(result) self.assertSuccess(result) @@ -112,12 +112,12 @@ def test_fusion_output(self): options_disabled = self.fusion_options(enabled=False, threshold=1) result_disabled = self.SIMULATOR.run( - qobj, backend_options=options_disabled).result() + qobj, **options_disabled).result() self.assertSuccess(result_disabled) options_enabled = self.fusion_options(enabled=True, threshold=1) result_enabled = self.SIMULATOR.run( - qobj, backend_options=options_enabled).result() + qobj, **options_enabled).result() self.assertSuccess(result_enabled) unitary_no_fusion = Operator(result_disabled.get_unitary(0)) diff --git a/test/terra/backends/unitary_simulator/unitary_snapshot.py b/test/terra/backends/unitary_simulator/unitary_snapshot.py index 1f43c3dfc1..9f7af08186 100644 --- a/test/terra/backends/unitary_simulator/unitary_snapshot.py +++ b/test/terra/backends/unitary_simulator/unitary_snapshot.py @@ -28,17 +28,19 @@ class UnitarySnapshotTests: def test_unitary_snap(self): """Test Unitary matrix snaps on a random circuit""" backend = UnitarySimulator() - backend_opts = {} + target = qi.random_unitary(2 ** 4, seed=111) circ = QuantumCircuit(4) - circ.append(qi.random_unitary(2 ** 4), [0, 1, 2, 3]) + circ.append(target, [0, 1, 2, 3]) circ.append(Snapshot("final", "unitary", 4), [0, 1, 2, 3]) - qobj = assemble(circ, backend=backend) - aer_input = backend._format_qobj(qobj, self.BACKEND_OPTS, None) - aer_output = backend._controller(aer_input) - self.assertIsInstance(aer_output, dict) - self.assertTrue(aer_output['success']) - snaps = aer_output['results'][0]['data']['snapshots']['unitary']['final'] - self.assertTrue(all([isinstance(arr, np.ndarray) for arr in snaps])) + qobj = assemble(circ, backend=backend, shots=1) + job = backend.run(qobj) + result = job.result() + self.assertSuccess(result) + snaps = result.data(0)['snapshots']['unitary']['final'] + for arr in snaps: + self.assertTrue(isinstance(arr, np.ndarray)) + self.assertEqual(qi.Operator(arr), target) + if __name__ == '__main__': unittest.main() diff --git a/test/terra/decorators.py b/test/terra/decorators.py index 8825d2d9f9..26d0734d8f 100644 --- a/test/terra/decorators.py +++ b/test/terra/decorators.py @@ -36,7 +36,7 @@ def is_method_available(backend, method): qobj = assemble(dummy_circ, optimization_level=0) backend_options = {"method": method} try: - job = backend.run(qobj, backend_options=backend_options) + job = backend.run(qobj, **backend_options) result = job.result() error_msg = 'not supported on this system' if not result.success and error_msg in result.results[0].status: diff --git a/test/terra/extensions/test_wrappers.py b/test/terra/extensions/test_wrappers.py index fd068125b7..7b863b34f6 100644 --- a/test/terra/extensions/test_wrappers.py +++ b/test/terra/extensions/test_wrappers.py @@ -49,8 +49,8 @@ def _create_qobj(self, backend, noise_model=None): circuit.x(list(range(num_qubits))) qobj = assemble(transpile(circuit, backend), backend) opts = {'max_parallel_threads': 1} - fqobj = backend._format_qobj(qobj, backend_options=opts, noise_model=noise_model) - return fqobj + fqobj = backend._format_qobj(qobj, **opts, noise_model=noise_model) + return fqobj.to_dict() def _map_and_test(self, cfunc, qobj): n = 2 diff --git a/test/terra/pulse/test_system_models.py b/test/terra/pulse/test_system_models.py index e390e80d42..5caa2aafe9 100644 --- a/test/terra/pulse/test_system_models.py +++ b/test/terra/pulse/test_system_models.py @@ -63,7 +63,6 @@ def _simple_system_model(self, v0=5.0, v1=5.1, j=0.01, r=0.02, alpha0=-0.33, alp dt = 1. return PulseSystemModel(hamiltonian=ham_model, - qubit_freq_est=self._default_qubit_lo_freq, u_channel_lo=self._u_channel_lo, subsystem_list=subsystem_list, dt=dt) @@ -113,27 +112,6 @@ def test_control_channel_labels_from_backend(self): self.assertEqual(system_model.control_channel_labels, expected) - def test_qubit_lo_default(self): - """Test drawing of defaults form a backend.""" - test_model = self._simple_system_model() - default_qubit_lo_freq = self._default_qubit_lo_freq - default_u_lo_freq = self._compute_u_lo_freqs(default_qubit_lo_freq) - - # test output of default qubit_lo_freq - freqs = test_model.calculate_channel_frequencies() - self.assertAlmostEqual(freqs['D0'], default_qubit_lo_freq[0]) - self.assertAlmostEqual(freqs['D1'], default_qubit_lo_freq[1]) - self.assertAlmostEqual(freqs['U0'], default_u_lo_freq[0]) - self.assertAlmostEqual(freqs['U1'], default_u_lo_freq[1]) - - # test defaults again, but with non-default hamiltonian - test_model = self._simple_system_model(v0=5.1, v1=4.9, j=0.02) - freqs = test_model.calculate_channel_frequencies() - self.assertAlmostEqual(freqs['D0'], default_qubit_lo_freq[0]) - self.assertAlmostEqual(freqs['D1'], default_qubit_lo_freq[1]) - self.assertAlmostEqual(freqs['U0'], default_u_lo_freq[0]) - self.assertAlmostEqual(freqs['U1'], default_u_lo_freq[1]) - def test_qubit_lo_from_hamiltonian(self): """Test computation of qubit_lo_freq from the hamiltonian itself.""" test_model = self._simple_system_model() @@ -155,6 +133,7 @@ def test_qubit_lo_from_hamiltonian(self): self.assertAlmostEqual(freqs['U1'], -0.203960780543) def test_qubit_lo_from_configurable_backend(self): + """Test computation of qubit_lo_freq from configurable backend.""" backend = FakeArmonk() test_model = PulseSystemModel.from_backend(backend) qubit_lo_from_hamiltonian = test_model.hamiltonian.get_qubit_lo_from_drift() diff --git a/test/terra/test_python_to_cpp.py b/test/terra/test_python_to_cpp.py index 7e60aec6cc..f8f820d470 100644 --- a/test/terra/test_python_to_cpp.py +++ b/test/terra/test_python_to_cpp.py @@ -25,7 +25,6 @@ class TestPythonToCpp(QiskitAerTestCase): """ Test Pyhton C API wrappers we have for dealing with Python data structures in C++ code. """ - def test_py_list_to_cpp_vec(self): arg = [1., 2., 3.] self.assertTrue(test_py_list_to_cpp_vec(arg)) diff --git a/tools/verify_wheels.py b/tools/verify_wheels.py index d0197d2878..da1f9f62d4 100644 --- a/tools/verify_wheels.py +++ b/tools/verify_wheels.py @@ -16,7 +16,7 @@ from qiskit.quantum_info.operators.predicates import matrix_equal from qiskit.providers.aer.pulse.system_models.duffing_model_generators import duffing_system_model -from qiskit.pulse import (Schedule, Play, Acquire, SamplePulse, DriveChannel, AcquireChannel, +from qiskit.pulse import (Schedule, Play, Acquire, Waveform, DriveChannel, AcquireChannel, MemorySlot) from qiskit.providers.aer import QasmSimulator @@ -428,7 +428,7 @@ def model_and_pi_schedule(): dt=1.0) # note: parameters set so that area under curve is 1/4 - sample_pulse = SamplePulse(np.ones(50)) + sample_pulse = Waveform(np.ones(50)) # construct schedule schedule = Schedule(name='test_sched') @@ -478,7 +478,7 @@ def model_and_pi_schedule(): meas_level=1, meas_return='avg', shots=1) - results = backend_sim.run(qobj, system_model).result() + results = backend_sim.run(qobj, system_model=system_model).result() state = results.get_statevector(0) assertAlmostEqual(state[0], 0, delta=10**-3) assertAlmostEqual(state[1], -1j, delta=10**-3) From 6fd2e5e4e2304bb590438ad191c130a303588ca3 Mon Sep 17 00:00:00 2001 From: "Christopher J. Wood" Date: Tue, 13 Oct 2020 17:29:46 -0400 Subject: [PATCH 018/126] Use ExperimentResult rather than ExperimentData in Controller and State functions (#981) * Pass ExperimentResult object rather than ExperimentData object in function args This changes the source code to pass around an ExperimentResult reference rather than an ExperimentData reference for storing simulator result data. This is so other data in the result can be accessed such as metadata, which was previously being compied from ExperimentData to ExperimentResult. --- src/controllers/controller.hpp | 49 ++++------ src/controllers/qasm_controller.hpp | 96 +++++++++---------- src/controllers/statevector_controller.hpp | 30 +++--- src/controllers/unitary_controller.hpp | 32 +++---- src/framework/results/experiment_data.hpp | 77 --------------- src/framework/results/experiment_result.hpp | 19 +++- src/framework/results/pybind_result.hpp | 2 +- src/noise/quantum_error.hpp | 2 +- .../density_matrix/densitymatrix_state.hpp | 48 +++++----- .../extended_stabilizer_state.hpp | 42 ++++---- .../matrix_product_state.hpp | 86 ++++++++--------- .../stabilizer/stabilizer_state.hpp | 48 +++++----- src/simulators/state.hpp | 36 +++---- .../statevector/statevector_state.hpp | 74 +++++++------- .../superoperator/superoperator_state.hpp | 12 +-- src/simulators/unitary/unitary_state.hpp | 14 +-- src/transpile/basic_opts.hpp | 8 +- src/transpile/circuitopt.hpp | 2 +- src/transpile/delay_measure.hpp | 6 +- src/transpile/fusion.hpp | 22 ++--- src/transpile/truncate_qubits.hpp | 6 +- 21 files changed, 322 insertions(+), 389 deletions(-) diff --git a/src/controllers/controller.hpp b/src/controllers/controller.hpp index 9e53b7cee2..b2c7fccda2 100755 --- a/src/controllers/controller.hpp +++ b/src/controllers/controller.hpp @@ -40,7 +40,7 @@ // Base Controller #include "framework/creg.hpp" #include "framework/qobj.hpp" -#include "framework/results/experiment_data.hpp" +#include "framework/results/experiment_result.hpp" #include "framework/results/result.hpp" #include "framework/rng.hpp" #include "noise/noise_model.hpp" @@ -137,14 +137,14 @@ class Controller { virtual void execute_circuit(Circuit &circ, Noise::NoiseModel &noise, const json_t &config, - ExperimentResult &exp_result); + ExperimentResult &result); // Abstract method for executing a circuit. // This method must initialize a state and return output data for // the required number of shots. virtual void run_circuit(const Circuit &circ, const Noise::NoiseModel &noise, const json_t &config, uint_t shots, uint_t rng_seed, - ExperimentData &data) const = 0; + ExperimentResult &result) const = 0; //------------------------------------------------------------------------- // State validation @@ -574,27 +574,27 @@ Result Controller::execute(std::vector &circuits, void Controller::execute_circuit(Circuit &circ, Noise::NoiseModel &noise, const json_t &config, - ExperimentResult &exp_result) { + ExperimentResult &result) { // Start individual circuit timer auto timer_start = myclock_t::now(); // state circuit timer // Initialize circuit json return - exp_result.data.set_config(config); + result.data.set_config(config); // Execute in try block so we can catch errors and return the error message // for individual circuit failures. try { // Remove barriers from circuit Transpile::ReduceBarrier barrier_pass; - barrier_pass.optimize_circuit(circ, noise, circ.opset(), exp_result.data); + barrier_pass.optimize_circuit(circ, noise, circ.opset(), result); // Truncate unused qubits from circuit and noise model if (truncate_qubits_) { Transpile::TruncateQubits truncate_pass; truncate_pass.set_config(config); truncate_pass.optimize_circuit(circ, noise, circ.opset(), - exp_result.data); + result); } // set parallelization for this circuit @@ -604,7 +604,7 @@ void Controller::execute_circuit(Circuit &circ, // Single shot thread execution if (parallel_shots_ <= 1) { - run_circuit(circ, noise, config, circ.shots, circ.seed, exp_result.data); + run_circuit(circ, noise, config, circ.shots, circ.seed, result); // Parallel shot thread execution } else { // Calculate shots per thread @@ -618,13 +618,13 @@ void Controller::execute_circuit(Circuit &circ, } // Vector to store parallel thread output data - std::vector par_data(parallel_shots_); + std::vector par_results(parallel_shots_); std::vector error_msgs(parallel_shots_); #pragma omp parallel for if (parallel_shots_ > 1) num_threads(parallel_shots_) for (int i = 0; i < parallel_shots_; i++) { try { run_circuit(circ, noise, config, subshots[i], circ.seed + i, - par_data[i]); + par_results[i]); } catch (std::runtime_error &error) { error_msgs[i] = error.what(); } @@ -636,36 +636,29 @@ void Controller::execute_circuit(Circuit &circ, // Accumulate results across shots // Use move semantics to avoid copying data - for (auto &datum : par_data) { - exp_result.data.combine(std::move(datum)); + for (auto &res : par_results) { + result.combine(std::move(res)); } } // Report success - exp_result.status = ExperimentResult::Status::completed; + result.status = ExperimentResult::Status::completed; // Pass through circuit header and add metadata - exp_result.header = circ.header; - exp_result.shots = circ.shots; - exp_result.seed = circ.seed; - // Move any metadata from the subclass run_circuit data - // to the experiment result metadata field - for (const auto &pair : exp_result.data.metadata()) { - exp_result.add_metadata(pair.first, pair.second); - } - // Remove the metatdata field from data - exp_result.data.metadata().clear(); - exp_result.metadata["parallel_shots"] = parallel_shots_; - exp_result.metadata["parallel_state_update"] = parallel_state_update_; + result.header = circ.header; + result.shots = circ.shots; + result.seed = circ.seed; + result.metadata["parallel_shots"] = parallel_shots_; + result.metadata["parallel_state_update"] = parallel_state_update_; // Add timer data auto timer_stop = myclock_t::now(); // stop timer double time_taken = std::chrono::duration(timer_stop - timer_start).count(); - exp_result.time_taken = time_taken; + result.time_taken = time_taken; } // If an exception occurs during execution, catch it and pass it to the output catch (std::exception &e) { - exp_result.status = ExperimentResult::Status::error; - exp_result.message = e.what(); + result.status = ExperimentResult::Status::error; + result.message = e.what(); } } diff --git a/src/controllers/qasm_controller.hpp b/src/controllers/qasm_controller.hpp index 9c3431db56..38c2d6b789 100755 --- a/src/controllers/qasm_controller.hpp +++ b/src/controllers/qasm_controller.hpp @@ -179,7 +179,7 @@ class QasmController : public Base::Controller { const json_t& config, uint_t shots, uint_t rng_seed, - ExperimentData& data) const override; + ExperimentResult& result) const override; //---------------------------------------------------------------- // Utility functions @@ -223,7 +223,7 @@ class QasmController : public Base::Controller { uint_t rng_seed, const Initstate_t& initial_state, const Method method, - ExperimentData& data) const; + ExperimentResult& result) const; // Execute a single shot a of circuit by initializing the state vector // to initial_state, running all ops in circ, and updating data with @@ -232,7 +232,7 @@ class QasmController : public Base::Controller { void run_single_shot(const Circuit& circ, State_t& state, const Initstate_t& initial_state, - ExperimentData& data, + ExperimentResult& result, RngEngine& rng) const; // Execute multiple shots a of circuit by initializing the state vector @@ -244,7 +244,7 @@ class QasmController : public Base::Controller { State_t& state, const Initstate_t& initial_state, const Method method, - ExperimentData& data, + ExperimentResult& result, RngEngine& rng) const; template @@ -255,7 +255,7 @@ class QasmController : public Base::Controller { State_t& state, const Initstate_t& initial_state, const Method method, - ExperimentData& data, + ExperimentResult& result, RngEngine& rng) const; //---------------------------------------------------------------- @@ -268,7 +268,7 @@ class QasmController : public Base::Controller { void measure_sampler(const std::vector& meas_ops, uint_t shots, State_t& state, - ExperimentData& data, + ExperimentResult& result, RngEngine& rng) const; // Check if measure sampling optimization is valid for the input circuit @@ -389,7 +389,7 @@ void QasmController::run_circuit(const Circuit& circ, const json_t& config, uint_t shots, uint_t rng_seed, - ExperimentData& data) const { + ExperimentResult& result) const { // Validate circuit for simulation method switch (simulation_method(circ, noise, true)) { case Method::statevector: { @@ -397,12 +397,12 @@ void QasmController::run_circuit(const Circuit& circ, // Double-precision Statevector simulation return run_circuit_helper>>( circ, noise, config, shots, rng_seed, initial_statevector_, - Method::statevector, data); + Method::statevector, result); } else { // Single-precision Statevector simulation return run_circuit_helper>>( circ, noise, config, shots, rng_seed, initial_statevector_, - Method::statevector, data); + Method::statevector, result); } } case Method::statevector_thrust_gpu: { @@ -416,13 +416,13 @@ void QasmController::run_circuit(const Circuit& circ, return run_circuit_helper< Statevector::State>>( circ, noise, config, shots, rng_seed, initial_statevector_, - Method::statevector_thrust_gpu, data); + Method::statevector_thrust_gpu, result); } else { // Single-precision Statevector simulation return run_circuit_helper< Statevector::State>>( circ, noise, config, shots, rng_seed, initial_statevector_, - Method::statevector_thrust_gpu, data); + Method::statevector_thrust_gpu, result); } #endif } @@ -437,13 +437,13 @@ void QasmController::run_circuit(const Circuit& circ, return run_circuit_helper< Statevector::State>>( circ, noise, config, shots, rng_seed, initial_statevector_, - Method::statevector_thrust_cpu, data); + Method::statevector_thrust_cpu, result); } else { // Single-precision Statevector simulation return run_circuit_helper< Statevector::State>>( circ, noise, config, shots, rng_seed, initial_statevector_, - Method::statevector_thrust_cpu, data); + Method::statevector_thrust_cpu, result); } #endif } @@ -453,13 +453,13 @@ void QasmController::run_circuit(const Circuit& circ, return run_circuit_helper< DensityMatrix::State>>( circ, noise, config, shots, rng_seed, cvector_t(), - Method::density_matrix, data); + Method::density_matrix, result); } else { // Single-precision density matrix simulation return run_circuit_helper< DensityMatrix::State>>( circ, noise, config, shots, rng_seed, cvector_t(), - Method::density_matrix, data); + Method::density_matrix, result); } } case Method::density_matrix_thrust_gpu: { @@ -473,13 +473,13 @@ void QasmController::run_circuit(const Circuit& circ, return run_circuit_helper< DensityMatrix::State>>( circ, noise, config, shots, rng_seed, cvector_t(), - Method::density_matrix_thrust_gpu, data); + Method::density_matrix_thrust_gpu, result); } else { // Single-precision density matrix simulation return run_circuit_helper< DensityMatrix::State>>( circ, noise, config, shots, rng_seed, cvector_t(), - Method::density_matrix_thrust_gpu, data); + Method::density_matrix_thrust_gpu, result); } #endif case Method::density_matrix_thrust_cpu: @@ -494,13 +494,13 @@ void QasmController::run_circuit(const Circuit& circ, return run_circuit_helper< DensityMatrix::State>>( circ, noise, config, shots, rng_seed, cvector_t(), - Method::density_matrix_thrust_cpu, data); + Method::density_matrix_thrust_cpu, result); } else { // Single-precision density matrix simulation return run_circuit_helper< DensityMatrix::State>>( circ, noise, config, shots, rng_seed, cvector_t(), - Method::density_matrix_thrust_cpu, data); + Method::density_matrix_thrust_cpu, result); } #endif } @@ -509,16 +509,16 @@ void QasmController::run_circuit(const Circuit& circ, // TODO: Stabilizer doesn't yet support custom state initialization return run_circuit_helper( circ, noise, config, shots, rng_seed, Clifford::Clifford(), - Method::stabilizer, data); + Method::stabilizer, result); case Method::extended_stabilizer: return run_circuit_helper( circ, noise, config, shots, rng_seed, CHSimulator::Runner(), - Method::extended_stabilizer, data); + Method::extended_stabilizer, result); case Method::matrix_product_state: return run_circuit_helper( circ, noise, config, shots, rng_seed, MatrixProductState::MPS(), - Method::matrix_product_state, data); + Method::matrix_product_state, result); default: throw std::runtime_error("QasmController:Invalid simulation method"); @@ -859,7 +859,7 @@ void QasmController::run_circuit_helper(const Circuit& circ, uint_t rng_seed, const Initstate_t& initial_state, const Method method, - ExperimentData& data) const { + ExperimentResult& result) const { // Initialize new state object State_t state; @@ -876,13 +876,13 @@ void QasmController::run_circuit_helper(const Circuit& circ, rng.set_seed(rng_seed); // Output data container - data.set_config(config); - data.add_metadata("method", state.name()); - state.add_metadata(data); + result.set_config(config); + result.add_metadata("method", state.name()); + state.add_metadata(result); // Add measure sampling to metadata // Note: this will set to `true` if sampling is enabled for the circuit - data.add_metadata("measure_sampling", false); + result.add_metadata("measure_sampling", false); // Choose execution method based on noise and method @@ -918,7 +918,7 @@ void QasmController::run_circuit_helper(const Circuit& circ, // General circuit noise sampling else { run_circuit_with_sampled_noise(circ, noise, config, shots, state, - initial_state, method, data, rng); + initial_state, method, result, rng); return; } @@ -926,24 +926,24 @@ void QasmController::run_circuit_helper(const Circuit& circ, Noise::NoiseModel dummy_noise; Transpile::DelayMeasure measure_pass; measure_pass.set_config(config); - measure_pass.optimize_circuit(opt_circ, dummy_noise, state.opset(), data); + measure_pass.optimize_circuit(opt_circ, dummy_noise, state.opset(), result); auto fusion_pass = transpile_fusion(method, config, fusion_method); - fusion_pass.optimize_circuit(opt_circ, dummy_noise, state.opset(), data); + fusion_pass.optimize_circuit(opt_circ, dummy_noise, state.opset(), result); // Run simulation - run_multi_shot(opt_circ, shots, state, initial_state, method, data, rng); + run_multi_shot(opt_circ, shots, state, initial_state, method, result, rng); } template void QasmController::run_single_shot(const Circuit& circ, State_t& state, const Initstate_t& initial_state, - ExperimentData& data, + ExperimentResult& result, RngEngine& rng) const { initialize_state(circ, state, initial_state); - state.apply_ops(circ.ops, data, rng, true); - state.add_creg_to_data(data); + state.apply_ops(circ.ops, result, rng, true); + state.add_creg_to_data(result); } template @@ -952,7 +952,7 @@ void QasmController::run_multi_shot(const Circuit& circ, State_t& state, const Initstate_t& initial_state, const Method method, - ExperimentData& data, + ExperimentResult& result, RngEngine& rng) const { // Check if measure sampler and optimization are valid if (check_measure_sampling_opt(circ, method)) { @@ -964,20 +964,20 @@ void QasmController::run_multi_shot(const Circuit& circ, circ.ops.begin() + pos); bool final_ops = (pos == circ.ops.size()); initialize_state(circ, state, initial_state); - state.apply_ops(ops, data, rng, final_ops); + state.apply_ops(ops, result, rng, final_ops); // Get measurement operations and set of measured qubits ops = std::vector(circ.ops.begin() + pos, circ.ops.end()); - measure_sampler(ops, shots, state, data, rng); + measure_sampler(ops, shots, state, result, rng); // Add measure sampling metadata - data.add_metadata("measure_sampling", true); + result.add_metadata("measure_sampling", true); } else { // Perform standard execution if we cannot apply the // measurement sampling optimization while (shots-- > 0) { - run_single_shot(circ, state, initial_state, data, rng); + run_single_shot(circ, state, initial_state, result, rng); } } } @@ -991,7 +991,7 @@ void QasmController::run_circuit_with_sampled_noise(const Circuit& circ, State_t& state, const Initstate_t& initial_state, const Method method, - ExperimentData& data, + ExperimentResult& result, RngEngine& rng) const { // Transpilation for circuit noise method @@ -1004,9 +1004,9 @@ void QasmController::run_circuit_with_sampled_noise(const Circuit& circ, while (shots-- > 0) { Circuit noise_circ = noise.sample_noise(circ, rng); noise_circ.shots = 1; - measure_pass.optimize_circuit(noise_circ, dummy_noise, state.opset(), data); - fusion_pass.optimize_circuit(noise_circ, dummy_noise, state.opset(), data); - run_single_shot(noise_circ, state, initial_state, data, rng); + measure_pass.optimize_circuit(noise_circ, dummy_noise, state.opset(), result); + fusion_pass.optimize_circuit(noise_circ, dummy_noise, state.opset(), result); + run_single_shot(noise_circ, state, initial_state, result, rng); } } @@ -1052,12 +1052,12 @@ void QasmController::measure_sampler( const std::vector& meas_roerror_ops, uint_t shots, State_t& state, - ExperimentData& data, + ExperimentResult& result, RngEngine& rng) const { // Check if meas_circ is empty, and if so return initial creg if (meas_roerror_ops.empty()) { while (shots-- > 0) { - state.add_creg_to_data(data); + state.add_creg_to_data(result); } return; } @@ -1127,10 +1127,10 @@ void QasmController::measure_sampler( } auto memory = creg.memory_hex(); - data.add_memory_count(memory); - data.add_pershot_memory(memory); + result.data.add_memory_count(memory); + result.data.add_pershot_memory(memory); - data.add_pershot_register(creg.register_hex()); + result.data.add_pershot_register(creg.register_hex()); // pop off processed sample all_samples.pop_back(); diff --git a/src/controllers/statevector_controller.hpp b/src/controllers/statevector_controller.hpp index f98a185810..1d981d8564 100755 --- a/src/controllers/statevector_controller.hpp +++ b/src/controllers/statevector_controller.hpp @@ -102,7 +102,7 @@ class StatevectorController : public Base::Controller { const Noise::NoiseModel& noise, const json_t& config, uint_t shots, uint_t rng_seed, - ExperimentData &data) const override; + ExperimentResult &result) const override; // Execute n-shots of a circuit on the input state template @@ -110,7 +110,7 @@ class StatevectorController : public Base::Controller { const Noise::NoiseModel& noise, const json_t& config, uint_t shots, uint_t rng_seed, - ExperimentData &data) const; + ExperimentResult &result) const; //----------------------------------------------------------------------- // Custom initial state //----------------------------------------------------------------------- @@ -200,18 +200,18 @@ size_t StatevectorController::required_memory_mb( void StatevectorController::run_circuit( const Circuit& circ, const Noise::NoiseModel& noise, const json_t& config, - uint_t shots, uint_t rng_seed, ExperimentData &data) const { + uint_t shots, uint_t rng_seed, ExperimentResult &result) const { switch (method_) { case Method::automatic: case Method::statevector_cpu: { if (precision_ == Precision::double_precision) { // Double-precision Statevector simulation return run_circuit_helper>>( - circ, noise, config, shots, rng_seed, data); + circ, noise, config, shots, rng_seed, result); } else { // Single-precision Statevector simulation return run_circuit_helper>>( - circ, noise, config, shots, rng_seed, data); + circ, noise, config, shots, rng_seed, result); } } case Method::statevector_thrust_gpu: { @@ -220,12 +220,12 @@ void StatevectorController::run_circuit( // Double-precision Statevector simulation return run_circuit_helper< Statevector::State>>( - circ, noise, config, shots, rng_seed, data); + circ, noise, config, shots, rng_seed, result); } else { // Single-precision Statevector simulation return run_circuit_helper< Statevector::State>>( - circ, noise, config, shots, rng_seed, data); + circ, noise, config, shots, rng_seed, result); } #else throw std::runtime_error( @@ -240,12 +240,12 @@ void StatevectorController::run_circuit( // Double-precision Statevector simulation return run_circuit_helper< Statevector::State>>( - circ, noise, config, shots, rng_seed, data); + circ, noise, config, shots, rng_seed, result); } else { // Single-precision Statevector simulation return run_circuit_helper< Statevector::State>>( - circ, noise, config, shots, rng_seed, data); + circ, noise, config, shots, rng_seed, result); } #else throw std::runtime_error( @@ -263,7 +263,7 @@ void StatevectorController::run_circuit( template void StatevectorController::run_circuit_helper( const Circuit& circ, const Noise::NoiseModel& noise, const json_t& config, - uint_t shots, uint_t rng_seed, ExperimentData &data) const { + uint_t shots, uint_t rng_seed, ExperimentResult &result) const { // Initialize state State_t state; @@ -294,7 +294,7 @@ void StatevectorController::run_circuit_helper( rng.set_seed(rng_seed); // Output data container - data.set_config(config); + result.set_config(config); // Optimize circuit const std::vector* op_ptr = &circ.ops; @@ -304,7 +304,7 @@ void StatevectorController::run_circuit_helper( if (fusion_pass.active && circ.num_qubits >= fusion_pass.threshold) { opt_circ = circ; // copy circuit Noise::NoiseModel dummy_noise; // dummy object for transpile pass - fusion_pass.optimize_circuit(opt_circ, dummy_noise, state.opset(), data); + fusion_pass.optimize_circuit(opt_circ, dummy_noise, state.opset(), result); op_ptr = &opt_circ.ops; } @@ -315,11 +315,11 @@ void StatevectorController::run_circuit_helper( state.initialize_qreg(circ.num_qubits, initial_state_); } state.initialize_creg(circ.num_memory, circ.num_registers); - state.apply_ops(*op_ptr, data, rng); - state.add_creg_to_data(data); + state.apply_ops(*op_ptr, result, rng); + state.add_creg_to_data(result); // Add final state to the data - data.add_additional_data("statevector", state.qreg().move_to_vector()); + result.data.add_additional_data("statevector", state.qreg().move_to_vector()); } //------------------------------------------------------------------------- diff --git a/src/controllers/unitary_controller.hpp b/src/controllers/unitary_controller.hpp index a38f06e4db..ccc7edd40b 100755 --- a/src/controllers/unitary_controller.hpp +++ b/src/controllers/unitary_controller.hpp @@ -93,13 +93,13 @@ class UnitaryController : public Base::Controller { virtual void run_circuit(const Circuit &circ, const Noise::NoiseModel &noise, const json_t &config, uint_t shots, - uint_t rng_seed, ExperimentData &data) const override; + uint_t rng_seed, ExperimentResult &result) const override; template void run_circuit_helper(const Circuit &circ, const Noise::NoiseModel &noise, const json_t &config, uint_t shots, - uint_t rng_seed, ExperimentData &data) const; + uint_t rng_seed, ExperimentResult &result) const; //----------------------------------------------------------------------- // Custom initial state @@ -192,7 +192,7 @@ void UnitaryController::run_circuit(const Circuit &circ, const Noise::NoiseModel &noise, const json_t &config, uint_t shots, - uint_t rng_seed, ExperimentData &data) const { + uint_t rng_seed, ExperimentResult &result) const { switch (method_) { case Method::automatic: case Method::unitary_cpu: { @@ -200,12 +200,12 @@ void UnitaryController::run_circuit(const Circuit &circ, // Double-precision unitary simulation return run_circuit_helper< QubitUnitary::State>>(circ, noise, config, - shots, rng_seed, data); + shots, rng_seed, result); } else { // Single-precision unitary simulation return run_circuit_helper< QubitUnitary::State>>(circ, noise, config, - shots, rng_seed, data); + shots, rng_seed, result); } } case Method::unitary_thrust_gpu: { @@ -214,12 +214,12 @@ void UnitaryController::run_circuit(const Circuit &circ, // Double-precision unitary simulation return run_circuit_helper< QubitUnitary::State>>( - circ, noise, config, shots, rng_seed, data); + circ, noise, config, shots, rng_seed, result); } else { // Single-precision unitary simulation return run_circuit_helper< QubitUnitary::State>>( - circ, noise, config, shots, rng_seed, data); + circ, noise, config, shots, rng_seed, result); } #else throw std::runtime_error( @@ -233,12 +233,12 @@ void UnitaryController::run_circuit(const Circuit &circ, // Double-precision unitary simulation return run_circuit_helper< QubitUnitary::State>>( - circ, noise, config, shots, rng_seed, data); + circ, noise, config, shots, rng_seed, result); } else { // Single-precision unitary simulation return run_circuit_helper< QubitUnitary::State>>( - circ, noise, config, shots, rng_seed, data); + circ, noise, config, shots, rng_seed, result); } #else throw std::runtime_error( @@ -254,7 +254,7 @@ void UnitaryController::run_circuit(const Circuit &circ, template void UnitaryController::run_circuit_helper( const Circuit &circ, const Noise::NoiseModel &noise, const json_t &config, - uint_t shots, uint_t rng_seed, ExperimentData &data) const { + uint_t shots, uint_t rng_seed, ExperimentResult &result) const { // Initialize state State_t state; @@ -292,8 +292,8 @@ void UnitaryController::run_circuit_helper( rng.set_seed(rng_seed); // Output data container - data.set_config(config); - data.add_metadata("method", state.name()); + result.set_config(config); + result.add_metadata("method", state.name()); // Optimize circuit const std::vector* op_ptr = &circ.ops; @@ -303,7 +303,7 @@ void UnitaryController::run_circuit_helper( if (fusion_pass.active && circ.num_qubits >= fusion_pass.threshold) { opt_circ = circ; // copy circuit Noise::NoiseModel dummy_noise; // dummy object for transpile pass - fusion_pass.optimize_circuit(opt_circ, dummy_noise, state.opset(), data); + fusion_pass.optimize_circuit(opt_circ, dummy_noise, state.opset(), result); op_ptr = &opt_circ.ops; } @@ -314,11 +314,11 @@ void UnitaryController::run_circuit_helper( state.initialize_qreg(circ.num_qubits, initial_unitary_); } state.initialize_creg(circ.num_memory, circ.num_registers); - state.apply_ops(*op_ptr, data, rng); - state.add_creg_to_data(data); + state.apply_ops(*op_ptr, result, rng); + state.add_creg_to_data(result); // Add final state unitary to the data - data.add_additional_data("unitary", state.qreg().move_to_matrix()); + result.data.add_additional_data("unitary", state.qreg().move_to_matrix()); } //------------------------------------------------------------------------- diff --git a/src/framework/results/experiment_data.hpp b/src/framework/results/experiment_data.hpp index 30c608032e..e89bc934c0 100755 --- a/src/framework/results/experiment_data.hpp +++ b/src/framework/results/experiment_data.hpp @@ -132,21 +132,6 @@ class ExperimentData : public DataContainer, using DataContainer>::add_additional_data; using DataContainer>::add_additional_data; - //---------------------------------------------------------------- - // Metadata - //---------------------------------------------------------------- - - // Access metadata map - stringmap_t &metadata() { return metadata_; } - const stringmap_t &metadata() const { return metadata_; } - - // Add new data to metadata at the specified key. - // This will use the json conversion method `to_json` for data type T. - // If they key already exists this will update the current data - // with the new data. - template - void add_metadata(const std::string &key, T &&data); - //---------------------------------------------------------------- // Config //---------------------------------------------------------------- @@ -188,14 +173,6 @@ class ExperimentData : public DataContainer, // Register state for each shot as hex string std::vector register_; - //---------------------------------------------------------------- - // Metadata - //---------------------------------------------------------------- - - // This will be passed up to the experiment_result level - // metadata field - stringmap_t metadata_; - //---------------------------------------------------------------- // Access Templated DataContainers //---------------------------------------------------------------- @@ -320,47 +297,6 @@ void ExperimentData::add_additional_data(const std::string &key, T &&data) { } } -//------------------------------------------------------------------ -// Metadata -//------------------------------------------------------------------ - -template -void ExperimentData::add_metadata(const std::string &key, T &&data) { - // Use implicit to_json conversion function for T - json_t jdata = data; - add_metadata(key, std::move(jdata)); -} - -template <> -void ExperimentData::add_metadata(const std::string &key, json_t &&data) { - auto elt = metadata_.find("key"); - if (elt == metadata_.end()) { - // If key doesn't already exist add new data - metadata_[key] = std::move(data); - } else { - // If key already exists append with additional data - elt->second.update(data.begin(), data.end()); - } -} - -template <> -void ExperimentData::add_metadata(const std::string &key, const json_t &data) { - auto elt = metadata_.find("key"); - if (elt == metadata_.end()) { - // If key doesn't already exist add new data - metadata_[key] = data; - } else { - // If key already exists append with additional data - elt->second.update(data.begin(), data.end()); - } -} - -template <> -void ExperimentData::add_metadata(const std::string &key, json_t &data) { - const json_t &const_data = data; - add_metadata(key, const_data); -} - //------------------------------------------------------------------ // Access Data //------------------------------------------------------------------ @@ -415,9 +351,6 @@ void ExperimentData::clear() { counts_.clear(); memory_.clear(); register_.clear(); - - // Clear metadata - metadata_.clear(); } ExperimentData &ExperimentData::combine(const ExperimentData &other) { @@ -445,11 +378,6 @@ ExperimentData &ExperimentData::combine(const ExperimentData &other) { counts_[pair.first] += pair.second; } - // Combine metadata - for (const auto &pair : other.metadata_) { - metadata_[pair.first] = pair.second; - } - return *this; } @@ -477,11 +405,6 @@ ExperimentData &ExperimentData::combine(ExperimentData &&other) { counts_[pair.first] += pair.second; } - // Combine metadata - for (auto &pair : other.metadata_) { - metadata_[pair.first] = std::move(pair.second); - } - // Clear any remaining data from other container other.clear(); diff --git a/src/framework/results/experiment_result.hpp b/src/framework/results/experiment_result.hpp index cf33d2e0b1..6a6aec08a8 100644 --- a/src/framework/results/experiment_result.hpp +++ b/src/framework/results/experiment_result.hpp @@ -51,8 +51,13 @@ struct ExperimentResult { // Serialize engine data to JSON json_t to_json(); -}; + // Set the output data config options + void set_config(const json_t &config) { data.set_config(config); } + + // Combine stored data + ExperimentResult& combine(ExperimentResult &&other); +}; //------------------------------------------------------------------------------ // Add metadata @@ -94,6 +99,18 @@ void ExperimentResult::add_metadata(const std::string &key, json_t &meta) { add_metadata(key, const_meta); } +ExperimentResult& ExperimentResult::combine(ExperimentResult &&other) { + // Combine data + data.combine(std::move(other.data)); + + // Combine metadata + for (const auto &pair : other.metadata) { + metadata[pair.first] = pair.second; + } + + return *this; +} + //------------------------------------------------------------------------------ // JSON serialization //------------------------------------------------------------------------------ diff --git a/src/framework/results/pybind_result.hpp b/src/framework/results/pybind_result.hpp index 53ff410f50..fc74cb1e16 100755 --- a/src/framework/results/pybind_result.hpp +++ b/src/framework/results/pybind_result.hpp @@ -17,7 +17,7 @@ #include "framework/pybind_basics.hpp" #include "framework/results/pybind_data.hpp" -#include "framework/results/experiment_data.hpp" +#include "framework/results/experiment_result.hpp" #include "framework/results/result.hpp" //------------------------------------------------------------------------------ diff --git a/src/noise/quantum_error.hpp b/src/noise/quantum_error.hpp index 1a1ef97f79..8ced414445 100644 --- a/src/noise/quantum_error.hpp +++ b/src/noise/quantum_error.hpp @@ -362,7 +362,7 @@ void QuantumError::compute_superoperator() { superop.initialize_qreg(get_num_qubits()); // Apply each gate in the circuit // We don't need output data or RNG for this - ExperimentData data; + ExperimentResult data; RngEngine rng; superop.apply_ops(circuits_[j], data, rng); superoperator_ += probabilities_[j] * superop.qreg().move_to_matrix(); diff --git a/src/simulators/density_matrix/densitymatrix_state.hpp b/src/simulators/density_matrix/densitymatrix_state.hpp index 0dbabec1f6..abfe1121cf 100644 --- a/src/simulators/density_matrix/densitymatrix_state.hpp +++ b/src/simulators/density_matrix/densitymatrix_state.hpp @@ -89,7 +89,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. virtual void apply_ops(const std::vector &ops, - ExperimentData &data, + ExperimentResult &result, RngEngine &rng, bool final_ops = false) override; @@ -151,7 +151,7 @@ class State : public Base::State { // Apply a supported snapshot instruction // If the input is not in allowed_snapshots an exeption will be raised. virtual void apply_snapshot(const Operations::Op &op, - ExperimentData &data, + ExperimentResult &result, bool last_op = false); // Apply a matrix to given qubits (identity on all other qubits) @@ -199,19 +199,19 @@ class State : public Base::State { // Snapshot reduced density matrix void snapshot_density_matrix(const Operations::Op &op, - ExperimentData &data, + ExperimentResult &result, bool last_op = false); // Snapshot current qubit probabilities for a measurement (average) - void snapshot_probabilities(const Operations::Op &op, ExperimentData &data, + void snapshot_probabilities(const Operations::Op &op, ExperimentResult &result, bool variance); // Snapshot the expectation value of a Pauli operator - void snapshot_pauli_expval(const Operations::Op &op, ExperimentData &data, + void snapshot_pauli_expval(const Operations::Op &op, ExperimentResult &result, bool variance); // Snapshot the expectation value of a matrix operator - void snapshot_matrix_expval(const Operations::Op &op, ExperimentData &data, + void snapshot_matrix_expval(const Operations::Op &op, ExperimentResult &result, bool variance); // Return the reduced density matrix for the simulator @@ -392,7 +392,7 @@ void State::set_config(const json_t &config) { template void State::apply_ops(const std::vector &ops, - ExperimentData &data, + ExperimentResult &result, RngEngine &rng, bool final_ops) { // Simple loop over vector of input operations @@ -419,7 +419,7 @@ void State::apply_ops(const std::vector &ops, apply_gate(op); break; case Operations::OpType::snapshot: - apply_snapshot(op, data, final_ops && ops.size() == i + 1); + apply_snapshot(op, result, final_ops && ops.size() == i + 1); break; case Operations::OpType::matrix: apply_matrix(op.qubits, op.mats[0]); @@ -447,7 +447,7 @@ void State::apply_ops(const std::vector &ops, template void State::apply_snapshot(const Operations::Op &op, - ExperimentData &data, + ExperimentResult &result, bool last_op) { // Look for snapshot type in snapshotset @@ -458,34 +458,34 @@ void State::apply_snapshot(const Operations::Op &op, "\'."); switch (it->second) { case Snapshots::densitymatrix: - snapshot_density_matrix(op, data, last_op); + snapshot_density_matrix(op, result, last_op); break; case Snapshots::cmemory: - BaseState::snapshot_creg_memory(op, data); + BaseState::snapshot_creg_memory(op, result); break; case Snapshots::cregister: - BaseState::snapshot_creg_register(op, data); + BaseState::snapshot_creg_register(op, result); break; case Snapshots::probs: // get probs as hexadecimal - snapshot_probabilities(op, data, false); + snapshot_probabilities(op, result, false); break; case Snapshots::probs_var: // get probs as hexadecimal - snapshot_probabilities(op, data, true); + snapshot_probabilities(op, result, true); break; case Snapshots::expval_pauli: { - snapshot_pauli_expval(op, data, false); + snapshot_pauli_expval(op, result, false); } break; case Snapshots::expval_pauli_var: { - snapshot_pauli_expval(op, data, true); + snapshot_pauli_expval(op, result, true); } break; /* TODO case Snapshots::expval_matrix: { - snapshot_matrix_expval(op, data, false); + snapshot_matrix_expval(op, result, false); } break; case Snapshots::expval_matrix_var: { - snapshot_matrix_expval(op, data, true); + snapshot_matrix_expval(op, result, true); } break; */ default: @@ -498,12 +498,12 @@ void State::apply_snapshot(const Operations::Op &op, template void State::snapshot_probabilities(const Operations::Op &op, - ExperimentData &data, + ExperimentResult &result, bool variance) { // get probs as hexadecimal auto probs = Utils::vec2ket(measure_probs(op.qubits), json_chop_threshold_, 16); - data.add_average_snapshot("probabilities", + result.data.add_average_snapshot("probabilities", op.string_params[0], BaseState::creg_.memory_hex(), std::move(probs), @@ -512,7 +512,7 @@ void State::snapshot_probabilities(const Operations::Op &op, template void State::snapshot_pauli_expval(const Operations::Op &op, - ExperimentData &data, + ExperimentResult &result, bool variance) { // Check empty edge case if (op.params_expval_pauli.empty()) { @@ -530,13 +530,13 @@ void State::snapshot_pauli_expval(const Operations::Op &op, // Add to snapshot Utils::chop_inplace(expval, json_chop_threshold_); - data.add_average_snapshot("expectation_value", op.string_params[0], + result.data.add_average_snapshot("expectation_value", op.string_params[0], BaseState::creg_.memory_hex(), expval, variance); } template void State::snapshot_density_matrix(const Operations::Op &op, - ExperimentData &data, + ExperimentResult &result, bool last_op) { cmatrix_t reduced_state; @@ -560,7 +560,7 @@ void State::snapshot_density_matrix(const Operations::Op &op, } } - data.add_average_snapshot("density_matrix", op.string_params[0], + result.data.add_average_snapshot("density_matrix", op.string_params[0], BaseState::creg_.memory_hex(), std::move(reduced_state), false); } diff --git a/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp b/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp index b589358e05..7c9e69cc03 100644 --- a/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp +++ b/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp @@ -73,7 +73,7 @@ class State: public Base::State //Apply a sequence of operations to the cicuit. For each operation, //we loop over the terms in the decomposition in parallel virtual void apply_ops(const std::vector &ops, - ExperimentData &data, + ExperimentResult &result, RngEngine &rng, bool final_ops = false) override; @@ -103,7 +103,7 @@ class State: public Base::State //circuit to a single state. This is used to optimize a circuit with a large //initial clifford fraction, or for running stabilizer circuits. void apply_stabilizer_circuit(const std::vector &ops, - ExperimentData &data, + ExperimentResult &result, RngEngine &rng); // Applies a sypported Gate operation to the state class. // If the input is not in allowed_gates an exeption will be raised. @@ -127,12 +127,12 @@ class State: public Base::State //Take a snapshot of the simulation state //TODO: Improve the CHSimulator::to_json method. - void apply_snapshot(const Operations::Op &op, ExperimentData &data, RngEngine &rng); + void apply_snapshot(const Operations::Op &op, ExperimentResult &result, RngEngine &rng); //Convert a decomposition to a state-vector - void statevector_snapshot(const Operations::Op &op, ExperimentData &data, RngEngine &rng); + void statevector_snapshot(const Operations::Op &op, ExperimentResult &result, RngEngine &rng); //Compute probabilities from a stabilizer rank decomposition //TODO: Check ordering/output format... - void probabilities_snapshot(const Operations::Op &op, ExperimentData &data, RngEngine &rng); + void probabilities_snapshot(const Operations::Op &op, ExperimentResult &result, RngEngine &rng); const static stringmap_t gateset_; const static stringmap_t snapshotset_; @@ -316,14 +316,14 @@ bool State::check_measurement_opt(const std::vector &ops) const // Implementation: Operations //------------------------------------------------------------------------- -void State::apply_ops(const std::vector &ops, ExperimentData &data, +void State::apply_ops(const std::vector &ops, ExperimentResult &result, RngEngine &rng, bool final_ops) { std::pair stabilizer_opts = check_stabilizer_opt(ops); bool is_stabilizer = stabilizer_opts.first; if(is_stabilizer) { - apply_stabilizer_circuit(ops, data, rng); + apply_stabilizer_circuit(ops, result, rng); } else { @@ -334,7 +334,7 @@ void State::apply_ops(const std::vector &ops, ExperimentData &da //Apply the stabilizer circuit first. This optimisaiton avoids duplicating the application //of the initial stabilizer circuit chi times. std::vector stabilizer_circuit(ops.cbegin(), ops.cbegin()+first_non_clifford); - apply_stabilizer_circuit(stabilizer_circuit, data, rng); + apply_stabilizer_circuit(stabilizer_circuit, result, rng); } std::vector non_stabilizer_circuit(ops.cbegin()+first_non_clifford, ops.cend()); uint_t chi = compute_chi(non_stabilizer_circuit); @@ -369,7 +369,7 @@ void State::apply_ops(const std::vector &ops, ExperimentData &da BaseState::creg_.apply_bfunc(op); break; case Operations::OpType::snapshot: - apply_snapshot(op, data, rng); + apply_snapshot(op, result, rng); break; default: throw std::invalid_argument("CH::State::apply_ops does not support operations of the type \'" + @@ -448,7 +448,7 @@ void State::apply_ops_parallel(const std::vector &ops, RngEngine } void State::apply_stabilizer_circuit(const std::vector &ops, - ExperimentData &data, RngEngine &rng) + ExperimentResult &result, RngEngine &rng) { for (const auto &op: ops) { @@ -475,7 +475,7 @@ void State::apply_stabilizer_circuit(const std::vector &ops, BaseState::creg_.apply_bfunc(op); break; case Operations::OpType::snapshot: - apply_snapshot(op, data, rng); + apply_snapshot(op, result, rng); break; default: throw std::invalid_argument("CH::State::apply_stabilizer_circuit does not support operations of the type \'" + @@ -627,7 +627,7 @@ void State::apply_gate(const Operations::Op &op, RngEngine &rng, uint_t rank) } } -void State::apply_snapshot(const Operations::Op &op, ExperimentData &data, RngEngine &rng) +void State::apply_snapshot(const Operations::Op &op, ExperimentResult &result, RngEngine &rng) { auto it = snapshotset_.find(op.name); if (it == snapshotset_.end()) @@ -638,19 +638,19 @@ void State::apply_snapshot(const Operations::Op &op, ExperimentData &data, RngEn switch(it->second) { case Snapshots::state: - BaseState::snapshot_state(op, data, "extended_stabilizer_state"); + BaseState::snapshot_state(op, result, "extended_stabilizer_state"); break; case Snapshots::cmemory: - BaseState::snapshot_creg_memory(op, data); + BaseState::snapshot_creg_memory(op, result); break; case Snapshots::cregister: - BaseState::snapshot_creg_register(op, data); + BaseState::snapshot_creg_register(op, result); break; case Snapshots::statevector: - statevector_snapshot(op, data, rng); + statevector_snapshot(op, result, rng); break; case Snapshots::probabilities: - probabilities_snapshot(op, data, rng); + probabilities_snapshot(op, result, rng); break; default: throw std::invalid_argument("CH::State::invlaid snapshot instruction \'"+ @@ -659,7 +659,7 @@ void State::apply_snapshot(const Operations::Op &op, ExperimentData &data, RngEn } } -void State::statevector_snapshot(const Operations::Op &op, ExperimentData &data, RngEngine &rng) +void State::statevector_snapshot(const Operations::Op &op, ExperimentResult &result, RngEngine &rng) { cvector_t statevector; BaseState::qreg_.state_vector(statevector, rng); @@ -668,10 +668,10 @@ void State::statevector_snapshot(const Operations::Op &op, ExperimentData &data, { sum += std::pow(std::abs(statevector[i]), 2); } - data.add_pershot_snapshot("statevector", op.string_params[0], statevector); + result.data.add_pershot_snapshot("statevector", op.string_params[0], statevector); } -void State::probabilities_snapshot(const Operations::Op &op, ExperimentData &data, RngEngine &rng) +void State::probabilities_snapshot(const Operations::Op &op, ExperimentResult &result, RngEngine &rng) { rvector_t probs; if (op.qubits.size() == 0) @@ -718,7 +718,7 @@ void State::probabilities_snapshot(const Operations::Op &op, ExperimentData &dat probs[i] /= probabilities_snapshot_samples_; } } - data.add_average_snapshot("probabilities", op.string_params[0], + result.data.add_average_snapshot("probabilities", op.string_params[0], BaseState::creg_.memory_hex(), Utils::vec2ket(probs, snapshot_chop_threshold_, 16), false); diff --git a/src/simulators/matrix_product_state/matrix_product_state.hpp b/src/simulators/matrix_product_state/matrix_product_state.hpp index fc72af7d0a..c0f00d4ccb 100644 --- a/src/simulators/matrix_product_state/matrix_product_state.hpp +++ b/src/simulators/matrix_product_state/matrix_product_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 exception will be raised. virtual void apply_ops(const std::vector &ops, - ExperimentData &data, + ExperimentResult &result, RngEngine &rng, bool final_ops = false) override; @@ -127,7 +127,7 @@ class State : public Base::State { // We currently set the threshold to 1 in qasm_controller.hpp, i.e., no parallelization virtual void set_config(const json_t &config) override; - virtual void add_metadata(ExperimentData &data) const override; + virtual void add_metadata(ExperimentResult &result) const override; // Sample n-measurement outcomes without applying the measure operation // to the system state @@ -189,7 +189,7 @@ class State : public Base::State { // Apply a supported snapshot instruction // If the input is not in allowed_snapshots an exception will be raised. - virtual void apply_snapshot(const Operations::Op &op, ExperimentData &data); + virtual void apply_snapshot(const Operations::Op &op, ExperimentResult &result); // Apply a matrix to given qubits (identity on all other qubits) // We assume matrix to be 2x2 @@ -238,26 +238,26 @@ class State : public Base::State { // Snapshot current qubit probabilities for a measurement (average) void snapshot_probabilities(const Operations::Op &op, - ExperimentData &data, + ExperimentResult &result, SnapshotDataType type); void snapshot_density_matrix(const Operations::Op &op, - ExperimentData &data, + ExperimentResult &result, SnapshotDataType type); // Snapshot the expectation value of a Pauli operator void snapshot_pauli_expval(const Operations::Op &op, - ExperimentData &data, + ExperimentResult &result, SnapshotDataType type); // Snapshot the expectation value of a matrix operator void snapshot_matrix_expval(const Operations::Op &op, - ExperimentData &data, + ExperimentResult &result, SnapshotDataType type); // Snapshot the state vector void snapshot_state(const Operations::Op &op, - ExperimentData &data, + ExperimentResult &result, std::string name = ""); //----------------------------------------------------------------------- @@ -431,11 +431,11 @@ void State::set_config(const json_t &config) { MPS::set_sample_measure_shots_thresh(10); } -void State::add_metadata(ExperimentData &data) const { - data.add_metadata("matrix_product_state_truncation_threshold", +void State::add_metadata(ExperimentResult &result) const { + result.add_metadata("matrix_product_state_truncation_threshold", MPS_Tensor::get_truncation_threshold()); - data.add_metadata("matrix_product_state_max_bond_dimension", + result.add_metadata("matrix_product_state_max_bond_dimension", MPS_Tensor::get_max_bond_dimension()); } @@ -444,7 +444,7 @@ void State::add_metadata(ExperimentData &data) const { //========================================================================= void State::apply_ops(const std::vector &ops, - ExperimentData &data, + ExperimentResult &result, RngEngine &rng, bool final_ops) { // Simple loop over vector of input operations @@ -472,7 +472,7 @@ void State::apply_ops(const std::vector &ops, apply_gate(op); break; case Operations::OpType::snapshot: - apply_snapshot(op, data); + apply_snapshot(op, result); break; case Operations::OpType::matrix: apply_matrix(op.qubits, op.mats[0]); @@ -493,7 +493,7 @@ void State::apply_ops(const std::vector &ops, //========================================================================= void State::snapshot_pauli_expval(const Operations::Op &op, - ExperimentData &data, + ExperimentResult &result, SnapshotDataType type){ if (op.params_expval_pauli.empty()) { throw std::invalid_argument("Invalid expval snapshot (Pauli components are empty)."); @@ -513,21 +513,21 @@ void State::snapshot_pauli_expval(const Operations::Op &op, Utils::chop_inplace(expval, MPS::get_json_chop_threshold()); switch (type) { case SnapshotDataType::average: - data.add_average_snapshot("expectation_value", op.string_params[0], + result.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], + result.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); + result.data.add_pershot_snapshot("expectation_values", op.string_params[0], expval); break; } } void State::snapshot_matrix_expval(const Operations::Op &op, - ExperimentData &data, + ExperimentResult &result, SnapshotDataType type){ if (op.params_expval_matrix.empty()) { throw std::invalid_argument("Invalid matrix snapshot (components are empty)."); @@ -552,42 +552,42 @@ void State::snapshot_matrix_expval(const Operations::Op &op, Utils::chop_inplace(expval, MPS::get_json_chop_threshold()); switch (type) { case SnapshotDataType::average: - data.add_average_snapshot("expectation_value", op.string_params[0], + result.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], + result.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); + result.data.add_pershot_snapshot("expectation_values", op.string_params[0], expval); break; } } void State::snapshot_state(const Operations::Op &op, - ExperimentData &data, + ExperimentResult &result, std::string name) { cvector_t statevector; qreg_.full_state_vector(statevector); - data.add_pershot_snapshot("statevector", op.string_params[0], statevector); + result.data.add_pershot_snapshot("statevector", op.string_params[0], statevector); } void State::snapshot_probabilities(const Operations::Op &op, - ExperimentData &data, + ExperimentResult &result, SnapshotDataType type) { rvector_t prob_vector; qreg_.get_probabilities_vector(prob_vector, op.qubits); auto probs = Utils::vec2ket(prob_vector, MPS::get_json_chop_threshold(), 16); bool variance = type == SnapshotDataType::average_var; - data.add_average_snapshot("probabilities", op.string_params[0], + result.data.add_average_snapshot("probabilities", op.string_params[0], BaseState::creg_.memory_hex(), probs, variance); } void State::snapshot_density_matrix(const Operations::Op &op, - ExperimentData &data, + ExperimentResult &result, SnapshotDataType type) { cmatrix_t reduced_state; if (op.qubits.empty()) { @@ -600,15 +600,15 @@ void State::snapshot_density_matrix(const Operations::Op &op, // Add density matrix to result data switch (type) { case SnapshotDataType::average: - data.add_average_snapshot("density_matrix", op.string_params[0], + result.data.add_average_snapshot("density_matrix", op.string_params[0], BaseState::creg_.memory_hex(), std::move(reduced_state), false); break; case SnapshotDataType::average_var: - data.add_average_snapshot("density_matrix", op.string_params[0], + result.data.add_average_snapshot("density_matrix", op.string_params[0], BaseState::creg_.memory_hex(), std::move(reduced_state), true); break; case SnapshotDataType::pershot: - data.add_pershot_snapshot("density_matrix", op.string_params[0], std::move(reduced_state)); + result.data.add_pershot_snapshot("density_matrix", op.string_params[0], std::move(reduced_state)); break; } } @@ -849,7 +849,7 @@ std::vector State:: return all_samples; } -void State::apply_snapshot(const Operations::Op &op, ExperimentData &data) { +void State::apply_snapshot(const Operations::Op &op, ExperimentResult &result) { // Look for snapshot type in snapshotset auto it = snapshotset_.find(op.name); if (it == snapshotset_.end()) @@ -857,47 +857,47 @@ void State::apply_snapshot(const Operations::Op &op, ExperimentData &data) { op.name + "\'."); switch (it -> second) { case Snapshots::statevector: { - snapshot_state(op, data, "statevector"); + snapshot_state(op, result, "statevector"); break; } case Snapshots::cmemory: - BaseState::snapshot_creg_memory(op, data); + BaseState::snapshot_creg_memory(op, result); break; case Snapshots::cregister: - BaseState::snapshot_creg_register(op, data); + BaseState::snapshot_creg_register(op, result); break; case Snapshots::probs: { // get probs as hexadecimal - snapshot_probabilities(op, data, SnapshotDataType::average); + snapshot_probabilities(op, result, SnapshotDataType::average); break; } case Snapshots::densmat: { - snapshot_density_matrix(op, data, SnapshotDataType::average); + snapshot_density_matrix(op, result, SnapshotDataType::average); } break; case Snapshots::expval_pauli: { - snapshot_pauli_expval(op, data, SnapshotDataType::average); + snapshot_pauli_expval(op, result, SnapshotDataType::average); } break; case Snapshots::expval_matrix: { - snapshot_matrix_expval(op, data, SnapshotDataType::average); + snapshot_matrix_expval(op, result, SnapshotDataType::average); } break; case Snapshots::probs_var: { // get probs as hexadecimal - snapshot_probabilities(op, data, SnapshotDataType::average_var); + snapshot_probabilities(op, result, SnapshotDataType::average_var); } break; case Snapshots::densmat_var: { - snapshot_density_matrix(op, data, SnapshotDataType::average_var); + snapshot_density_matrix(op, result, SnapshotDataType::average_var); } break; case Snapshots::expval_pauli_var: { - snapshot_pauli_expval(op, data, SnapshotDataType::average_var); + snapshot_pauli_expval(op, result, SnapshotDataType::average_var); } break; case Snapshots::expval_matrix_var: { - snapshot_matrix_expval(op, data, SnapshotDataType::average_var); + snapshot_matrix_expval(op, result, SnapshotDataType::average_var); } break; case Snapshots::expval_pauli_shot: { - snapshot_pauli_expval(op, data, SnapshotDataType::pershot); + snapshot_pauli_expval(op, result, SnapshotDataType::pershot); } break; case Snapshots::expval_matrix_shot: { - snapshot_matrix_expval(op, data, SnapshotDataType::pershot); + snapshot_matrix_expval(op, result, SnapshotDataType::pershot); } break; default: // We shouldn't get here unless there is a bug in the snapshotset diff --git a/src/simulators/stabilizer/stabilizer_state.hpp b/src/simulators/stabilizer/stabilizer_state.hpp index e73079f5e8..262d4350e0 100644 --- a/src/simulators/stabilizer/stabilizer_state.hpp +++ b/src/simulators/stabilizer/stabilizer_state.hpp @@ -79,7 +79,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. virtual void apply_ops(const std::vector &ops, - ExperimentData &data, + ExperimentResult &result, RngEngine &rng, bool final_ops = false) override; @@ -131,7 +131,7 @@ class State : public Base::State { // Apply a supported snapshot instruction // If the input is not in allowed_snapshots an exeption will be raised. - virtual void apply_snapshot(const Operations::Op &op, ExperimentData &data); + virtual void apply_snapshot(const Operations::Op &op, ExperimentResult &result); //----------------------------------------------------------------------- // Measurement Helpers @@ -150,11 +150,11 @@ class State : public Base::State { // Snapshot the stabilizer state of the simulator. // This returns a list of stabilizer generators - void snapshot_stabilizer(const Operations::Op &op, ExperimentData &data); + void snapshot_stabilizer(const Operations::Op &op, ExperimentResult &result); // Snapshot current qubit probabilities for a measurement (average) void snapshot_probabilities(const Operations::Op &op, - ExperimentData &data, + ExperimentResult &result, bool variance); void snapshot_probabilities_auxiliary(const reg_t& qubits, @@ -164,7 +164,7 @@ class State : public Base::State { // Snapshot the expectation value of a Pauli operator void snapshot_pauli_expval(const Operations::Op &op, - ExperimentData &data, + ExperimentResult &result, SnapshotDataType type); //----------------------------------------------------------------------- @@ -276,7 +276,7 @@ void State::set_config(const json_t &config) { //========================================================================= void State::apply_ops(const std::vector &ops, - ExperimentData &data, + ExperimentResult &result, RngEngine &rng, bool final_ops) { // Simple loop over vector of input operations for (const auto &op: ops) { @@ -300,7 +300,7 @@ void State::apply_ops(const std::vector &ops, apply_gate(op); break; case Operations::OpType::snapshot: - apply_snapshot(op, data); + apply_snapshot(op, result); break; default: throw std::invalid_argument("Stabilizer::State::invalid instruction \'" + @@ -437,7 +437,7 @@ std::vector State::sample_measure(const reg_t &qubits, //========================================================================= void State::apply_snapshot(const Operations::Op &op, - ExperimentData &data) { + ExperimentResult &result) { // Look for snapshot type in snapshotset auto it = snapshotset_.find(op.name); @@ -446,28 +446,28 @@ void State::apply_snapshot(const Operations::Op &op, op.name + "\'."); switch (it->second) { case Snapshots::stabilizer: - snapshot_stabilizer(op, data); + snapshot_stabilizer(op, result); break; case Snapshots::cmemory: - BaseState::snapshot_creg_memory(op, data); + BaseState::snapshot_creg_memory(op, result); break; case Snapshots::cregister: - BaseState::snapshot_creg_register(op, data); + BaseState::snapshot_creg_register(op, result); break; case Snapshots::probs: { - snapshot_probabilities(op, data, false); + snapshot_probabilities(op, result, false); } break; case Snapshots::probs_var: { - snapshot_probabilities(op, data, true); + snapshot_probabilities(op, result, true); } break; case Snapshots::expval_pauli: { - snapshot_pauli_expval(op, data, SnapshotDataType::average); + snapshot_pauli_expval(op, result, SnapshotDataType::average); } break; case Snapshots::expval_pauli_var: { - snapshot_pauli_expval(op, data, SnapshotDataType::average_var); + snapshot_pauli_expval(op, result, SnapshotDataType::average_var); } break; case Snapshots::expval_pauli_shot: { - snapshot_pauli_expval(op, data, SnapshotDataType::pershot); + snapshot_pauli_expval(op, result, SnapshotDataType::pershot); } break; default: // We shouldn't get here unless there is a bug in the snapshotset @@ -477,19 +477,19 @@ void State::apply_snapshot(const Operations::Op &op, } -void State::snapshot_stabilizer(const Operations::Op &op, ExperimentData &data) { +void State::snapshot_stabilizer(const Operations::Op &op, ExperimentResult &result) { // We don't want to snapshot the full Clifford table, only the // stabilizer part. First Convert simulator clifford table to JSON json_t clifford = BaseState::qreg_; // Then extract the stabilizer generator list - data.add_pershot_snapshot("stabilizer", + result.data.add_pershot_snapshot("stabilizer", op.string_params[0], clifford["stabilizers"]); } void State::snapshot_probabilities(const Operations::Op &op, - ExperimentData &data, + ExperimentResult &result, bool variance) { // Check number of qubits being measured is less than 64. // otherwise we cant use 64-bit int logic. @@ -511,7 +511,7 @@ void State::snapshot_probabilities(const Operations::Op &op, op.qubits, std::string(op.qubits.size(), 'X'), 1, probs); // Add snapshot to data - data.add_average_snapshot("probabilities", op.string_params[0], + result.data.add_average_snapshot("probabilities", op.string_params[0], BaseState::creg_.memory_hex(), probs, variance); } @@ -561,7 +561,7 @@ void State::snapshot_probabilities_auxiliary(const reg_t &qubits, } void State::snapshot_pauli_expval(const Operations::Op &op, - ExperimentData &data, SnapshotDataType type) { + ExperimentResult &result, SnapshotDataType type) { // Check empty edge case if (op.params_expval_pauli.empty()) { throw std::invalid_argument( @@ -611,15 +611,15 @@ void State::snapshot_pauli_expval(const Operations::Op &op, Utils::chop_inplace(expval, json_chop_threshold_); switch (type) { case SnapshotDataType::average: - data.add_average_snapshot("expectation_value", op.string_params[0], + result.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], + result.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); + result.data.add_pershot_snapshot("expectation_values", op.string_params[0], expval); break; } } diff --git a/src/simulators/state.hpp b/src/simulators/state.hpp index 3df92e4b1e..2d6a03074c 100644 --- a/src/simulators/state.hpp +++ b/src/simulators/state.hpp @@ -19,7 +19,7 @@ #include "framework/opset.hpp" #include "framework/types.hpp" #include "framework/creg.hpp" -#include "framework/results/experiment_data.hpp" +#include "framework/results/experiment_result.hpp" namespace AER { namespace Base { @@ -108,7 +108,7 @@ class State { // to the state after this sequence, so the state can be modified at the // end of the instructions. virtual void apply_ops(const std::vector &ops, - ExperimentData &data, + ExperimentResult &result, RngEngine &rng, bool final_ops = false) = 0; @@ -137,7 +137,7 @@ class State { //----------------------------------------------------------------------- // Every state can add information to the metadata structure - virtual void add_metadata(ExperimentData &data) const { + virtual void add_metadata(ExperimentResult &result) const { } //----------------------------------------------------------------------- @@ -174,8 +174,8 @@ class State { const std::string &memory_hex, const std::string ®ister_hex); - // Add current creg classical bit values to a ExperimentData container - void add_creg_to_data(ExperimentData &data) const; + // Add current creg classical bit values to a ExperimentResult container + void add_creg_to_data(ExperimentResult &result) const; //----------------------------------------------------------------------- // Standard snapshots @@ -183,15 +183,15 @@ class State { // Snapshot the current statevector (single-shot) // if type_label is the empty string the operation type will be used for the type - void snapshot_state(const Operations::Op &op, ExperimentData &data, + void snapshot_state(const Operations::Op &op, ExperimentResult &result, std::string name = "") const; // Snapshot the classical memory bits state (single-shot) - void snapshot_creg_memory(const Operations::Op &op, ExperimentData &data, + void snapshot_creg_memory(const Operations::Op &op, ExperimentResult &result, std::string name = "memory") const; // Snapshot the classical register bits state (single-shot) - void snapshot_creg_register(const Operations::Op &op, ExperimentData &data, + void snapshot_creg_register(const Operations::Op &op, ExperimentResult &result, std::string name = "register") const; //----------------------------------------------------------------------- @@ -274,18 +274,18 @@ void State::initialize_creg(uint_t num_memory, template void State::snapshot_state(const Operations::Op &op, - ExperimentData &data, + ExperimentResult &result, std::string name) const { name = (name.empty()) ? op.name : name; - data.add_pershot_snapshot(name, op.string_params[0], qreg_); + result.data.add_pershot_snapshot(name, op.string_params[0], qreg_); } template void State::snapshot_creg_memory(const Operations::Op &op, - ExperimentData &data, + ExperimentResult &result, std::string name) const { - data.add_pershot_snapshot(name, + result.data.add_pershot_snapshot(name, op.string_params[0], creg_.memory_hex()); } @@ -293,24 +293,24 @@ void State::snapshot_creg_memory(const Operations::Op &op, template void State::snapshot_creg_register(const Operations::Op &op, - ExperimentData &data, + ExperimentResult &result, std::string name) const { - data.add_pershot_snapshot(name, + result.data.add_pershot_snapshot(name, op.string_params[0], creg_.register_hex()); } template -void State::add_creg_to_data(ExperimentData &data) const { +void State::add_creg_to_data(ExperimentResult &result) const { if (creg_.memory_size() > 0) { std::string memory_hex = creg_.memory_hex(); - data.add_memory_count(memory_hex); - data. add_pershot_memory(memory_hex); + result.data.add_memory_count(memory_hex); + result.data.add_pershot_memory(memory_hex); } // Register bits value if (creg_.register_size() > 0) { - data. add_pershot_register(creg_.register_hex()); + result.data.add_pershot_register(creg_.register_hex()); } } //------------------------------------------------------------------------- diff --git a/src/simulators/statevector/statevector_state.hpp b/src/simulators/statevector/statevector_state.hpp index daeecf89bb..ddb3695c0e 100755 --- a/src/simulators/statevector/statevector_state.hpp +++ b/src/simulators/statevector/statevector_state.hpp @@ -104,7 +104,7 @@ class State : public Base::State { // Apply a sequence of operations by looping over list // If the input is not in allowed_ops an exception will be raised. virtual void apply_ops(const std::vector &ops, - ExperimentData &data, + ExperimentResult &result, RngEngine &rng, bool final_ops = false) override; @@ -171,7 +171,7 @@ class State : public Base::State { // Apply a supported snapshot instruction // If the input is not in allowed_snapshots an exeption will be raised. - virtual void apply_snapshot(const Operations::Op &op, ExperimentData &data, bool last_op = false); + virtual void apply_snapshot(const Operations::Op &op, ExperimentResult &result, bool last_op = false); // Apply a matrix to given qubits (identity on all other qubits) void apply_matrix(const Operations::Op &op); @@ -229,19 +229,19 @@ class State : public Base::State { //----------------------------------------------------------------------- // Snapshot current qubit probabilities for a measurement (average) - void snapshot_probabilities(const Operations::Op &op, ExperimentData &data, + void snapshot_probabilities(const Operations::Op &op, ExperimentResult &result, SnapshotDataType type); // Snapshot the expectation value of a Pauli operator - void snapshot_pauli_expval(const Operations::Op &op, ExperimentData &data, + void snapshot_pauli_expval(const Operations::Op &op, ExperimentResult &result, SnapshotDataType type); // Snapshot the expectation value of a matrix operator - void snapshot_matrix_expval(const Operations::Op &op, ExperimentData &data, + void snapshot_matrix_expval(const Operations::Op &op, ExperimentResult &result, SnapshotDataType type); // Snapshot reduced density matrix - void snapshot_density_matrix(const Operations::Op &op, ExperimentData &data, + void snapshot_density_matrix(const Operations::Op &op, ExperimentResult &result, SnapshotDataType type); // Return the reduced density matrix for the simulator @@ -464,7 +464,7 @@ void State::set_config(const json_t &config) { template void State::apply_ops(const std::vector &ops, - ExperimentData &data, + ExperimentResult &result, RngEngine &rng, bool final_ops) { @@ -494,7 +494,7 @@ void State::apply_ops(const std::vector &ops, apply_gate(op); break; case Operations::OpType::snapshot: - apply_snapshot(op, data, final_ops && ops.size() == i + 1); + apply_snapshot(op, result, final_ops && ops.size() == i + 1); break; case Operations::OpType::matrix: apply_matrix(op); @@ -523,7 +523,7 @@ void State::apply_ops(const std::vector &ops, template void State::apply_snapshot(const Operations::Op &op, - ExperimentData &data, + ExperimentResult &result, bool last_op) { // Look for snapshot type in snapshotset @@ -534,48 +534,48 @@ void State::apply_snapshot(const Operations::Op &op, switch (it->second) { case Snapshots::statevector: if (last_op) { - data.add_pershot_snapshot("statevector", op.string_params[0], BaseState::qreg_.move_to_vector()); + result.data.add_pershot_snapshot("statevector", op.string_params[0], BaseState::qreg_.move_to_vector()); } else { - data.add_pershot_snapshot("statevector", op.string_params[0], BaseState::qreg_.copy_to_vector()); + result.data.add_pershot_snapshot("statevector", op.string_params[0], BaseState::qreg_.copy_to_vector()); } break; case Snapshots::cmemory: - BaseState::snapshot_creg_memory(op, data); + BaseState::snapshot_creg_memory(op, result); break; case Snapshots::cregister: - BaseState::snapshot_creg_register(op, data); + BaseState::snapshot_creg_register(op, result); break; case Snapshots::probs: { // get probs as hexadecimal - snapshot_probabilities(op, data, SnapshotDataType::average); + snapshot_probabilities(op, result, SnapshotDataType::average); } break; case Snapshots::densmat: { - snapshot_density_matrix(op, data, SnapshotDataType::average); + snapshot_density_matrix(op, result, SnapshotDataType::average); } break; case Snapshots::expval_pauli: { - snapshot_pauli_expval(op, data, SnapshotDataType::average); + snapshot_pauli_expval(op, result, SnapshotDataType::average); } break; case Snapshots::expval_matrix: { - snapshot_matrix_expval(op, data, SnapshotDataType::average); + snapshot_matrix_expval(op, result, SnapshotDataType::average); } break; case Snapshots::probs_var: { // get probs as hexadecimal - snapshot_probabilities(op, data, SnapshotDataType::average_var); + snapshot_probabilities(op, result, SnapshotDataType::average_var); } break; case Snapshots::densmat_var: { - snapshot_density_matrix(op, data, SnapshotDataType::average_var); + snapshot_density_matrix(op, result, SnapshotDataType::average_var); } break; case Snapshots::expval_pauli_var: { - snapshot_pauli_expval(op, data, SnapshotDataType::average_var); + snapshot_pauli_expval(op, result, SnapshotDataType::average_var); } break; case Snapshots::expval_matrix_var: { - snapshot_matrix_expval(op, data, SnapshotDataType::average_var); + snapshot_matrix_expval(op, result, SnapshotDataType::average_var); } break; case Snapshots::expval_pauli_shot: { - snapshot_pauli_expval(op, data, SnapshotDataType::pershot); + snapshot_pauli_expval(op, result, SnapshotDataType::pershot); } break; case Snapshots::expval_matrix_shot: { - snapshot_matrix_expval(op, data, SnapshotDataType::pershot); + snapshot_matrix_expval(op, result, SnapshotDataType::pershot); } break; default: // We shouldn't get here unless there is a bug in the snapshotset @@ -587,19 +587,19 @@ void State::apply_snapshot(const Operations::Op &op, template void State::snapshot_probabilities(const Operations::Op &op, - ExperimentData &data, + ExperimentResult &result, SnapshotDataType type) { // get probs as hexadecimal auto probs = Utils::vec2ket(measure_probs(op.qubits), json_chop_threshold_, 16); bool variance = type == SnapshotDataType::average_var; - data.add_average_snapshot("probabilities", op.string_params[0], + result.data.add_average_snapshot("probabilities", op.string_params[0], BaseState::creg_.memory_hex(), probs, variance); } template void State::snapshot_pauli_expval(const Operations::Op &op, - ExperimentData &data, + ExperimentResult &result, SnapshotDataType type) { // Check empty edge case if (op.params_expval_pauli.empty()) { @@ -619,15 +619,15 @@ void State::snapshot_pauli_expval(const Operations::Op &op, Utils::chop_inplace(expval, json_chop_threshold_); switch (type) { case SnapshotDataType::average: - data.add_average_snapshot("expectation_value", op.string_params[0], + result.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], + result.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], + result.data.add_pershot_snapshot("expectation_values", op.string_params[0], expval); break; } @@ -635,7 +635,7 @@ void State::snapshot_pauli_expval(const Operations::Op &op, template void State::snapshot_matrix_expval(const Operations::Op &op, - ExperimentData &data, + ExperimentResult &result, SnapshotDataType type) { // Check empty edge case if (op.params_expval_matrix.empty()) { @@ -681,15 +681,15 @@ void State::snapshot_matrix_expval(const Operations::Op &op, Utils::chop_inplace(expval, json_chop_threshold_); switch (type) { case SnapshotDataType::average: - data.add_average_snapshot("expectation_value", op.string_params[0], + result.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], + result.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], + result.data.add_pershot_snapshot("expectation_values", op.string_params[0], expval); break; } @@ -699,7 +699,7 @@ void State::snapshot_matrix_expval(const Operations::Op &op, template void State::snapshot_density_matrix(const Operations::Op &op, - ExperimentData &data, + ExperimentResult &result, SnapshotDataType type) { cmatrix_t reduced_state; @@ -714,17 +714,17 @@ void State::snapshot_density_matrix(const Operations::Op &op, // Add density matrix to result data switch (type) { case SnapshotDataType::average: - data.add_average_snapshot("density_matrix", op.string_params[0], + result.data.add_average_snapshot("density_matrix", op.string_params[0], BaseState::creg_.memory_hex(), std::move(reduced_state), false); break; case SnapshotDataType::average_var: - data.add_average_snapshot("density_matrix", op.string_params[0], + result.data.add_average_snapshot("density_matrix", op.string_params[0], BaseState::creg_.memory_hex(), std::move(reduced_state), true); break; case SnapshotDataType::pershot: - data.add_pershot_snapshot("density_matrix", op.string_params[0], + result.data.add_pershot_snapshot("density_matrix", op.string_params[0], std::move(reduced_state)); break; } diff --git a/src/simulators/superoperator/superoperator_state.hpp b/src/simulators/superoperator/superoperator_state.hpp index e7a48fee82..64cb42d895 100755 --- a/src/simulators/superoperator/superoperator_state.hpp +++ b/src/simulators/superoperator/superoperator_state.hpp @@ -73,7 +73,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. virtual void apply_ops(const std::vector &ops, - ExperimentData &data, + ExperimentResult &result, RngEngine &rng, bool final_ops = false) override; @@ -118,7 +118,7 @@ class State : public Base::State { // Apply a supported snapshot instruction // If the input is not in allowed_snapshots an exeption will be raised. - virtual void apply_snapshot(const Operations::Op &op, ExperimentData &data); + virtual void apply_snapshot(const Operations::Op &op, ExperimentResult &result); // Apply a matrix to given qubits (identity on all other qubits) void apply_matrix(const reg_t &qubits, const cmatrix_t &mat); @@ -209,7 +209,7 @@ const stringmap_t State::gateset_({ template void State::apply_ops(const std::vector &ops, - ExperimentData &data, + ExperimentResult &result, RngEngine &rng, bool final_ops) { // Simple loop over vector of input operations @@ -239,7 +239,7 @@ void State::apply_ops(const std::vector &ops, op.qubits, Utils::vectorize_matrix(op.mats[0])); break; case Operations::OpType::snapshot: - apply_snapshot(op, data); + apply_snapshot(op, result); break; default: throw std::invalid_argument( @@ -465,10 +465,10 @@ void State::apply_gate_u3(const uint_t qubit, double theta, template void State::apply_snapshot(const Operations::Op &op, - ExperimentData &data) { + ExperimentResult &result) { // Look for snapshot type in snapshotset if (op.name == "superopertor" || op.name == "state") { - BaseState::snapshot_state(op, data, "superoperator"); + BaseState::snapshot_state(op, result, "superoperator"); } else { throw std::invalid_argument( "QubitSuperoperator::State::invalid snapshot instruction \'" + op.name + diff --git a/src/simulators/unitary/unitary_state.hpp b/src/simulators/unitary/unitary_state.hpp index 74d47cf065..1c96b8a49c 100755 --- a/src/simulators/unitary/unitary_state.hpp +++ b/src/simulators/unitary/unitary_state.hpp @@ -74,7 +74,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. virtual void apply_ops(const std::vector &ops, - ExperimentData &data, RngEngine &rng, + ExperimentResult &result, RngEngine &rng, bool final_ops = false) override; // Initializes an n-qubit unitary to the identity matrix @@ -118,7 +118,7 @@ class State : public Base::State { // Apply a supported snapshot instruction // If the input is not in allowed_snapshots an exeption will be raised. - virtual void apply_snapshot(const Operations::Op &op, ExperimentData &data); + virtual void apply_snapshot(const Operations::Op &op, ExperimentResult &result); // Apply a matrix to given qubits (identity on all other qubits) void apply_matrix(const reg_t &qubits, const cmatrix_t &mat); @@ -230,7 +230,7 @@ const stringmap_t State::gateset_({ template void State::apply_ops( - const std::vector &ops, ExperimentData &data, + const std::vector &ops, ExperimentResult &result, RngEngine &rng, bool final_ops) { // Simple loop over vector of input operations for (const auto &op : ops) { @@ -243,7 +243,7 @@ void State::apply_ops( apply_gate(op); break; case Operations::OpType::snapshot: - apply_snapshot(op, data); + apply_snapshot(op, result); break; case Operations::OpType::matrix: apply_matrix(op.qubits, op.mats[0]); @@ -462,12 +462,12 @@ void State::apply_gate_mcu3(const reg_t &qubits, double theta, template void State::apply_snapshot(const Operations::Op &op, - ExperimentData &data) { + ExperimentResult &result) { // Look for snapshot type in snapshotset if (op.name == "unitary" || op.name == "state") { - data.add_pershot_snapshot("unitary", op.string_params[0], + result.data.add_pershot_snapshot("unitary", op.string_params[0], BaseState::qreg_.copy_to_matrix()); - BaseState::snapshot_state(op, data); + BaseState::snapshot_state(op, result); } else { throw std::invalid_argument( "Unitary::State::invalid snapshot instruction \'" + op.name + "\'."); diff --git a/src/transpile/basic_opts.hpp b/src/transpile/basic_opts.hpp index 3e6c37c8c7..2e6b50591d 100644 --- a/src/transpile/basic_opts.hpp +++ b/src/transpile/basic_opts.hpp @@ -32,13 +32,13 @@ class ReduceBarrier : public CircuitOptimization { void optimize_circuit(Circuit& circ, Noise::NoiseModel& noise, const opset_t &opset, - ExperimentData &data) const override; + ExperimentResult &result) const override; }; void ReduceBarrier::optimize_circuit(Circuit& circ, Noise::NoiseModel& noise, const opset_t &allowed_opset, - ExperimentData &data) const { + ExperimentResult &result) const { // Position of first sampling op size_t idx = 0; size_t new_measure_pos = circ.first_measure_pos; @@ -64,13 +64,13 @@ class Debug : public CircuitOptimization { void optimize_circuit(Circuit& circ, Noise::NoiseModel& noise, const opset_t &opset, - ExperimentData &data) const override; + ExperimentResult &result) const override; }; void Debug::optimize_circuit(Circuit& circ, Noise::NoiseModel& noise, const opset_t &allowed_opset, - ExperimentData &data) const { + ExperimentResult &result) const { oplist_t::iterator it = circ.ops.begin(); while (it != circ.ops.end()) { diff --git a/src/transpile/circuitopt.hpp b/src/transpile/circuitopt.hpp index 18843cd9ed..1c5852532b 100644 --- a/src/transpile/circuitopt.hpp +++ b/src/transpile/circuitopt.hpp @@ -40,7 +40,7 @@ class CircuitOptimization { virtual void optimize_circuit(Circuit& circ, Noise::NoiseModel& noise, const Operations::OpSet &opset, - ExperimentData &data) const = 0; + ExperimentResult &result) const = 0; virtual void set_config(const json_t &config); diff --git a/src/transpile/delay_measure.hpp b/src/transpile/delay_measure.hpp index 36f599b839..ece6209ba0 100644 --- a/src/transpile/delay_measure.hpp +++ b/src/transpile/delay_measure.hpp @@ -36,7 +36,7 @@ class DelayMeasure : public CircuitOptimization { void optimize_circuit(Circuit& circ, Noise::NoiseModel& noise, const Operations::OpSet &opset, - ExperimentData &data) const override; + ExperimentResult &result) const override; private: // show debug info @@ -55,7 +55,7 @@ void DelayMeasure::set_config(const json_t &config) { void DelayMeasure::optimize_circuit(Circuit& circ, Noise::NoiseModel& noise, const Operations::OpSet &allowed_opset, - ExperimentData &data) const { + ExperimentResult &result) const { // If there are no measure instructions or circuit already has // no instructions after measurement, or there is quantum noise // we don't need to optimize @@ -119,7 +119,7 @@ void DelayMeasure::optimize_circuit(Circuit& circ, circ.ops.insert(circ.ops.end(), meas_ops.begin(), meas_ops.end()); if (verbose_) - data.add_metadata("delay_measure_verbose", circ.ops); + result.add_metadata("delay_measure_verbose", circ.ops); } diff --git a/src/transpile/fusion.hpp b/src/transpile/fusion.hpp index b19076f7f6..3005c7cd5c 100644 --- a/src/transpile/fusion.hpp +++ b/src/transpile/fusion.hpp @@ -63,7 +63,7 @@ class Fusion : public CircuitOptimization { void optimize_circuit(Circuit& circ, Noise::NoiseModel& noise, const opset_t &allowed_opset, - ExperimentData &data) const override; + ExperimentResult &result) const override; // Qubit threshold for activating fusion pass uint_t max_qubit; @@ -87,7 +87,7 @@ class Fusion : public CircuitOptimization { const int fusion_start, const int fusion_end, uint_t max_fused_qubits, - ExperimentData &data, + ExperimentResult &result, Method method) const; // Aggregate a subcircuit of operations into a single operation @@ -152,7 +152,7 @@ void Fusion::set_config(const json_t &config) { void Fusion::optimize_circuit(Circuit& circ, Noise::NoiseModel& noise, const opset_t &allowed_opset, - ExperimentData &data) const { + ExperimentResult &result) const { // Check if fusion should be skipped if (!active || !allowed_opset.contains(optype_t::matrix)) return; @@ -195,7 +195,7 @@ void Fusion::optimize_circuit(Circuit& circ, // for the density matrix simulator // Check if circuit size is above threshold if (circ.num_qubits < qubit_threshold) { - data.add_metadata("fusion", metadata); + result.add_metadata("fusion", metadata); return; } // Apply fusion @@ -207,13 +207,13 @@ void Fusion::optimize_circuit(Circuit& circ, continue; if (!can_apply_fusion(circ.ops[op_idx], max_fused_qubits, method)) { applied |= fusion_start != op_idx && aggregate_operations( - circ.ops, fusion_start, op_idx, max_fused_qubits, data, method); + circ.ops, fusion_start, op_idx, max_fused_qubits, result, method); fusion_start = op_idx + 1; } } if (fusion_start < circ.ops.size() && - aggregate_operations(circ.ops, fusion_start, circ.ops.size(), max_fused_qubits, data, method)) + aggregate_operations(circ.ops, fusion_start, circ.ops.size(), max_fused_qubits, result, method)) applied = true; if (applied) { @@ -241,7 +241,7 @@ void Fusion::optimize_circuit(Circuit& circ, } auto timer_stop = clock_t::now(); metadata["time_taken"] = std::chrono::duration(timer_stop - timer_start).count(); - data.add_metadata("fusion", metadata); + result.add_metadata("fusion", metadata); } bool Fusion::can_ignore(const op_t& op) const { @@ -296,13 +296,13 @@ op_t Fusion::generate_fusion_operation(const std::vector& fusioned_ops, Method method) const { // Run simulation RngEngine dummy_rng; - ExperimentData dummy_data; + ExperimentResult dummy_result; if (method == Method::unitary) { // Unitary simulation QubitUnitary::State<> unitary_simulator; unitary_simulator.initialize_qreg(qubits.size()); - unitary_simulator.apply_ops(fusioned_ops, dummy_data, dummy_rng); + unitary_simulator.apply_ops(fusioned_ops, dummy_result, dummy_rng); return Operations::make_unitary(qubits, unitary_simulator.qreg().move_to_matrix(), std::string("fusion")); } @@ -311,7 +311,7 @@ op_t Fusion::generate_fusion_operation(const std::vector& fusioned_ops, // simulator QubitSuperoperator::State<> superop_simulator; superop_simulator.initialize_qreg(qubits.size()); - superop_simulator.apply_ops(fusioned_ops, dummy_data, dummy_rng); + superop_simulator.apply_ops(fusioned_ops, dummy_result, dummy_rng); auto superop = superop_simulator.qreg().move_to_matrix(); if (method == Method::superop) { @@ -328,7 +328,7 @@ bool Fusion::aggregate_operations(oplist_t& ops, const int fusion_start, const int fusion_end, uint_t max_fused_qubits, - ExperimentData &data, + ExperimentResult &result, Method method) const { // costs[i]: estimated cost to execute from 0-th to i-th in original.ops diff --git a/src/transpile/truncate_qubits.hpp b/src/transpile/truncate_qubits.hpp index b2029ff7c6..38bed3ff32 100644 --- a/src/transpile/truncate_qubits.hpp +++ b/src/transpile/truncate_qubits.hpp @@ -33,7 +33,7 @@ class TruncateQubits : public CircuitOptimization { void optimize_circuit(Circuit& circ, Noise::NoiseModel& noise, const Operations::OpSet &opset, - ExperimentData &data) const override; + ExperimentResult &result) const override; private: // check if this optimization can be applied @@ -80,7 +80,7 @@ void TruncateQubits::set_config(const json_t &config) { void TruncateQubits::optimize_circuit(Circuit& circ, Noise::NoiseModel& noise, const Operations::OpSet &allowed_opset, - ExperimentData &data) const { + ExperimentResult &result) const { // Check if circuit operations allow remapping // Remapped circuits must return the same output data as the @@ -115,7 +115,7 @@ void TruncateQubits::optimize_circuit(Circuit& circ, json_t truncate_metadata; truncate_metadata["active_qubits"] = active_qubits; truncate_metadata["mapping"] = mapping; - data.add_metadata("truncate_qubits", truncate_metadata); + result.add_metadata("truncate_qubits", truncate_metadata); } } From 2c0c50b2177d10043771471256ba4f7b277a861f Mon Sep 17 00:00:00 2001 From: "Christopher J. Wood" Date: Wed, 14 Oct 2020 12:02:13 -0400 Subject: [PATCH 019/126] Add missing standard gate basis gates (#989) --- .../providers/aer/backends/qasm_simulator.py | 14 +++---- .../aer/backends/statevector_simulator.py | 2 +- .../aer/backends/unitary_simulator.py | 2 +- .../notes/basis-gates-acbc8a1a52a49413.yaml | 42 ++++++++++++++----- src/noise/noise_model.hpp | 1 + .../density_matrix/densitymatrix_state.hpp | 9 ++-- .../extended_stabilizer/ch_runner.hpp | 8 ++++ .../extended_stabilizer_state.hpp | 7 +++- src/simulators/extended_stabilizer/gates.hpp | 4 +- .../matrix_product_state.hpp | 15 +++++-- .../matrix_product_state_internal.cpp | 19 +++++---- .../matrix_product_state_internal.hpp | 3 +- .../statevector/statevector_state.hpp | 16 ++++--- .../superoperator/superoperator_state.hpp | 9 ++-- src/simulators/unitary/unitary_state.hpp | 16 ++++--- .../qasm_simulator/qasm_standard_gates.py | 42 ++++--------------- .../statevector_gates.py | 10 ++++- .../unitary_simulator/unitary_gates.py | 10 ++++- 18 files changed, 137 insertions(+), 92 deletions(-) diff --git a/qiskit/providers/aer/backends/qasm_simulator.py b/qiskit/providers/aer/backends/qasm_simulator.py index 0dc0908ba8..422c7e8118 100644 --- a/qiskit/providers/aer/backends/qasm_simulator.py +++ b/qiskit/providers/aer/backends/qasm_simulator.py @@ -248,7 +248,7 @@ class QasmSimulator(AerBackend): 'description': 'A C++ QasmQobj simulator with noise', 'coupling_map': None, 'basis_gates': [ - 'u1', 'u2', 'u3', 'p', 'r', 'rx', 'ry', 'rz', 'id', 'x', + 'u1', 'u2', 'u3', 'u', 'p', 'r', 'rx', 'ry', 'rz', 'id', 'x', 'y', 'z', 'h', 's', 'sdg', 'sx', 't', 'tdg', 'swap', 'cx', 'cy', 'cz', 'csx', 'cp', 'cu1', 'cu2', 'cu3', 'rxx', 'ryy', 'rzz', 'rzx', 'ccx', 'cswap', 'mcx', 'mcy', 'mcz', 'mcsx', @@ -400,7 +400,7 @@ def _method_configuration(method=None): config.n_qubits = config.n_qubits // 2 config.description = 'A C++ QasmQobj density matrix simulator with noise' config.basis_gates = [ - 'u1', 'u2', 'u3', 'p', 'r', 'rx', 'ry', 'rz', 'id', 'x', + 'u1', 'u2', 'u3', 'u', 'p', 'r', 'rx', 'ry', 'rz', 'id', 'x', 'y', 'z', 'h', 's', 'sdg', 'sx', 't', 'tdg', 'swap', 'cx', 'cy', 'cz', 'csx', 'cp', 'cu1', 'cu2', 'cu3', 'rxx', 'ryy', 'rzz', 'rzx', 'ccx', 'unitary', 'diagonal', 'kraus', 'superop' @@ -411,8 +411,8 @@ def _method_configuration(method=None): elif method == 'matrix_product_state': config.description = 'A C++ QasmQobj matrix product state simulator with noise' config.basis_gates = [ - 'u1', 'u2', 'u3', 'cx', 'cz', 'id', 'x', 'y', 'z', 'h', 's', - 'sdg', 't', 'tdg', 'swap', 'ccx', 'unitary', 'roerror', 'delay' + 'u1', 'u2', 'u3', 'u', 'p', 'cp', 'cx', 'cz', 'id', 'x', 'y', 'z', 'h', 's', + 'sdg', 'sx', 't', 'tdg', 'swap', 'ccx', 'unitary', 'roerror', 'delay' ] # Stabilizer method @@ -420,7 +420,7 @@ def _method_configuration(method=None): config.n_qubits = 5000 # TODO: estimate from memory config.description = 'A C++ QasmQobj Clifford stabilizer simulator with noise' config.basis_gates = [ - 'id', 'x', 'y', 'z', 'h', 's', 'sdg', 'cx', 'cy', 'cz', + 'id', 'x', 'y', 'z', 'h', 's', 'sdg', 'sx', 'cx', 'cy', 'cz', 'swap', 'roerror', 'delay' ] @@ -429,8 +429,8 @@ def _method_configuration(method=None): config.n_qubits = 63 # TODO: estimate from memory config.description = 'A C++ QasmQobj ranked stabilizer simulator with noise' config.basis_gates = [ - 'cx', 'cz', 'id', 'x', 'y', 'z', 'h', 's', 'sdg', 'swap', - 'u0', 'u1', 'ccx', 'ccz', 'roerror', 'delay' + 'cx', 'cz', 'id', 'x', 'y', 'z', 'h', 's', 'sdg', 'sx', 'swap', + 'u0', 'u1', 'p', 'ccx', 'ccz', 'roerror', 'delay' ] return config diff --git a/qiskit/providers/aer/backends/statevector_simulator.py b/qiskit/providers/aer/backends/statevector_simulator.py index f03ceab0ae..51198dddc9 100644 --- a/qiskit/providers/aer/backends/statevector_simulator.py +++ b/qiskit/providers/aer/backends/statevector_simulator.py @@ -110,7 +110,7 @@ class StatevectorSimulator(AerBackend): 'description': 'A C++ statevector simulator for QASM Qobj files', 'coupling_map': None, 'basis_gates': [ - 'u1', 'u2', 'u3', 'p', 'r', 'rx', 'ry', 'rz', 'id', 'x', + 'u1', 'u2', 'u3', 'u', 'p', 'r', 'rx', 'ry', 'rz', 'id', 'x', 'y', 'z', 'h', 's', 'sdg', 'sx', 't', 'tdg', 'swap', 'cx', 'cy', 'cz', 'csx', 'cp', 'cu1', 'cu2', 'cu3', 'rxx', 'ryy', 'rzz', 'rzx', 'ccx', 'cswap', 'mcx', 'mcy', 'mcz', 'mcsx', diff --git a/qiskit/providers/aer/backends/unitary_simulator.py b/qiskit/providers/aer/backends/unitary_simulator.py index f671d65150..bccb4ab4ea 100644 --- a/qiskit/providers/aer/backends/unitary_simulator.py +++ b/qiskit/providers/aer/backends/unitary_simulator.py @@ -116,7 +116,7 @@ class UnitarySimulator(AerBackend): 'description': 'A C++ unitary simulator for QASM Qobj files', 'coupling_map': None, 'basis_gates': [ - 'u1', 'u2', 'u3', 'p', 'r', 'rx', 'ry', 'rz', 'id', 'x', + 'u1', 'u2', 'u3', 'u', 'p', 'r', 'rx', 'ry', 'rz', 'id', 'x', 'y', 'z', 'h', 's', 'sdg', 'sx', 't', 'tdg', 'swap', 'cx', 'cy', 'cz', 'csx', 'cp', 'cu1', 'cu2', 'cu3', 'rxx', 'ryy', 'rzz', 'rzx', 'ccx', 'cswap', 'mcx', 'mcy', 'mcz', 'mcsx', diff --git a/releasenotes/notes/basis-gates-acbc8a1a52a49413.yaml b/releasenotes/notes/basis-gates-acbc8a1a52a49413.yaml index fb0b1883d0..916d720327 100644 --- a/releasenotes/notes/basis-gates-acbc8a1a52a49413.yaml +++ b/releasenotes/notes/basis-gates-acbc8a1a52a49413.yaml @@ -1,28 +1,50 @@ --- features: - | - Adds support for parameterized delay gate ``"delay"`` to the - :class:`~qiskit.providers.aer.StatevectorSimulator`, + Adds basis gate support for the :class:`qiskit.circuit.Delay` + instruction to the :class:`~qiskit.providers.aer.StatevectorSimulator`, :class:`~qiskit.providers.aer.UnitarySimulator`, and :class:`~qiskit.providers.aer.QasmSimulator`. - By default this gate is treated as an identity gate during simulation. + Note that this gate is treated as an identity gate during simulation + and the delay length parameter is ignored. - | - Adds support for parameterized phase gate ``"p"`` and controlled-phase - gate ``"cp"`` to the :class:`~qiskit.providers.aer.StatevectorSimulator`, + Adds basis gate support for the single-qubit gate + :class:`qiskit.circuit.library.UGate` to the + :class:`~qiskit.providers.aer.StatevectorSimulator`, :class:`~qiskit.providers.aer.UnitarySimulator`, and the - ``"statevector"`` and ``"density_matrix"`` methods of the + ``"statevector"``, ``"density_matrix"``, ``"matrix_product_state"``, + and ``"extended_stabilizer"`` methods of the :class:`~qiskit.providers.aer.QasmSimulator`. - | - Adds support for the multi-controlled phase gate ``"mcphase"`` to the + Adds basis gate support for the phase gate + :class:`qiskit.circuit.library.PhaseGate` to the + :class:`~qiskit.providers.aer.StatevectorSimulator`, + :class:`~qiskit.providers.aer.StatevectorSimulator`, + :class:`~qiskit.providers.aer.UnitarySimulator`, and the + ``"statevector"``, ``"density_matrix"``, ``"matrix_product_state"``, + and ``"extended_stabilizer"`` methods of the + :class:`~qiskit.providers.aer.QasmSimulator`. + - | + Adds basis gate support for the controlled-phase gate + :class:`qiskit.circuit.library.CPhaseGate` to the + :class:`~qiskit.providers.aer.StatevectorSimulator`, + :class:`~qiskit.providers.aer.StatevectorSimulator`, + :class:`~qiskit.providers.aer.UnitarySimulator`, and the + ``"statevector"``, ``"density_matrix"``, and + ``"matrix_product_state"`` methods of the + :class:`~qiskit.providers.aer.QasmSimulator`. + - | + Adds support for the multi-controlled phase gate + :class:`qiskit.circuit.library.MCPhaseGate` to the :class:`~qiskit.providers.aer.StatevectorSimulator`, :class:`~qiskit.providers.aer.UnitarySimulator`, and the ``"statevector"`` method of the :class:`~qiskit.providers.aer.QasmSimulator`. - | - Adds support for the :math:`\sqrt(X)` gate ``"sx"`` to the + Adds support for the :math:`\sqrt(X)` gate + :class:`qiskit.circuit.library.SXGate` to the class:`~qiskit.providers.aer.StatevectorSimulator`, - :class:`~qiskit.providers.aer.UnitarySimulator`, and the - ``"statevector"`` and ``"density_matrix"`` methods of the + :class:`~qiskit.providers.aer.UnitarySimulator`, and :class:`~qiskit.providers.aer.QasmSimulator`. deprecations: - | diff --git a/src/noise/noise_model.hpp b/src/noise/noise_model.hpp index 0b9b86030c..36ad41c52e 100644 --- a/src/noise/noise_model.hpp +++ b/src/noise/noise_model.hpp @@ -260,6 +260,7 @@ class NoiseModel { const stringmap_t NoiseModel::param_gate_table_ = { + {"u", ParamGate::u3}, {"u3", ParamGate::u3}, {"u2", ParamGate::u2}, {"u1", ParamGate::u1}, diff --git a/src/simulators/density_matrix/densitymatrix_state.hpp b/src/simulators/density_matrix/densitymatrix_state.hpp index abfe1121cf..8ea57749a4 100644 --- a/src/simulators/density_matrix/densitymatrix_state.hpp +++ b/src/simulators/density_matrix/densitymatrix_state.hpp @@ -41,10 +41,10 @@ const Operations::OpSet StateOpSet( Operations::OpType::diagonal_matrix, Operations::OpType::kraus, Operations::OpType::superop}, // Gates - {"U", "CX", "u1", "u2", "u3", "cx", "cy", "cz", "swap", "id", - "x", "y", "z", "h", "s", "sdg", "t", "tdg", "ccx", - "r", "rx", "ry", "rz", "rxx", "ryy", "rzz", "rzx", "p", - "cp","cu1", "sx", "x90", "delay"}, + {"U", "CX", "u1", "u2", "u3", "u", "cx", "cy", "cz", + "swap", "id", "x", "y", "z", "h", "s", "sdg", "t", + "tdg", "ccx", "r", "rx", "ry", "rz", "rxx", "ryy", "rzz", + "rzx", "p", "cp", "cu1", "sx", "x90", "delay"}, // Snapshots {"density_matrix", "memory", "register", "probabilities", "probabilities_with_variance", "expectation_value_pauli", @@ -277,6 +277,7 @@ const stringmap_t State::gateset_({ {"u1", Gates::u1}, // zero-X90 pulse waltz gate {"u2", Gates::u2}, // single-X90 pulse waltz gate {"u3", Gates::u3}, // two X90 pulse waltz gate + {"u", Gates::u3}, // two X90 pulse waltz gate {"U", Gates::u3}, // two X90 pulse waltz gate // Two-qubit gates {"CX", Gates::cx}, // Controlled-X gate (CNOT) diff --git a/src/simulators/extended_stabilizer/ch_runner.hpp b/src/simulators/extended_stabilizer/ch_runner.hpp index 3cb2bc6034..addc8f138d 100644 --- a/src/simulators/extended_stabilizer/ch_runner.hpp +++ b/src/simulators/extended_stabilizer/ch_runner.hpp @@ -104,6 +104,7 @@ class Runner void apply_cz(uint_t control, uint_t target, uint_t rank); void apply_swap(uint_t qubit_1, uint_t qubit_2, uint_t rank); void apply_h(uint_t qubit, uint_t rank); + void apply_sx(uint_t qubit, uint_t rank); void apply_s(uint_t qubit, uint_t rank); void apply_sdag(uint_t qubit, uint_t rank); void apply_x(uint_t qubit, uint_t rank); @@ -254,6 +255,13 @@ void Runner::apply_sdag(uint_t qubit, uint_t rank) states_[rank].Sdag(qubit); } +void Runner::apply_sx(uint_t qubit, uint_t rank) +{ + states_[rank].Sdag(qubit); + states_[rank].H(qubit); + states_[rank].Sdag(qubit); +} + void Runner::apply_x(uint_t qubit, uint_t rank) { states_[rank].X(qubit); diff --git a/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp b/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp index 7c9e69cc03..8df8727f98 100644 --- a/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp +++ b/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp @@ -38,7 +38,7 @@ const Operations::OpSet StateOpSet( Operations::OpType::roerror, Operations::OpType::bfunc, Operations::OpType::snapshot}, // Gates - {"CX", "u0", "u1", "cx", "cz", "swap", "id", "x", "y", "z", "h", + {"CX", "u0", "u1", "p", "cx", "cz", "swap", "id", "x", "y", "z", "h", "s", "sdg", "t", "tdg", "ccx", "ccz", "delay"}, // Snapshots {"statevector", "probabilities", "memory", "register"} @@ -188,11 +188,13 @@ const stringmap_t State::gateset_({ {"s", Gates::s}, // Phase gate (aka sqrt(Z) gate) {"sdg", Gates::sdg}, // Conjugate-transpose of Phase gate {"h", Gates::h}, // Hadamard gate (X + Z / sqrt(2)) + {"sx", Gates::sx}, // sqrt(X) gate {"t", Gates::t}, // T-gate (sqrt(S)) {"tdg", Gates::tdg}, // Conjguate-transpose of T gate // Waltz Gates {"u0", Gates::u0}, // idle gate in multiples of X90 {"u1", Gates::u1}, // zero-X90 pulse waltz gate + {"p", Gates::u1}, // zero-X90 pulse waltz gate // Two-qubit gates {"CX", Gates::cx}, // Controlled-X gate (CNOT) {"cx", Gates::cx}, // Controlled-X gate (CNOT) @@ -598,6 +600,9 @@ void State::apply_gate(const Operations::Op &op, RngEngine &rng, uint_t rank) case Gates::h: BaseState::qreg_.apply_h(op.qubits[0], rank); break; + case Gates::sx: + BaseState::qreg_.apply_sx(op.qubits[0], rank); + break; case Gates::cx: BaseState::qreg_.apply_cx(op.qubits[0], op.qubits[1], rank); break; diff --git a/src/simulators/extended_stabilizer/gates.hpp b/src/simulators/extended_stabilizer/gates.hpp index 696c734501..dbc9d17825 100644 --- a/src/simulators/extended_stabilizer/gates.hpp +++ b/src/simulators/extended_stabilizer/gates.hpp @@ -30,7 +30,7 @@ namespace CHSimulator using complex_t = std::complex; enum class Gates { - u0, u1, id, x, y, z, h, s, sdg, t, tdg, + u0, u1, id, x, y, z, h, s, sdg, sx, t, tdg, cx, cz, swap, ccx, ccz }; @@ -48,12 +48,14 @@ namespace CHSimulator {"z", Gatetypes::pauli}, // Pauli-Z gate {"s", Gatetypes::clifford}, // Phase gate (aka sqrt(Z) gate) {"sdg", Gatetypes::clifford}, // Conjugate-transpose of Phase gate + {"sx", Gatetypes::clifford}, // Sqrt(X) gate {"h", Gatetypes::clifford}, // Hadamard gate (X + Z / sqrt(2)) {"t", Gatetypes::non_clifford}, // T-gate (sqrt(S)) {"tdg", Gatetypes::non_clifford}, // Conjguate-transpose of T gate // Waltz Gates {"u0", Gatetypes::pauli}, // idle gate in multiples of X90 {"u1", Gatetypes::non_clifford}, // zero-X90 pulse waltz gate + {"p", Gatetypes::non_clifford}, // zero-X90 pulse waltz gate // Two-qubit gates {"CX", Gatetypes::clifford}, // Controlled-X gate (CNOT) {"cx", Gatetypes::clifford}, // Controlled-X gate (CNOT) diff --git a/src/simulators/matrix_product_state/matrix_product_state.hpp b/src/simulators/matrix_product_state/matrix_product_state.hpp index c0f00d4ccb..74b22a33cf 100644 --- a/src/simulators/matrix_product_state/matrix_product_state.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state.hpp @@ -49,8 +49,8 @@ const Operations::OpSet StateOpSet( Operations::OpType::bfunc, Operations::OpType::roerror, Operations::OpType::matrix, Operations::OpType::kraus}, // Gates - {"id", "x", "y", "z", "s", "sdg", "h", "t", "tdg", "u1", "u2", "u3", - "U", "CX", "cx", "cz", "cu1", "swap", "ccx"}, + {"id", "x", "y", "z", "s", "sdg", "h", "t", "tdg", "p", "u1", + "u2", "u3", "u", "U", "CX", "cx", "cz", "cp", "cu1", "swap", "ccx"}, // Snapshots {"statevector", "memory", "register", "probabilities", "expectation_value_pauli", "expectation_value_pauli_with_variance", @@ -297,21 +297,25 @@ const stringmap_t State::gateset_({ {"s", Gates::s}, // Phase gate (aka sqrt(Z) gate) {"sdg", Gates::sdg}, // Conjugate-transpose of Phase gate {"h", Gates::h}, // Hadamard gate (X + Z / sqrt(2)) + {"sx", Gates::sx}, // Sqrt(X) gate {"t", Gates::t}, // T-gate (sqrt(S)) {"tdg", Gates::tdg}, // Conjguate-transpose of T gate // Waltz Gates + {"p", Gates::u1}, // zero-X90 pulse waltz gate {"u1", Gates::u1}, // zero-X90 pulse waltz gate {"u2", Gates::u2}, // single-X90 pulse waltz gate {"u3", Gates::u3}, // two X90 pulse waltz gate + {"u", Gates::u3}, // two X90 pulse waltz gate {"U", Gates::u3}, // two X90 pulse waltz gate // Two-qubit gates {"CX", Gates::cx}, // Controlled-X gate (CNOT) {"cx", Gates::cx}, // Controlled-X gate (CNOT) {"cz", Gates::cz}, // Controlled-Z gate - {"cu1", Gates::cu1}, // Controlled-U1 gate + {"cu1", Gates::cu1}, // Controlled-U1 gate + {"cp", Gates::cu1}, // Controlled-U1 gate {"swap", Gates::swap}, // SWAP gate // Three-qubit gates - {"ccx", Gates::mcx} // Controlled-CX gate (Toffoli) + {"ccx", Gates::mcx} // Controlled-CX gate (Toffoli) }); const stringmap_t State::snapshotset_({ @@ -663,6 +667,9 @@ void State::apply_gate(const Operations::Op &op) { case Gates::sdg: qreg_.apply_sdg(op.qubits[0]); break; + case Gates::sx: + qreg_.apply_sx(op.qubits[0]); + break; case Gates::t: qreg_.apply_t(op.qubits[0]); break; 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 e387792da4..63445913de 100644 --- a/src/simulators/matrix_product_state/matrix_product_state_internal.cpp +++ b/src/simulators/matrix_product_state/matrix_product_state_internal.cpp @@ -314,28 +314,31 @@ reg_t MPS::get_internal_qubits(const reg_t &qubits) const { void MPS::apply_h(uint_t index) { - cmatrix_t h_matrix = AER::Linalg::Matrix::H; - get_qubit(index).apply_matrix(h_matrix); + get_qubit(index).apply_matrix(AER::Linalg::Matrix::H); +} + +void MPS::apply_sx(uint_t index) +{ + get_qubit(index).apply_matrix(AER::Linalg::Matrix::SX); } void MPS::apply_u1(uint_t index, double lambda) { - cmatrix_t u1_matrix = AER::Linalg::Matrix::u1(lambda); - get_qubit(index).apply_matrix(u1_matrix); + get_qubit(index).apply_matrix(AER::Linalg::Matrix::u1(lambda)); } void MPS::apply_u2(uint_t index, double phi, double lambda) { - cmatrix_t u2_matrix = AER::Linalg::Matrix::u2(phi, lambda); - get_qubit(index).apply_matrix(u2_matrix); + get_qubit(index).apply_matrix(AER::Linalg::Matrix::u2(phi, lambda)); } void MPS::apply_u3(uint_t index, double theta, double phi, double lambda) { - cmatrix_t u3_matrix = AER::Linalg::Matrix::u3(theta, phi, lambda); - get_qubit(index).apply_matrix(u3_matrix); + get_qubit(index).apply_matrix(AER::Linalg::Matrix::u3(theta, phi, lambda)); } + + void MPS::apply_cnot(uint_t index_A, uint_t index_B) { apply_2_qubit_gate(get_qubit_index(index_A), 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 f458d2cae3..a5dba3c932 100644 --- a/src/simulators/matrix_product_state/matrix_product_state_internal.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state_internal.hpp @@ -26,7 +26,7 @@ namespace MatrixProductState { // Allowed gates enum class enum Gates { - id, h, x, y, z, s, sdg, t, tdg, u1, u2, u3, // single qubit + id, h, x, y, z, s, sdg, sx, t, tdg, u1, u2, u3, // single qubit cx, cz, cu1, swap, su4, // two qubit mcx // three qubit }; @@ -98,6 +98,7 @@ class MPS{ // Returns: none. //---------------------------------------------------------------- void apply_h(uint_t index); + void apply_sx(uint_t index); void apply_x(uint_t index){ get_qubit(index).apply_x();} void apply_y(uint_t index){ get_qubit(index).apply_y();} void apply_z(uint_t index){ get_qubit(index).apply_z();} diff --git a/src/simulators/statevector/statevector_state.hpp b/src/simulators/statevector/statevector_state.hpp index ddb3695c0e..237f4a96b5 100755 --- a/src/simulators/statevector/statevector_state.hpp +++ b/src/simulators/statevector/statevector_state.hpp @@ -40,12 +40,13 @@ const Operations::OpSet StateOpSet( Operations::OpType::matrix, Operations::OpType::diagonal_matrix, Operations::OpType::multiplexer, Operations::OpType::kraus}, // Gates - {"u1", "u2", "u3", "cx", "cz", "cy", "cp", "cu1", - "cu2", "cu3", "swap", "id", "p", "x", "y", "z", - "h", "s", "sdg", "t", "tdg", "r", "rx", "ry", - "rz", "rxx", "ryy", "rzz", "rzx", "ccx", "cswap", "mcx", - "mcy", "mcz", "mcu1", "mcu2", "mcu3", "mcswap", "mcphase", "mcr", - "mcrx", "mcry", "mcry", "sx", "csx", "mcsx", "delay"}, + {"u1", "u2", "u3", "u", "U", "CX", "cx", "cz", + "cy", "cp", "cu1", "cu2", "cu3", "swap", "id", "p", + "x", "y", "z", "h", "s", "sdg", "t", "tdg", + "r", "rx", "ry", "rz", "rxx", "ryy", "rzz", "rzx", + "ccx", "cswap", "mcx", "mcy", "mcz", "mcu1", "mcu2", "mcu3", + "mcswap", "mcphase", "mcr", "mcrx", "mcry", "mcry", "sx", "csx", + "mcsx", "delay"}, // Snapshots {"statevector", "memory", "register", "probabilities", "probabilities_with_variance", "expectation_value_pauli", "density_matrix", @@ -319,7 +320,10 @@ const stringmap_t State::gateset_({ {"u1", Gates::mcp}, // zero-X90 pulse waltz gate {"u2", Gates::mcu2}, // single-X90 pulse waltz gate {"u3", Gates::mcu3}, // two X90 pulse waltz gate + {"u", Gates::mcu3}, // two X90 pulse waltz gate + {"U", Gates::mcu3}, // two X90 pulse waltz gate // 2-qubit gates + {"CX", Gates::mcx}, // Controlled-X gate (CNOT) {"cx", Gates::mcx}, // Controlled-X gate (CNOT) {"cy", Gates::mcy}, // Controlled-Y gate {"cz", Gates::mcz}, // Controlled-Z gate diff --git a/src/simulators/superoperator/superoperator_state.hpp b/src/simulators/superoperator/superoperator_state.hpp index 64cb42d895..2d2e0fb621 100755 --- a/src/simulators/superoperator/superoperator_state.hpp +++ b/src/simulators/superoperator/superoperator_state.hpp @@ -35,10 +35,10 @@ const Operations::OpSet StateOpSet( Operations::OpType::matrix, Operations::OpType::diagonal_matrix, Operations::OpType::kraus, Operations::OpType::superop}, // Gates - {"U", "CX", "u1", "u2", "u3", "cx", "cy", "cz", "swap", - "id", "x", "y", "z", "h", "s", "sdg", "t", "tdg", - "ccx", "r", "rx", "ry", "rz", "rxx", "ryy", "rzz", "rzx", - "p", "cp", "cu1", "sx", "x90", "delay"}, + {"U", "CX", "u1", "u2", "u3", "u", "cx", "cy", "cz", + "swap", "id", "x", "y", "z", "h", "s", "sdg", "t", + "tdg", "ccx", "r", "rx", "ry", "rz", "rxx", "ryy", "rzz", + "rzx", "p", "cp", "cu1", "sx", "x90", "delay"}, // Snapshots {"superoperator"}); @@ -186,6 +186,7 @@ const stringmap_t State::gateset_({ {"u1", Gates::u1}, // zero-X90 pulse waltz gate {"u2", Gates::u2}, // single-X90 pulse waltz gate {"u3", Gates::u3}, // two X90 pulse waltz gate + {"u", Gates::u3}, // two X90 pulse waltz gate {"U", Gates::u3}, // two X90 pulse waltz gate // Two-qubit gates {"CX", Gates::cx}, // Controlled-X gate (CNOT) diff --git a/src/simulators/unitary/unitary_state.hpp b/src/simulators/unitary/unitary_state.hpp index 1c96b8a49c..9413922fd0 100755 --- a/src/simulators/unitary/unitary_state.hpp +++ b/src/simulators/unitary/unitary_state.hpp @@ -37,12 +37,13 @@ const Operations::OpSet StateOpSet( Operations::OpType::matrix, Operations::OpType::diagonal_matrix, Operations::OpType::snapshot}, // Gates - {"u1", "u2", "u3", "cx", "cz", "cy", "cp", "cu1", - "cu2", "cu3", "swap", "id", "p", "x", "y", "z", - "h", "s", "sdg", "t", "tdg", "r", "rx", "ry", - "rz", "rxx", "ryy", "rzz", "rzx", "ccx", "cswap", "mcx", - "mcy", "mcz", "mcu1", "mcu2", "mcu3", "mcswap", "mcphase", "mcr", - "mcrx", "mcry", "mcry", "sx", "csx", "mcsx", "delay"}, + {"u1", "u2", "u3", "u", "U", "CX", "cx", "cz", + "cy", "cp", "cu1", "cu2", "cu3", "swap", "id", "p", + "x", "y", "z", "h", "s", "sdg", "t", "tdg", + "r", "rx", "ry", "rz", "rxx", "ryy", "rzz", "rzx", + "ccx", "cswap", "mcx", "mcy", "mcz", "mcu1", "mcu2", "mcu3", + "mcswap", "mcphase", "mcr", "mcrx", "mcry", "mcry", "sx", "csx", + "mcsx", "delay"}, // Snapshots {"unitary"}); @@ -189,7 +190,10 @@ const stringmap_t State::gateset_({ {"u1", Gates::mcp}, // zero-X90 pulse waltz gate {"u2", Gates::mcu2}, // single-X90 pulse waltz gate {"u3", Gates::mcu3}, // two X90 pulse waltz gate + {"u", Gates::mcu3}, // two X90 pulse waltz gate + {"U", Gates::mcu3}, // two X90 pulse waltz gate // Two-qubit gates + {"CX", Gates::mcx}, // Controlled-X gate (CNOT) {"cx", Gates::mcx}, // Controlled-X gate (CNOT) {"cy", Gates::mcy}, // Controlled-Z gate {"cz", Gates::mcz}, // Controlled-Z gate diff --git a/test/terra/backends/qasm_simulator/qasm_standard_gates.py b/test/terra/backends/qasm_simulator/qasm_standard_gates.py index 4d8c578acd..5b82e34607 100644 --- a/test/terra/backends/qasm_simulator/qasm_standard_gates.py +++ b/test/terra/backends/qasm_simulator/qasm_standard_gates.py @@ -80,26 +80,6 @@ (UGate, 3) ] -STATEVECTOR_BG = QasmSimulator().configuration().basis_gates -DENSITY_MATRIX_BG = [ - "u1", "u2", "u3", "cx", "cy", "cz", "swap", "id", "x", "y", "z", "h", "s", - "sdg", "t", "tdg", "ccx", "r", "rx", "ry", "rz", "rxx", "ryy", "rzz", - "rzx", "p", "cp", "cu1", "sx", "delay", -] -MATRIX_PRODUCT_STATE_BG = [ - "id", "x", "y", "z", "s", "sdg", "h", "t", "tdg", "u1", "u2", "u3", - "cx", "cz", "cu1", "swap", "ccx", "delay", -] -BASIS_GATES = { - 'statevector': STATEVECTOR_BG, - 'statevector_gpu': STATEVECTOR_BG, - 'statevector_thrust': STATEVECTOR_BG, - 'density_matrix': DENSITY_MATRIX_BG, - 'density_matrix_gpu': DENSITY_MATRIX_BG, - 'density_matrix_thrust': DENSITY_MATRIX_BG, - 'matrix_product_state': MATRIX_PRODUCT_STATE_BG -} - @ddt class QasmStandardGateStatevectorTests: @@ -128,13 +108,10 @@ def test_gate_statevector(self, gate_cls, num_params): # Add snapshot and execute circuit.snapshot_statevector('final') backend_options = self.BACKEND_OPTS - method = backend_options.get('method', 'automatic') - basis_gates = BASIS_GATES.get(method) - result = execute(circuit, - self.SIMULATOR, - basis_gates=basis_gates, - shots=1, - **backend_options).result() + method = backend_options.pop('method', 'automatic') + backend = self.SIMULATOR + backend.set_options(method=method) + result = execute(circuit, backend, shots=1, **backend_options).result() # Check results success = getattr(result, 'success', False) @@ -175,13 +152,10 @@ def test_gate_density_matrix(self, gate_cls, num_params): # Add snapshot and execute circuit.snapshot_density_matrix('final') backend_options = self.BACKEND_OPTS - method = backend_options.get('method', 'automatic') - basis_gates = BASIS_GATES.get(method) - result = execute(circuit, - self.SIMULATOR, - basis_gates=basis_gates, - shots=1, - **backend_options).result() + method = backend_options.pop('method', 'automatic') + backend = self.SIMULATOR + backend.set_options(method=method) + result = execute(circuit, backend, shots=1, **backend_options).result() # Check results success = getattr(result, 'success', False) diff --git a/test/terra/backends/statevector_simulator/statevector_gates.py b/test/terra/backends/statevector_simulator/statevector_gates.py index 85a1bca3c3..4d3416aef8 100644 --- a/test/terra/backends/statevector_simulator/statevector_gates.py +++ b/test/terra/backends/statevector_simulator/statevector_gates.py @@ -89,8 +89,14 @@ class StatevectorGateTests: (U3Gate, 3), (UGate, 3) ] - BASIS_GATES = [None, ['id', 'u3', 'cx'], ['id', 'r', 'cz'], - ['id', 'rz', 'rx', 'cz'], ['id', 'p', 'sx', 'cx']] + BASIS_GATES = [ + None, + ['id', 'u1', 'u2', 'u3', 'cx'], + ['id', 'u', 'cx'], + ['id', 'r', 'cz'], + ['id', 'rz', 'rx', 'cz'], + ['id', 'p', 'sx', 'cx'] + ] @data(*[(gate_params[0], gate_params[1], basis_gates) for gate_params, basis_gates in product(GATES, BASIS_GATES)]) diff --git a/test/terra/backends/unitary_simulator/unitary_gates.py b/test/terra/backends/unitary_simulator/unitary_gates.py index 28eeb0f037..2c4d8f7472 100644 --- a/test/terra/backends/unitary_simulator/unitary_gates.py +++ b/test/terra/backends/unitary_simulator/unitary_gates.py @@ -89,8 +89,14 @@ class UnitaryGateTests: (U3Gate, 3), (UGate, 3) ] - BASIS_GATES = [None, ['id', 'u3', 'cx'], ['id', 'r', 'cz'], - ['id', 'rz', 'rx', 'cz'], ['id', 'p', 'sx', 'cx']] + BASIS_GATES = [ + None, + ['id', 'u1', 'u2', 'u3', 'cx'], + ['id', 'u', 'cx'], + ['id', 'r', 'cz'], + ['id', 'rz', 'rx', 'cz'], + ['id', 'p', 'sx', 'cx'] + ] @data(*[(gate_params[0], gate_params[1], basis_gates) for gate_params, basis_gates in product(GATES, BASIS_GATES)]) From 10a41dc00564599b74a2ae60b6d836fecc781b8b Mon Sep 17 00:00:00 2001 From: "Christopher J. Wood" Date: Thu, 15 Oct 2020 03:14:16 -0400 Subject: [PATCH 020/126] Fix fusion thresholds and defaults (#990) --- .github/CODEOWNERS | 2 +- qiskit/providers/aer/backends/aerbackend.py | 4 +- .../providers/aer/backends/qasm_simulator.py | 2 +- .../aer/backends/statevector_simulator.py | 11 +++ .../aer/backends/unitary_simulator.py | 11 +++ .../fusion-threshold-33127b9b4e219640.yaml | 11 +++ src/controllers/qasm_controller.hpp | 57 +++++++++------- src/controllers/statevector_controller.hpp | 4 +- src/controllers/unitary_controller.hpp | 3 +- src/transpile/fusion.hpp | 46 +++++++------ .../backends/qasm_simulator/qasm_fusion.py | 67 ++++++++++--------- .../statevector_fusion.py | 2 +- .../backends/test_config_pulse_simulator.py | 4 +- .../unitary_simulator/unitary_fusion.py | 2 +- 14 files changed, 135 insertions(+), 91 deletions(-) create mode 100644 releasenotes/notes/fusion-threshold-33127b9b4e219640.yaml diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a8014593c2..ec0b63bb2b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -8,7 +8,7 @@ # Generic rule for the repository. This pattern is actually the one that will # apply unless specialized by a later rule -* @chriseclectic @atilag +* @chriseclectic @vvilpas @atilag # Individual folders on root directory /qiskit @chriseclectic @atilag @vvilpas diff --git a/qiskit/providers/aer/backends/aerbackend.py b/qiskit/providers/aer/backends/aerbackend.py index 28bcb8543a..215c84fa6f 100644 --- a/qiskit/providers/aer/backends/aerbackend.py +++ b/qiskit/providers/aer/backends/aerbackend.py @@ -109,7 +109,7 @@ def __init__(self, def run(self, qobj, backend_options=None, # DEPRECATED - validate=True, + validate=False, **run_options): """Run a qobj on the backend. @@ -117,7 +117,7 @@ def run(self, qobj (QasmQobj): The Qobj to be executed. backend_options (dict or None): DEPRECATED dictionary of backend options for the execution (default: None). - validate (bool): validate the Qobj before running (default: True). + validate (bool): validate the Qobj before running (default: False). run_options (kwargs): additional run time backend options. Returns: diff --git a/qiskit/providers/aer/backends/qasm_simulator.py b/qiskit/providers/aer/backends/qasm_simulator.py index 422c7e8118..f781078538 100644 --- a/qiskit/providers/aer/backends/qasm_simulator.py +++ b/qiskit/providers/aer/backends/qasm_simulator.py @@ -231,7 +231,7 @@ class QasmSimulator(AerBackend): * ``fusion_max_qubit`` (int): Maximum number of qubits for a operation generated in a fusion optimization [Default: 5] * ``fusion_threshold`` (int): Threshold that number of qubits must be greater - than or equal to enable fusion optimization [Default: 20] + than or equal to enable fusion optimization [Default: 14] """ _DEFAULT_CONFIGURATION = { diff --git a/qiskit/providers/aer/backends/statevector_simulator.py b/qiskit/providers/aer/backends/statevector_simulator.py index 51198dddc9..449bcca3ec 100644 --- a/qiskit/providers/aer/backends/statevector_simulator.py +++ b/qiskit/providers/aer/backends/statevector_simulator.py @@ -90,6 +90,17 @@ class StatevectorSimulator(AerBackend): this will only use unallocated CPU cores up to max_parallel_threads. Note that setting this too low can reduce performance (Default: 14). + + These backend options apply in circuit optimization passes: + + * ``fusion_enable`` (bool): Enable fusion optimization in circuit + optimization passes [Default: True] + * ``fusion_verbose`` (bool): Output gates generated in fusion optimization + into metadata [Default: False] + * ``fusion_max_qubit`` (int): Maximum number of qubits for a operation generated + in a fusion optimization [Default: 5] + * ``fusion_threshold`` (int): Threshold that number of qubits must be greater + than or equal to enable fusion optimization [Default: 14] """ _DEFAULT_CONFIGURATION = { diff --git a/qiskit/providers/aer/backends/unitary_simulator.py b/qiskit/providers/aer/backends/unitary_simulator.py index bccb4ab4ea..f7d9b735d7 100644 --- a/qiskit/providers/aer/backends/unitary_simulator.py +++ b/qiskit/providers/aer/backends/unitary_simulator.py @@ -96,6 +96,17 @@ class UnitarySimulator(AerBackend): this will only use unallocated CPU cores up to max_parallel_threads. Note that setting this too low can reduce performance (Default: 14). + + These backend options apply in circuit optimization passes: + + * ``fusion_enable`` (bool): Enable fusion optimization in circuit + optimization passes [Default: True] + * ``fusion_verbose`` (bool): Output gates generated in fusion optimization + into metadata [Default: False] + * ``fusion_max_qubit`` (int): Maximum number of qubits for a operation generated + in a fusion optimization [Default: 5] + * ``fusion_threshold`` (int): Threshold that number of qubits must be greater + than or equal to enable fusion optimization [Default: 7] """ _DEFAULT_CONFIGURATION = { diff --git a/releasenotes/notes/fusion-threshold-33127b9b4e219640.yaml b/releasenotes/notes/fusion-threshold-33127b9b4e219640.yaml new file mode 100644 index 0000000000..5ff8ad83f5 --- /dev/null +++ b/releasenotes/notes/fusion-threshold-33127b9b4e219640.yaml @@ -0,0 +1,11 @@ +--- +features: + - | + Changes ``"fusion_threshold"`` backend option to apply fusion when the + number of qubits is above the threshold, not equal or above the threshold, + to match the behaviour of the OpenMP qubit threshold parameter. + - | + Changes the default value of ``"fusion_threshold"`` from 20 to 14 for the + :class:`~qiskit.providers.aer.QasmSimulator` and + :class:`~qiskit.providers.aer.StatevectorSimulator`, and from 10 to 7 for + the :class:`~qiskit.providers.aer.UnitarySimulator`. diff --git a/src/controllers/qasm_controller.hpp b/src/controllers/qasm_controller.hpp index 38c2d6b789..06251d9ade 100755 --- a/src/controllers/qasm_controller.hpp +++ b/src/controllers/qasm_controller.hpp @@ -48,7 +48,7 @@ namespace Simulator { * zero in result data [Default: 1e-10] * - "statevector_parallel_threshold" (int): Threshold that number of qubits * must be greater than to enable OpenMP parallelization at State - * level [Default: 13] + * level [Default: 14] * - "statevector_sample_measure_opt" (int): Threshold that number of qubits * must be greater than to enable indexing optimization during * measure sampling [Default: 10] @@ -117,7 +117,7 @@ namespace Simulator { * - fusion_max_qubit (int): Maximum number of qubits for a operation generated * in a fusion optimization [Default: 5] * - fusion_threshold (int): Threshold that number of qubits must be greater - * than or equal to enable fusion optimization [Default: 20] + * than or equal to enable fusion optimization [Default: 14] * **************************************************************************/ @@ -164,9 +164,6 @@ class QasmController : public Base::Controller { // Simulation precision enum class Precision { double_precision, single_precision }; - // Fusion method - using FusionMethod = Transpile::Fusion::Method; - //----------------------------------------------------------------------- // Base class abstract method override //----------------------------------------------------------------------- @@ -207,8 +204,8 @@ class QasmController : public Base::Controller { // Return a fusion transpilation pass configured for the current // method, circuit and config Transpile::Fusion transpile_fusion(Method method, - const json_t& config, - FusionMethod fusion_method = FusionMethod::unitary) const; + const Operations::OpSet &opset, + const json_t& config) const; //---------------------------------------------------------------- // Run circuit helpers @@ -781,29 +778,44 @@ size_t QasmController::required_memory_mb( } Transpile::Fusion QasmController::transpile_fusion(Method method, - const json_t& config, - FusionMethod fusion_method) const { + const Operations::OpSet &opset, + const json_t& config) const { Transpile::Fusion fusion_pass; + if (opset.contains(Operations::OpType::superop)) { + fusion_pass.allow_superop = true; + } + if (opset.contains(Operations::OpType::kraus)) { + fusion_pass.allow_kraus = true; + } switch (method) { - case Method::statevector: - case Method::statevector_thrust_gpu: - case Method::statevector_thrust_cpu: case Method::density_matrix: case Method::density_matrix_thrust_gpu: case Method::density_matrix_thrust_cpu: { - if (fusion_method == FusionMethod::superop) { - fusion_pass.allow_superop = true; - } else if (fusion_method == FusionMethod::kraus) { - fusion_pass.allow_kraus = true; + // Halve the default threshold and max fused qubits for density matrix + fusion_pass.threshold /= 2; + fusion_pass.max_qubit /= 2; + break; + } + case Method::matrix_product_state: { + // Disable fusion by default, but allow it to be enabled by config settings + fusion_pass.active = false; + } + case Method::statevector: + case Method::statevector_thrust_gpu: + case Method::statevector_thrust_cpu: { + if (fusion_pass.allow_kraus) { + // Halve default max fused qubits for Kraus noise fusion + fusion_pass.max_qubit /= 2; } - fusion_pass.set_config(config); break; } default: { fusion_pass.active = false; - break; + return fusion_pass; } } + // Override default fusion settings with custom config + fusion_pass.set_config(config); return fusion_pass; } @@ -885,9 +897,7 @@ void QasmController::run_circuit_helper(const Circuit& circ, result.add_metadata("measure_sampling", false); // Choose execution method based on noise and method - Circuit opt_circ; - FusionMethod fusion_method = FusionMethod::unitary; // Ideal circuit if (noise.is_ideal()) { @@ -904,7 +914,6 @@ void QasmController::run_circuit_helper(const Circuit& circ, // Sample noise using SuperOp method auto noise_superop = noise; noise_superop.activate_superop_method(); - fusion_method = FusionMethod::superop; opt_circ = noise_superop.sample_noise(circ, rng); } // Kraus noise sampling @@ -912,7 +921,6 @@ void QasmController::run_circuit_helper(const Circuit& circ, noise.opset().contains(Operations::OpType::superop)) { auto noise_kraus = noise; noise_kraus.activate_kraus_method(); - fusion_method = FusionMethod::kraus; opt_circ = noise_kraus.sample_noise(circ, rng); } // General circuit noise sampling @@ -927,8 +935,7 @@ void QasmController::run_circuit_helper(const Circuit& circ, Transpile::DelayMeasure measure_pass; measure_pass.set_config(config); measure_pass.optimize_circuit(opt_circ, dummy_noise, state.opset(), result); - - auto fusion_pass = transpile_fusion(method, config, fusion_method); + auto fusion_pass = transpile_fusion(method, opt_circ.opset(), config); fusion_pass.optimize_circuit(opt_circ, dummy_noise, state.opset(), result); // Run simulation @@ -995,7 +1002,7 @@ void QasmController::run_circuit_with_sampled_noise(const Circuit& circ, RngEngine& rng) const { // Transpilation for circuit noise method - auto fusion_pass = transpile_fusion(method, config, FusionMethod::unitary); + auto fusion_pass = transpile_fusion(method, circ.opset(), config); Transpile::DelayMeasure measure_pass; measure_pass.set_config(config); Noise::NoiseModel dummy_noise; diff --git a/src/controllers/statevector_controller.hpp b/src/controllers/statevector_controller.hpp index 1d981d8564..e5b9f8f6da 100755 --- a/src/controllers/statevector_controller.hpp +++ b/src/controllers/statevector_controller.hpp @@ -37,7 +37,7 @@ namespace Simulator { * zero in result data [Default: 1e-10] * - "statevector_parallel_threshold" (int): Threshold that number of qubits * must be greater than to enable OpenMP parallelization at State - * level [Default: 13] + * level [Default: 14] * - "statevector_sample_measure_opt" (int): Threshold that number of qubits * must be greater than to enable indexing optimization during * measure sampling [Default: 10] @@ -298,7 +298,7 @@ void StatevectorController::run_circuit_helper( // Optimize circuit const std::vector* op_ptr = &circ.ops; - Transpile::Fusion fusion_pass(5, 20); // 20-qubit default threshold + Transpile::Fusion fusion_pass; fusion_pass.set_config(config); Circuit opt_circ; if (fusion_pass.active && circ.num_qubits >= fusion_pass.threshold) { diff --git a/src/controllers/unitary_controller.hpp b/src/controllers/unitary_controller.hpp index ccc7edd40b..7d0b4eda0a 100755 --- a/src/controllers/unitary_controller.hpp +++ b/src/controllers/unitary_controller.hpp @@ -297,7 +297,8 @@ void UnitaryController::run_circuit_helper( // Optimize circuit const std::vector* op_ptr = &circ.ops; - Transpile::Fusion fusion_pass(5, 10); // 10-qubit default threshold + Transpile::Fusion fusion_pass; + fusion_pass.threshold /= 2; // Halve default threshold for unitary simulator fusion_pass.set_config(config); Circuit opt_circ; if (fusion_pass.active && circ.num_qubits >= fusion_pass.threshold) { diff --git a/src/transpile/fusion.hpp b/src/transpile/fusion.hpp index 3005c7cd5c..50dab60b85 100644 --- a/src/transpile/fusion.hpp +++ b/src/transpile/fusion.hpp @@ -45,11 +45,11 @@ class Fusion : public CircuitOptimization { * - fusion_max_qubit (int): Maximum number of qubits for a operation generated * in a fusion optimization [Default: 5] * - fusion_threshold (int): Threshold that number of qubits must be greater - * than to enable fusion optimization [Default: 20] + * than to enable fusion optimization [Default: 14] * - fusion_cost_factor (double): a cost function to estimate an aggregate * gate [Default: 1.8] */ - Fusion(uint_t _max_qubit = 5, uint_t _threshold = 20, double _cost_factor = 1.8) + Fusion(uint_t _max_qubit = 5, uint_t _threshold = 14, double _cost_factor = 1.8) : max_qubit(_max_qubit), threshold(_threshold), cost_factor(_cost_factor) {} // Allowed fusion methods: @@ -153,14 +153,22 @@ void Fusion::optimize_circuit(Circuit& circ, Noise::NoiseModel& noise, const opset_t &allowed_opset, ExperimentResult &result) const { - // Check if fusion should be skipped - if (!active || !allowed_opset.contains(optype_t::matrix)) - return; - // Start timer using clock_t = std::chrono::high_resolution_clock; auto timer_start = clock_t::now(); + // Fusion metadata container + json_t metadata; + + // Check if fusion should be skipped + if (!active || !allowed_opset.contains(optype_t::matrix)) { + metadata["enabled"] = false; + result.add_metadata("fusion", metadata); + return; + } + metadata["enabled"] = true; + metadata["applied"] = false; + // Determine fusion method // TODO: Support Kraus fusion method Method method = Method::unitary; @@ -174,12 +182,8 @@ void Fusion::optimize_circuit(Circuit& circ, || circ.opset().contains(optype_t::superop))) { method = Method::kraus; } - uint_t qubit_threshold = (method==Method::unitary) ? threshold : threshold / 2; - uint_t max_fused_qubits = (method==Method::unitary) ? max_qubit : max_qubit / 2; - // Fusion metadata container - json_t metadata; - metadata["applied"] = false; + // Calculate thresholds based on method if (method == Method::unitary) { metadata["method"] = "unitary"; } else if (method == Method::superop) { @@ -187,17 +191,15 @@ void Fusion::optimize_circuit(Circuit& circ, } else if (method == Method::kraus) { metadata["method"] = "kraus"; } - metadata["threshold"] = qubit_threshold; - metadata["cost_factor"] = cost_factor; - metadata["max_fused_qubits"] = max_fused_qubits; - - // If we are doing superoperator fusion we have the threshold - // for the density matrix simulator - // Check if circuit size is above threshold - if (circ.num_qubits < qubit_threshold) { + // Check qubit threshold + metadata["threshold"] = threshold; + if (circ.num_qubits <= threshold || circ.ops.size() < 2) { result.add_metadata("fusion", metadata); return; } + metadata["cost_factor"] = cost_factor; + metadata["max_fused_qubits"] = max_qubit; + // Apply fusion bool applied = false; @@ -205,15 +207,15 @@ void Fusion::optimize_circuit(Circuit& circ, for (uint_t op_idx = 0; op_idx < circ.ops.size(); ++op_idx) { if (can_ignore(circ.ops[op_idx])) continue; - if (!can_apply_fusion(circ.ops[op_idx], max_fused_qubits, method)) { + if (!can_apply_fusion(circ.ops[op_idx], max_qubit, method)) { applied |= fusion_start != op_idx && aggregate_operations( - circ.ops, fusion_start, op_idx, max_fused_qubits, result, method); + circ.ops, fusion_start, op_idx, max_qubit, result, method); fusion_start = op_idx + 1; } } if (fusion_start < circ.ops.size() && - aggregate_operations(circ.ops, fusion_start, circ.ops.size(), max_fused_qubits, result, method)) + aggregate_operations(circ.ops, fusion_start, circ.ops.size(), max_qubit, result, method)) applied = true; if (applied) { diff --git a/test/terra/backends/qasm_simulator/qasm_fusion.py b/test/terra/backends/qasm_simulator/qasm_fusion.py index cac29d67e2..a10f4947ce 100644 --- a/test/terra/backends/qasm_simulator/qasm_fusion.py +++ b/test/terra/backends/qasm_simulator/qasm_fusion.py @@ -13,6 +13,7 @@ QasmSimulator Integration Tests """ # pylint: disable=no-member +import copy from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit from qiskit.circuit.library import QuantumVolume, QFT @@ -31,8 +32,8 @@ class QasmFusionTests: def create_statevector_circuit(self): """ Creates a simple circuit for running in the statevector """ - qr = QuantumRegister(10) - cr = ClassicalRegister(10) + qr = QuantumRegister(5) + cr = ClassicalRegister(5) circuit = QuantumCircuit(qr, cr) circuit.u3(0.1, 0.1, 0.1, qr[0]) circuit.barrier(qr) @@ -105,7 +106,8 @@ def test_fusion_theshold(self): qobj, **backend_options).result() self.assertSuccess(result) meta = self.fusion_metadata(result) - self.assertFalse(meta.get('applied', False)) + self.assertTrue(meta.get('enabled')) + self.assertFalse(meta.get('applied')) with self.subTest(msg='at fusion threshold'): circuit = transpile(QFT(threshold), @@ -117,7 +119,8 @@ def test_fusion_theshold(self): qobj, **backend_options).result() self.assertSuccess(result) meta = self.fusion_metadata(result) - self.assertTrue(meta.get('applied', False)) + self.assertTrue(meta.get('enabled')) + self.assertFalse(meta.get('applied')) with self.subTest(msg='above fusion threshold'): circuit = transpile(QFT(threshold + 1), @@ -129,7 +132,8 @@ def test_fusion_theshold(self): qobj, **backend_options).result() self.assertSuccess(result) meta = self.fusion_metadata(result) - self.assertTrue(meta.get('applied', False)) + self.assertTrue(meta.get('enabled')) + self.assertTrue(meta.get('applied')) def test_fusion_verbose(self): """Test Fusion with verbose option""" @@ -192,10 +196,9 @@ def test_kraus_noise_fusion(self): result = self.SIMULATOR.run(qobj, noise_model=noise_model, **backend_options).result() + method = result.results[0].metadata.get('method') meta = self.fusion_metadata(result) - if backend_options.get('method') in ['density_matrix', - 'density_matrix_thrust', - 'density_matrix_gpu']: + if method in ['density_matrix', 'density_matrix_thrust', 'density_matrix_gpu']: target_method = 'superop' else: target_method = 'kraus' @@ -223,9 +226,8 @@ def test_non_kraus_noise_fusion(self): noise_model=noise_model, **backend_options).result() meta = self.fusion_metadata(result) - if backend_options.get('method') in ['density_matrix', - 'density_matrix_thrust', - 'density_matrix_gpu']: + method = result.results[0].metadata.get('method') + if method in ['density_matrix', 'density_matrix_thrust', 'density_matrix_gpu']: target_method = 'superop' else: target_method = 'unitary' @@ -249,30 +251,32 @@ def test_control_fusion(self): with self.subTest(msg='fusion enabled'): backend_options = self.fusion_options(enabled=True, threshold=1) result = self.SIMULATOR.run( - qobj, **backend_options).result() + copy.deepcopy(qobj), **backend_options).result() meta = self.fusion_metadata(result) self.assertSuccess(result) + self.assertTrue(meta.get('enabled')) self.assertTrue(meta.get('applied', False)) with self.subTest(msg='fusion disabled'): backend_options = backend_options = self.fusion_options(enabled=False, threshold=1) result = self.SIMULATOR.run( - qobj, **backend_options).result() + copy.deepcopy(qobj), **backend_options).result() meta = self.fusion_metadata(result) self.assertSuccess(result) - self.assertFalse(meta.get('applied', False)) + self.assertFalse(meta.get('enabled')) with self.subTest(msg='fusion default'): backend_options = self.fusion_options() result = self.SIMULATOR.run( - qobj, **backend_options).result() + copy.deepcopy(qobj), **backend_options).result() meta = self.fusion_metadata(result) self.assertSuccess(result) - self.assertFalse(meta.get('applied', False)) + self.assertTrue(meta.get('enabled')) + self.assertFalse(meta.get('applied', False), msg=meta) def test_fusion_operations(self): """Test Fusion enable/disable option""" @@ -351,8 +355,9 @@ def test_fusion_operations(self): self.assertTrue(getattr(result_disabled, 'success', 'False')) self.assertTrue(getattr(result_enabled, 'success', 'False')) - self.assertEqual(meta_disabled, {}) - self.assertTrue(meta_enabled.get('applied', False)) + self.assertFalse(meta_disabled.get('enabled')) + self.assertTrue(meta_enabled.get('enabled')) + self.assertTrue(meta_enabled.get('applied')) self.assertDictAlmostEqual(result_enabled.get_counts(circuit), result_disabled.get_counts(circuit), delta=0.0, @@ -361,30 +366,25 @@ def test_fusion_operations(self): def test_fusion_qv(self): """Test Fusion with quantum volume""" shots = 100 - num_qubits = 8 + num_qubits = 6 depth = 2 circuit = transpile(QuantumVolume(num_qubits, depth, seed=0), backend=self.SIMULATOR, optimization_level=0) circuit.measure_all() - qobj = assemble([circuit], - self.SIMULATOR, - shots=shots, - seed_simulator=1) - - backend_options = self.fusion_options(enabled=False, threshold=1) - result_disabled = self.SIMULATOR.run( - qobj, **backend_options).result() + qobj_disabled = assemble([circuit], self.SIMULATOR, shots=shots, + **self.fusion_options(enabled=False, threshold=1, verbose=True)) + result_disabled = self.SIMULATOR.run(qobj_disabled).result() meta_disabled = self.fusion_metadata(result_disabled) - backend_options = self.fusion_options(enabled=True, threshold=1) - result_enabled = self.SIMULATOR.run( - qobj, **backend_options).result() + qobj_enabled = assemble([circuit], self.SIMULATOR, shots=shots, + **self.fusion_options(enabled=True, threshold=1, verbose=True)) + result_enabled = self.SIMULATOR.run(qobj_enabled).result() meta_enabled = self.fusion_metadata(result_enabled) self.assertTrue(getattr(result_disabled, 'success', 'False')) self.assertTrue(getattr(result_enabled, 'success', 'False')) - self.assertEqual(meta_disabled, {}) + self.assertFalse(meta_disabled.get('applied', False)) self.assertTrue(meta_enabled.get('applied', False)) self.assertDictAlmostEqual(result_enabled.get_counts(circuit), result_disabled.get_counts(circuit), @@ -417,8 +417,9 @@ def test_fusion_qft(self): self.assertTrue(getattr(result_disabled, 'success', 'False')) self.assertTrue(getattr(result_enabled, 'success', 'False')) - self.assertEqual(meta_disabled, {}) - self.assertTrue(meta_enabled.get('applied', False)) + self.assertFalse(meta_disabled.get('enabled')) + self.assertTrue(meta_enabled.get('enabled')) + self.assertTrue(meta_enabled.get('applied')) self.assertDictAlmostEqual(result_enabled.get_counts(circuit), result_disabled.get_counts(circuit), delta=0.0, diff --git a/test/terra/backends/statevector_simulator/statevector_fusion.py b/test/terra/backends/statevector_simulator/statevector_fusion.py index ed547ace5a..6a69e7b7af 100644 --- a/test/terra/backends/statevector_simulator/statevector_fusion.py +++ b/test/terra/backends/statevector_simulator/statevector_fusion.py @@ -65,7 +65,7 @@ def test_fusion_theshold(self): meta = self.fusion_metadata(result) self.assertSuccess(result) - self.assertTrue(meta.get('applied')) + self.assertFalse(meta.get('applied')) with self.subTest(msg='above fusion threshold'): circuit = QuantumVolume(threshold + 1, seed=seed) diff --git a/test/terra/backends/test_config_pulse_simulator.py b/test/terra/backends/test_config_pulse_simulator.py index 43d3311408..c88185b4df 100644 --- a/test/terra/backends/test_config_pulse_simulator.py +++ b/test/terra/backends/test_config_pulse_simulator.py @@ -236,7 +236,7 @@ def test_validation_num_acquires(self): shots=256) try: - test_sim.run(qobj).result() + test_sim.run(qobj, validate=True).result() except AerError as error: self.assertTrue('does not support multiple Acquire' in error.message) @@ -249,7 +249,7 @@ def test_validation_num_acquires(self): shots=256) try: - test_sim.run(qobj).result() + test_sim.run(qobj, validate=True).result() except AerError as error: self.assertTrue('requires at least one Acquire' in error.message) diff --git a/test/terra/backends/unitary_simulator/unitary_fusion.py b/test/terra/backends/unitary_simulator/unitary_fusion.py index 5b4f4af319..1ce48decd4 100644 --- a/test/terra/backends/unitary_simulator/unitary_fusion.py +++ b/test/terra/backends/unitary_simulator/unitary_fusion.py @@ -65,7 +65,7 @@ def test_fusion_theshold(self): meta = self.fusion_metadata(result) self.assertSuccess(result) - self.assertTrue(meta.get('applied')) + self.assertFalse(meta.get('applied')) with self.subTest(msg='above fusion threshold'): circuit = QuantumVolume(threshold + 1, seed=seed) From d64c06ddfc075bb52eca7a954051ef63ef06a71d Mon Sep 17 00:00:00 2001 From: merav-aharoni <46567124+merav-aharoni@users.noreply.github.com> Date: Thu, 15 Oct 2020 22:50:30 +0300 Subject: [PATCH 021/126] MPS::Improve the heuristics for choosing the algorithm in sample_measure (#994) * Rewrote the method sample_measure to choose heuristically between the two algorithms. The heuristics were determined experimentally Co-authored-by: Christopher J. Wood --- .../providers/aer/backends/qasm_simulator.py | 10 +++ .../matrix_product_state.hpp | 75 +++++++++++++------ .../matrix_product_state_internal.cpp | 21 +++++- .../matrix_product_state_internal.hpp | 26 +++---- 4 files changed, 93 insertions(+), 39 deletions(-) diff --git a/qiskit/providers/aer/backends/qasm_simulator.py b/qiskit/providers/aer/backends/qasm_simulator.py index f781078538..fe9954f25d 100644 --- a/qiskit/providers/aer/backends/qasm_simulator.py +++ b/qiskit/providers/aer/backends/qasm_simulator.py @@ -222,6 +222,16 @@ class QasmSimulator(AerBackend): their squares is smaller than this threshold. (Default: 1e-16). + * ``mps_sample_measure_algorithm`` (str): + Choose which algorithm to use for ``"sample_measure"``. ``"mps_probabilities"`` + means all state probabilities are computed and measurements are based on them. + It is more efficient for a large number of shots, small number of qubits and low + entanglement. ``"mps_apply_measure"`` creates a copy of the mps structure and + makes a measurement on it. It is more effients for a small number of shots, high + number of qubits, and low entanglement. If the user does not specify the algorithm, + a heuristic algorithm is used to select between the two algorithms. + (Default: "mps_heuristic"). + These backend options apply in circuit optimization passes: * ``fusion_enable`` (bool): Enable fusion optimization in circuit diff --git a/src/simulators/matrix_product_state/matrix_product_state.hpp b/src/simulators/matrix_product_state/matrix_product_state.hpp index 74b22a33cf..09f9fb985c 100644 --- a/src/simulators/matrix_product_state/matrix_product_state.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state.hpp @@ -422,17 +422,17 @@ void State::set_config(const json_t &config) { else MPS::set_omp_threads(1); - uint_t index_size; - if (JSON::get_value(index_size, "mps_sample_measure_qubits_opt", config)) // Set the sample measure qubit size - MPS::set_sample_measure_index_size(index_size); - else - MPS::set_sample_measure_index_size(26); - - uint_t shots_num; - if (JSON::get_value(shots_num, "mps_sample_measure_shots_opt", config)) - MPS::set_sample_measure_shots_thresh(shots_num); - else - MPS::set_sample_measure_shots_thresh(10); +// Set the algorithm for sample measure + std::string alg; + if (JSON::get_value(alg, "mps_sample_measure_algorithm", config)) { + if (alg.compare("mps_probabilities") == 0) { + MPS::set_sample_measure_alg(Sample_measure_alg::PROB); + } else if (alg.compare("mps_apply_measure") == 0) { + MPS::set_sample_measure_alg(Sample_measure_alg::APPLY_MEASURE); + } + } else { + MPS::set_sample_measure_alg(Sample_measure_alg::HEURISTIC); + } } void State::add_metadata(ExperimentResult &result) const { @@ -441,6 +441,9 @@ void State::add_metadata(ExperimentResult &result) const { result.add_metadata("matrix_product_state_max_bond_dimension", MPS_Tensor::get_max_bond_dimension()); + + result.add_metadata("matrix_product_state_sample_measure_algorithm", + MPS::get_sample_measure_alg()); } //========================================================================= @@ -794,19 +797,49 @@ std::vector State::sample_measure(const reg_t &qubits, uint_t shots, RngEngine &rng) { - uint_t num_measured_qubits = qubits.size(); - // There are two alternative algorithms for sample measure // We choose the one that is optimal relative to the total number - //of qubits,and the number of shots. + // of qubits,and the number of shots. // The parameters used below are based on experimentation. - if (num_measured_qubits > MPS::get_sample_measure_index_size() || - shots < MPS::get_sample_measure_shots_thresh()) { - return sample_measure_using_apply_measure(qubits, shots, rng); - } + // The user can override this by setting the parameter "mps_sample_measure_algorithm" + uint_t num_qubits = qubits.size(); + + if (MPS::get_sample_measure_alg() == Sample_measure_alg::PROB || num_qubits < 10) + return sample_measure_using_probabilities(qubits, shots, rng); + if (MPS::get_sample_measure_alg() == Sample_measure_alg::APPLY_MEASURE || + num_qubits >26 ) + return sample_measure_using_apply_measure(qubits, shots, rng); + + double num_qubits_dbl = static_cast(num_qubits); + double shots_dbl = static_cast(shots); + + // Sample_measure_alg::HEURISTIC + uint_t max_bond_dim = qreg_.get_max_bond_dimensions(); + + if (max_bond_dim <= 2) { + if (shots_dbl < 12.0 * pow(1.85, (num_qubits_dbl-10.0))) + return sample_measure_using_apply_measure(qubits, shots, rng); + else + return sample_measure_using_probabilities(qubits, shots, rng); + } else if (max_bond_dim <= 4) { + if (shots_dbl < 3.0 * pow(1.75, (num_qubits_dbl-10.0))) + return sample_measure_using_apply_measure(qubits, shots, rng); + else + return sample_measure_using_probabilities(qubits, shots, rng); + } else if (max_bond_dim <= 8) { + if (shots_dbl < 2.5 * pow(1.65, (num_qubits_dbl-10.0))) + return sample_measure_using_apply_measure(qubits, shots, rng); + else + return sample_measure_using_probabilities(qubits, shots, rng); + } else if (max_bond_dim <= 16) { + if (shots_dbl < 0.5 * pow(1.75, (num_qubits_dbl-10.0))) + return sample_measure_using_apply_measure(qubits, shots, rng); + else + return sample_measure_using_probabilities(qubits, shots, rng); + } return sample_measure_using_probabilities(qubits, shots, rng); } - + std::vector State:: sample_measure_using_probabilities(const reg_t &qubits, uint_t shots, @@ -844,15 +877,11 @@ std::vector State:: all_samples.resize(shots); reg_t single_result; - #pragma omp parallel if (shots > MPS::get_omp_threshold() && MPS::get_omp_threads() > 1) num_threads(MPS::get_omp_threads()) - { - #pragma omp for for (int_t i=0; i(shots); i++) { temp.initialize(qreg_); single_result = temp.apply_measure(qubits, rng); all_samples[i] = single_result; } - } // end omp parallel return all_samples; } 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 63445913de..5d95ebab47 100644 --- a/src/simulators/matrix_product_state/matrix_product_state_internal.cpp +++ b/src/simulators/matrix_product_state/matrix_product_state_internal.cpp @@ -40,8 +40,7 @@ static const cmatrix_t one_measure = {{0, 0}, {1, 0}}}); uint_t MPS::omp_threads_ = 1; uint_t MPS::omp_threshold_ = 14; - uint_t MPS::sample_measure_index_size_ = 26; - uint_t MPS::sample_measure_shots_thresh_ = 10; + enum Sample_measure_alg MPS::sample_measure_alg_ = Sample_measure_alg::HEURISTIC; double MPS::json_chop_threshold_ = 1E-8; //------------------------------------------------------------------------ // local function declarations @@ -1044,6 +1043,24 @@ std::vector MPS::get_matrices_sizes() const return result; } +reg_t MPS::get_bond_dimensions() const { + reg_t result; + for(uint_t i=0; i max) + max = lambda_reg_[i].size(); + } + return max; +} + MPS_Tensor MPS::state_vec_as_MPS(const reg_t &qubits) { bool ordered = true; reg_t new_qubits; 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 a5dba3c932..712d407cfa 100644 --- a/src/simulators/matrix_product_state/matrix_product_state_internal.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state_internal.hpp @@ -31,7 +31,9 @@ enum Gates { mcx // three qubit }; -enum class Direction {RIGHT, LEFT}; + //enum class Direction {RIGHT, LEFT}; + + enum class Sample_measure_alg {APPLY_MEASURE, PROB, HEURISTIC}; //========================================================================= // MPS class @@ -201,12 +203,10 @@ class MPS{ json_chop_threshold_ = json_chop_threshold; } - static void set_sample_measure_index_size(uint_t index_size){ - sample_measure_index_size_ = index_size; - } - static void set_sample_measure_shots_thresh(uint_t index_size){ - sample_measure_shots_thresh_ = index_size; + static void set_sample_measure_alg(Sample_measure_alg alg) { + sample_measure_alg_ = alg; } + static void set_enable_gate_opt(bool enable_gate_opt) { enable_gate_opt_ = enable_gate_opt; } @@ -220,11 +220,8 @@ class MPS{ static double get_json_chop_threshold() { return json_chop_threshold_; } - static uint_t get_sample_measure_index_size() { - return sample_measure_index_size_; - } - static uint_t get_sample_measure_shots_thresh() { - return sample_measure_shots_thresh_; + static Sample_measure_alg get_sample_measure_alg() { + return sample_measure_alg_; } static bool get_enable_gate_opt() { @@ -258,7 +255,8 @@ class MPS{ //---------------------------------------------------------------- void initialize_from_statevector(uint_t num_qubits, cvector_t state_vector); - + reg_t get_bond_dimensions() const; + uint_t get_max_bond_dimensions() const; private: @@ -428,8 +426,8 @@ class MPS{ //----------------------------------------------------------------------- static uint_t omp_threads_; // Disable multithreading by default static uint_t omp_threshold_; // Qubit threshold for multithreading when enabled - static uint_t sample_measure_index_size_; // Qubit threshold for computing sample_measure using probabilities - static uint_t sample_measure_shots_thresh_; // Shots threshold for computing sample_measure using probablities + static Sample_measure_alg sample_measure_alg_; // Algorithm for computing sample_measure + static double json_chop_threshold_; // Threshold for choping small values // in JSON serialization static bool enable_gate_opt_; // allow optimizations on gates From 65e60bfffce5e591c631e48871ce1946db6507bf Mon Sep 17 00:00:00 2001 From: "Christopher J. Wood" Date: Thu, 15 Oct 2020 16:57:11 -0400 Subject: [PATCH 022/126] Release 0.7.0 (#993) * Move release notes to 0.7 folder * Update readme example to include ideal and noisy simulation --- README.md | 50 +++++++++---------- .../aer/noise/errors/readout_error.py | 2 +- ...tatevector-precision-24350e9fd7368c24.yaml | 2 +- .../0.7/0.7.0-release-a6655712e304234b.yaml | 15 ++++++ .../add-openblas-lapack-67ad654d1148a309.yaml | 0 .../basis-gates-acbc8a1a52a49413.yaml | 21 +++++++- ...onfigurable-backends-a55cd6a39a0a1561.yaml | 4 ++ ...te-snapshot-variance-7d02188deacf9a08.yaml | 2 +- .../{ => 0.7}/drop-py35-814876e9d7354a39.yaml | 0 ...ix-cpp-for-loop-refs-5a6bb879bf58a4fb.yaml | 0 .../fix-snapshot-copy-54ee685094d1e261.yaml | 0 .../fix-y-expectation-1ad355c31b4c3247.yaml | 0 .../fusion-threshold-33127b9b4e219640.yaml | 19 +++++++ .../global-phase-9fc2105dac076f48.yaml | 0 .../kraus-noise-fusion-5577d4a38862e966.yaml | 2 +- ...move-final-snapshots-1cdc5e93b4695324.yaml | 0 .../0.7/mps-apply-kraus-3cc8de65a66385ab.yaml | 9 ++++ .../mps-density-matrix-51f7d5b1ef51e746.yaml | 9 ++++ .../pybind-functors-a0b7b357fbe67dfb.yaml | 0 .../simd-support-c2352ca3d639770f.yaml | 0 ...e-memory-statevector-d1b4fc48b002856f.yaml | 0 .../vector-class-ee57ad715b18cc55.yaml | 0 .../fusion-threshold-33127b9b4e219640.yaml | 11 ---- .../mps-apply-kraus-3cc8de65a66385ab.yaml | 8 --- .../mps-density-matrix-51f7d5b1ef51e746.yaml | 7 --- .../rotation-gates-7c09f4565329ca78.yaml | 16 ------ 26 files changed, 103 insertions(+), 74 deletions(-) rename releasenotes/notes/{ => 0.6}/fix-statevector-precision-24350e9fd7368c24.yaml (73%) create mode 100644 releasenotes/notes/0.7/0.7.0-release-a6655712e304234b.yaml rename releasenotes/notes/{ => 0.7}/add-openblas-lapack-67ad654d1148a309.yaml (100%) rename releasenotes/notes/{ => 0.7}/basis-gates-acbc8a1a52a49413.yaml (68%) rename releasenotes/notes/{ => 0.7}/configurable-backends-a55cd6a39a0a1561.yaml (88%) rename releasenotes/notes/{ => 0.7}/deprecate-snapshot-variance-7d02188deacf9a08.yaml (81%) rename releasenotes/notes/{ => 0.7}/drop-py35-814876e9d7354a39.yaml (100%) rename releasenotes/notes/{ => 0.7}/fix-cpp-for-loop-refs-5a6bb879bf58a4fb.yaml (100%) rename releasenotes/notes/{ => 0.7}/fix-snapshot-copy-54ee685094d1e261.yaml (100%) rename releasenotes/notes/{ => 0.7}/fix-y-expectation-1ad355c31b4c3247.yaml (100%) create mode 100644 releasenotes/notes/0.7/fusion-threshold-33127b9b4e219640.yaml rename releasenotes/notes/{ => 0.7}/global-phase-9fc2105dac076f48.yaml (100%) rename releasenotes/notes/{ => 0.7}/kraus-noise-fusion-5577d4a38862e966.yaml (97%) rename releasenotes/notes/{ => 0.7}/move-final-snapshots-1cdc5e93b4695324.yaml (100%) create mode 100644 releasenotes/notes/0.7/mps-apply-kraus-3cc8de65a66385ab.yaml create mode 100644 releasenotes/notes/0.7/mps-density-matrix-51f7d5b1ef51e746.yaml rename releasenotes/notes/{ => 0.7}/pybind-functors-a0b7b357fbe67dfb.yaml (100%) rename releasenotes/notes/{ => 0.7}/simd-support-c2352ca3d639770f.yaml (100%) rename releasenotes/notes/{ => 0.7}/validate-memory-statevector-d1b4fc48b002856f.yaml (100%) rename releasenotes/notes/{ => 0.7}/vector-class-ee57ad715b18cc55.yaml (100%) delete mode 100644 releasenotes/notes/fusion-threshold-33127b9b4e219640.yaml delete mode 100644 releasenotes/notes/mps-apply-kraus-3cc8de65a66385ab.yaml delete mode 100644 releasenotes/notes/mps-density-matrix-51f7d5b1ef51e746.yaml delete mode 100644 releasenotes/notes/rotation-gates-7c09f4565329ca78.yaml diff --git a/README.md b/README.md index 12dde86f57..822563289e 100755 --- a/README.md +++ b/README.md @@ -41,43 +41,41 @@ $ python ``` ```python -from qiskit import QuantumCircuit, execute -from qiskit import Aer, IBMQ -from qiskit.providers.aer.noise import NoiseModel - -# Choose a real device to simulate from IBMQ provider -provider = IBMQ.load_account() -backend = provider.get_backend('ibmq_vigo') -coupling_map = backend.configuration().coupling_map - -# Generate an Aer noise model for device -noise_model = NoiseModel.from_backend(backend) -basis_gates = noise_model.basis_gates +import qiskit +from qiskit import IBMQ +from qiskit.providers.aer import QasmSimulator # Generate 3-qubit GHZ state -num_qubits = 3 -circ = QuantumCircuit(3, 3) +circ = qiskit.QuantumCircuit(3, 3) circ.h(0) circ.cx(0, 1) circ.cx(1, 2) circ.measure([0, 1, 2], [0, 1 ,2]) +# Construct an ideal simulator +sim = QasmSimulator() + +# Perform an ideal simulation +result_ideal = qiskit.execute(circ, sim).result() +counts_ideal = result_ideal.get_counts(0) +print('Counts(ideal):', counts_ideal) +# Counts(ideal): {'000': 493, '111': 531} + +# Construct a noisy simulator backend from an IBMQ backend +# This simulator backend will be automatically configured +# using the device configuration and noise model +provider = IBMQ.load_account() +vigo_backend = provider.get_backend('ibmq_vigo') +vigo_sim = QasmSimulator.from_backend(vigo_backend) + # Perform noisy simulation -backend = Aer.get_backend('qasm_simulator') -job = execute(circ, backend, - coupling_map=coupling_map, - noise_model=noise_model, - basis_gates=basis_gates) -result = job.result() - -print(result.get_counts(0)) -``` +result_noise = qiskit.execute(circ, vigo_sim).result() +counts_noise = result_noise.get_counts(0) -```python -{'000': 495, '001': 18, '010': 8, '011': 18, '100': 2, '101': 14, '110': 28, '111': 441} +print('Counts(noise):', counts_noise) +# Counts(noise): {'000': 492, '001': 6, '010': 8, '011': 14, '100': 3, '101': 14, '110': 18, '111': 469} ``` - ## Contribution Guidelines If you'd like to contribute to Qiskit, please take a look at our diff --git a/qiskit/providers/aer/noise/errors/readout_error.py b/qiskit/providers/aer/noise/errors/readout_error.py index f492e2c26c..6db9072f17 100644 --- a/qiskit/providers/aer/noise/errors/readout_error.py +++ b/qiskit/providers/aer/noise/errors/readout_error.py @@ -42,7 +42,7 @@ def __init__(self, probabilities, atol=ATOL_DEFAULT): .. code-block:: python - probabilities[j] = [P(0|m), P(1|m), ..., P(2 ** N - 1|m)] + probabilities[m] = [P(0|m), P(1|m), ..., P(2 ** N - 1|m)] where ``P(j|m)`` is the probability of recording a measurement outcome of ``m`` as the value ``j``. Where ``j`` and ``m`` are integer diff --git a/releasenotes/notes/fix-statevector-precision-24350e9fd7368c24.yaml b/releasenotes/notes/0.6/fix-statevector-precision-24350e9fd7368c24.yaml similarity index 73% rename from releasenotes/notes/fix-statevector-precision-24350e9fd7368c24.yaml rename to releasenotes/notes/0.6/fix-statevector-precision-24350e9fd7368c24.yaml index a0fedb645a..6ce4056540 100644 --- a/releasenotes/notes/fix-statevector-precision-24350e9fd7368c24.yaml +++ b/releasenotes/notes/0.6/fix-statevector-precision-24350e9fd7368c24.yaml @@ -1,7 +1,7 @@ --- fixes: - | - Fixes bug in the :class:`qiskit.providers.aer.StatevectorSimulator` that + Fixes bug in the :class:`~qiskit.providers.aer.StatevectorSimulator` that caused it to always run as CPU with double-precision without SIMD/AVX2 support even on systems with AVX2, or when single-precision or the GPU method was specified in the backend options. diff --git a/releasenotes/notes/0.7/0.7.0-release-a6655712e304234b.yaml b/releasenotes/notes/0.7/0.7.0-release-a6655712e304234b.yaml new file mode 100644 index 0000000000..d6a3cf9be2 --- /dev/null +++ b/releasenotes/notes/0.7/0.7.0-release-a6655712e304234b.yaml @@ -0,0 +1,15 @@ +--- +prelude: > + This 0.7.0 release includes numerous performance improvements and + significant enhancements to the simulator interface, and drops support + for Python 3.5. + The main interface changes are configurable simulator backends, + and constructing preconfigured simulators from IBMQ backends. + Noise model an basis gate support has also been extended for most of the + Qiskit circuit library standard gates, including new support for 1 and 2-qubit + rotation gates. + Performance improvements include adding SIMD support to the density matrix + and unitary simulation methods, reducing the used memory and improving the + performance of circuits using statevector and density matrix snapshots, and + adding support for Kraus instructions to the gate fusion circuit optimization + for greatly improving the performance of noisy statevector simulations. diff --git a/releasenotes/notes/add-openblas-lapack-67ad654d1148a309.yaml b/releasenotes/notes/0.7/add-openblas-lapack-67ad654d1148a309.yaml similarity index 100% rename from releasenotes/notes/add-openblas-lapack-67ad654d1148a309.yaml rename to releasenotes/notes/0.7/add-openblas-lapack-67ad654d1148a309.yaml diff --git a/releasenotes/notes/basis-gates-acbc8a1a52a49413.yaml b/releasenotes/notes/0.7/basis-gates-acbc8a1a52a49413.yaml similarity index 68% rename from releasenotes/notes/basis-gates-acbc8a1a52a49413.yaml rename to releasenotes/notes/0.7/basis-gates-acbc8a1a52a49413.yaml index 916d720327..fc69d63e90 100644 --- a/releasenotes/notes/basis-gates-acbc8a1a52a49413.yaml +++ b/releasenotes/notes/0.7/basis-gates-acbc8a1a52a49413.yaml @@ -46,10 +46,27 @@ features: class:`~qiskit.providers.aer.StatevectorSimulator`, :class:`~qiskit.providers.aer.UnitarySimulator`, and :class:`~qiskit.providers.aer.QasmSimulator`. + - | + Adds support for 1 and 2-qubit Qiskit circuit library rotation gates + :class:`~qiskit.circuit.library.RXGate`, :class:`~qiskit.circuit.library.RYGate`, + :class:`~qiskit.circuit.library.RZGate`, :class:`~qiskit.circuit.library.RGate`, + :class:`~qiskit.circuit.library.RXXGate`, :class:`~qiskit.circuit.library.RYYGate`, + :class:`~qiskit.circuit.library.RZZGate`, :class:`~qiskit.circuit.library.RZXGate` + to the :class:`~qiskit.providers.aer.StatevectorSimulator`, + :class:`~qiskit.providers.aer.UnitarySimulator`, and the + ``"statevector"`` and ``"density_matrix"`` methods of the + :class:`~qiskit.providers.aer.QasmSimulator`. + - | + Adds support for multi-controlled rotation gates ``"mcr"``, ``"mcrx"``, + ``"mcry"``, ``"mcrz"`` + to the :class:`~qiskit.providers.aer.StatevectorSimulator`, + :class:`~qiskit.providers.aer.UnitarySimulator`, and the + ``"statevector"`` method of the + :class:`~qiskit.providers.aer.QasmSimulator`. deprecations: - | :meth:`qiskit.providers.aer.noise.NoiseModel.set_x90_single_qubit_gates` has been deprecated as unrolling to custom basis gates has been added to the qiskit transpiler. The correct way to use an X90 based noise model is to - define noise on the Sqrt(X) "sx" or "rx" gate and one of the single-qubit - phase gates "u1", "rx", "p" in the noise model. + define noise on the Sqrt(X) ``"sx"`` or ``"rx"`` gate and one of the single-qubit + phase gates ``"u1"``, ``"rx"``, or ``"p"`` in the noise model. diff --git a/releasenotes/notes/configurable-backends-a55cd6a39a0a1561.yaml b/releasenotes/notes/0.7/configurable-backends-a55cd6a39a0a1561.yaml similarity index 88% rename from releasenotes/notes/configurable-backends-a55cd6a39a0a1561.yaml rename to releasenotes/notes/0.7/configurable-backends-a55cd6a39a0a1561.yaml index 6b91dd9ca3..da08ec3068 100644 --- a/releasenotes/notes/configurable-backends-a55cd6a39a0a1561.yaml +++ b/releasenotes/notes/0.7/configurable-backends-a55cd6a39a0a1561.yaml @@ -14,6 +14,10 @@ features: and defaults will be configured automatically from the backend configuration, properties and defaults. + For example a noisy density matrix simulator backend can be constructed as + ``QasmSimulator(method='density_matrix', noise_model=noise_model)``, or an ideal + matrix product state simulator as ``QasmSimulator(method='matrix_product_state')``. + A benefit is that a :class:`~qiskit.providers.aer.PulseSimulator` instance configured from a backend better serves as a drop-in replacement to the original backend, making it easier to swap in and out a simulator and real backend, e.g. when testing code on a simulator before diff --git a/releasenotes/notes/deprecate-snapshot-variance-7d02188deacf9a08.yaml b/releasenotes/notes/0.7/deprecate-snapshot-variance-7d02188deacf9a08.yaml similarity index 81% rename from releasenotes/notes/deprecate-snapshot-variance-7d02188deacf9a08.yaml rename to releasenotes/notes/0.7/deprecate-snapshot-variance-7d02188deacf9a08.yaml index 01a17da72e..5ee827e4e0 100644 --- a/releasenotes/notes/deprecate-snapshot-variance-7d02188deacf9a08.yaml +++ b/releasenotes/notes/0.7/deprecate-snapshot-variance-7d02188deacf9a08.yaml @@ -1,7 +1,7 @@ --- deprecations: - | - The `variance` kwarg of Snapshot instructions has been deprecated. This + The ``variance`` kwarg of Snapshot instructions has been deprecated. This function computed the sample variance in the snapshot due to noise model sampling, not the variance due to measurement statistics so was often being used incorrectly. If noise modeling variance is required single shot diff --git a/releasenotes/notes/drop-py35-814876e9d7354a39.yaml b/releasenotes/notes/0.7/drop-py35-814876e9d7354a39.yaml similarity index 100% rename from releasenotes/notes/drop-py35-814876e9d7354a39.yaml rename to releasenotes/notes/0.7/drop-py35-814876e9d7354a39.yaml diff --git a/releasenotes/notes/fix-cpp-for-loop-refs-5a6bb879bf58a4fb.yaml b/releasenotes/notes/0.7/fix-cpp-for-loop-refs-5a6bb879bf58a4fb.yaml similarity index 100% rename from releasenotes/notes/fix-cpp-for-loop-refs-5a6bb879bf58a4fb.yaml rename to releasenotes/notes/0.7/fix-cpp-for-loop-refs-5a6bb879bf58a4fb.yaml diff --git a/releasenotes/notes/fix-snapshot-copy-54ee685094d1e261.yaml b/releasenotes/notes/0.7/fix-snapshot-copy-54ee685094d1e261.yaml similarity index 100% rename from releasenotes/notes/fix-snapshot-copy-54ee685094d1e261.yaml rename to releasenotes/notes/0.7/fix-snapshot-copy-54ee685094d1e261.yaml diff --git a/releasenotes/notes/fix-y-expectation-1ad355c31b4c3247.yaml b/releasenotes/notes/0.7/fix-y-expectation-1ad355c31b4c3247.yaml similarity index 100% rename from releasenotes/notes/fix-y-expectation-1ad355c31b4c3247.yaml rename to releasenotes/notes/0.7/fix-y-expectation-1ad355c31b4c3247.yaml diff --git a/releasenotes/notes/0.7/fusion-threshold-33127b9b4e219640.yaml b/releasenotes/notes/0.7/fusion-threshold-33127b9b4e219640.yaml new file mode 100644 index 0000000000..53cc3db1d3 --- /dev/null +++ b/releasenotes/notes/0.7/fusion-threshold-33127b9b4e219640.yaml @@ -0,0 +1,19 @@ +--- +upgrade: + - | + Updates gate fusion default thresholds so that gate fusion will be applied + to circuits with of more than 14 qubits for statevector simulations on the + :class:`~qiskit.providers.aer.StatevectorSimulator` and + :class:`~qiskit.providers.aer.QasmSimulator`. + + For the ``"density_matrix"`` + method of the :class:`~qiskit.providers.aer.QasmSimulator` and for the + :class:`~qiskit.providers.aer.UnitarySimulator` gate fusion will be applied + to circuits with more than 7 qubits. + + Custom qubit threshold values can be set using the ``fusion_threshold`` + backend option ie ``backend.set_options(fusion_threshold=10)`` + - | + Changes ``fusion_threshold`` backend option to apply fusion when the + number of qubits is above the threshold, not equal or above the threshold, + to match the behavior of the OpenMP qubit threshold parameter. diff --git a/releasenotes/notes/global-phase-9fc2105dac076f48.yaml b/releasenotes/notes/0.7/global-phase-9fc2105dac076f48.yaml similarity index 100% rename from releasenotes/notes/global-phase-9fc2105dac076f48.yaml rename to releasenotes/notes/0.7/global-phase-9fc2105dac076f48.yaml diff --git a/releasenotes/notes/kraus-noise-fusion-5577d4a38862e966.yaml b/releasenotes/notes/0.7/kraus-noise-fusion-5577d4a38862e966.yaml similarity index 97% rename from releasenotes/notes/kraus-noise-fusion-5577d4a38862e966.yaml rename to releasenotes/notes/0.7/kraus-noise-fusion-5577d4a38862e966.yaml index 3a6558c5bc..28e76c61e7 100644 --- a/releasenotes/notes/kraus-noise-fusion-5577d4a38862e966.yaml +++ b/releasenotes/notes/0.7/kraus-noise-fusion-5577d4a38862e966.yaml @@ -3,4 +3,4 @@ features: - | Improves general noisy statevector simulation performance by adding a Kraus method to the gate fusion circuit optimization that allows applying gate - fusion to noisy statevector simulations with general Kraus noise. + fusion to noisy statevector simulations with general Kraus noise. \ No newline at end of file diff --git a/releasenotes/notes/move-final-snapshots-1cdc5e93b4695324.yaml b/releasenotes/notes/0.7/move-final-snapshots-1cdc5e93b4695324.yaml similarity index 100% rename from releasenotes/notes/move-final-snapshots-1cdc5e93b4695324.yaml rename to releasenotes/notes/0.7/move-final-snapshots-1cdc5e93b4695324.yaml diff --git a/releasenotes/notes/0.7/mps-apply-kraus-3cc8de65a66385ab.yaml b/releasenotes/notes/0.7/mps-apply-kraus-3cc8de65a66385ab.yaml new file mode 100644 index 0000000000..7ec0f471fe --- /dev/null +++ b/releasenotes/notes/0.7/mps-apply-kraus-3cc8de65a66385ab.yaml @@ -0,0 +1,9 @@ +--- + +features: + - | + Adds support for general Kraus + :class:`~qiskit.providers.aer.noise.QauntumError` gate errors in the + :class:`~qiskit.providers.aer.noise.NoiseModel` to the + ``"matrix_product_state"`` method of the + :class:`~qiskit.providers.aer.QasmSimulator`. diff --git a/releasenotes/notes/0.7/mps-density-matrix-51f7d5b1ef51e746.yaml b/releasenotes/notes/0.7/mps-density-matrix-51f7d5b1ef51e746.yaml new file mode 100644 index 0000000000..e8ea0bf6ed --- /dev/null +++ b/releasenotes/notes/0.7/mps-density-matrix-51f7d5b1ef51e746.yaml @@ -0,0 +1,9 @@ +--- + +features: + - | + Adds support for density matrix snapshot instruction + :class:`qiskit.providers.aer.extensions.SnapshotDensityMatrix` to the + ``"matrix_product_state"`` method of the + :class:`~qiskit.providers.aer.QasmSimulator`. + diff --git a/releasenotes/notes/pybind-functors-a0b7b357fbe67dfb.yaml b/releasenotes/notes/0.7/pybind-functors-a0b7b357fbe67dfb.yaml similarity index 100% rename from releasenotes/notes/pybind-functors-a0b7b357fbe67dfb.yaml rename to releasenotes/notes/0.7/pybind-functors-a0b7b357fbe67dfb.yaml diff --git a/releasenotes/notes/simd-support-c2352ca3d639770f.yaml b/releasenotes/notes/0.7/simd-support-c2352ca3d639770f.yaml similarity index 100% rename from releasenotes/notes/simd-support-c2352ca3d639770f.yaml rename to releasenotes/notes/0.7/simd-support-c2352ca3d639770f.yaml diff --git a/releasenotes/notes/validate-memory-statevector-d1b4fc48b002856f.yaml b/releasenotes/notes/0.7/validate-memory-statevector-d1b4fc48b002856f.yaml similarity index 100% rename from releasenotes/notes/validate-memory-statevector-d1b4fc48b002856f.yaml rename to releasenotes/notes/0.7/validate-memory-statevector-d1b4fc48b002856f.yaml diff --git a/releasenotes/notes/vector-class-ee57ad715b18cc55.yaml b/releasenotes/notes/0.7/vector-class-ee57ad715b18cc55.yaml similarity index 100% rename from releasenotes/notes/vector-class-ee57ad715b18cc55.yaml rename to releasenotes/notes/0.7/vector-class-ee57ad715b18cc55.yaml diff --git a/releasenotes/notes/fusion-threshold-33127b9b4e219640.yaml b/releasenotes/notes/fusion-threshold-33127b9b4e219640.yaml deleted file mode 100644 index 5ff8ad83f5..0000000000 --- a/releasenotes/notes/fusion-threshold-33127b9b4e219640.yaml +++ /dev/null @@ -1,11 +0,0 @@ ---- -features: - - | - Changes ``"fusion_threshold"`` backend option to apply fusion when the - number of qubits is above the threshold, not equal or above the threshold, - to match the behaviour of the OpenMP qubit threshold parameter. - - | - Changes the default value of ``"fusion_threshold"`` from 20 to 14 for the - :class:`~qiskit.providers.aer.QasmSimulator` and - :class:`~qiskit.providers.aer.StatevectorSimulator`, and from 10 to 7 for - the :class:`~qiskit.providers.aer.UnitarySimulator`. diff --git a/releasenotes/notes/mps-apply-kraus-3cc8de65a66385ab.yaml b/releasenotes/notes/mps-apply-kraus-3cc8de65a66385ab.yaml deleted file mode 100644 index d24a9fc18c..0000000000 --- a/releasenotes/notes/mps-apply-kraus-3cc8de65a66385ab.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- - -features: - - | - Added support for ``apply_kraus``in ``matrix_product_state.hpp``. This - enables running the ``matrix_product_state`` simulation method with all - types of Kraus noise. - diff --git a/releasenotes/notes/mps-density-matrix-51f7d5b1ef51e746.yaml b/releasenotes/notes/mps-density-matrix-51f7d5b1ef51e746.yaml deleted file mode 100644 index 037898c262..0000000000 --- a/releasenotes/notes/mps-density-matrix-51f7d5b1ef51e746.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- - -features: - - | - Adds support for ``snapshot_density_matrix`` in the ``matrix_product_state - simulation method``. - diff --git a/releasenotes/notes/rotation-gates-7c09f4565329ca78.yaml b/releasenotes/notes/rotation-gates-7c09f4565329ca78.yaml deleted file mode 100644 index 367cfa18ac..0000000000 --- a/releasenotes/notes/rotation-gates-7c09f4565329ca78.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -features: - - | - Adds support for 1 and 2-qubit rotation gates ``"rx"``, ``"ry"``, ``"rz"``, - ``"r"``, ``"rxx"``, ``"ryy"``, ``"rzz"``, ``"rzx"`` to the - :class:`~qiskit.providers.aer.StatevectorSimulator`, - :class:`~qiskit.providers.aer.UnitarySimulator`, and the - ``"statevector"`` and ``"density_matrix"`` methods of the - :class:`~qiskit.providers.aer.StatevectorSimulator`. - - | - Adds support for multi-controlled rotation gates ``"mcr"``, ``"mcrx"``, - ``"mcry"``, ``"mcrz"`` - to the :class:`~qiskit.providers.aer.StatevectorSimulator`, - :class:`~qiskit.providers.aer.UnitarySimulator`, and the - ``"statevector"`` method of the - :class:`~qiskit.providers.aer.StatevectorSimulator`. From f715703c631574565669e5ebc3b8a8b8008a1d34 Mon Sep 17 00:00:00 2001 From: "Christopher J. Wood" Date: Fri, 16 Oct 2020 09:19:52 -0400 Subject: [PATCH 023/126] Bump version to 0.8.0 (#995) --- docs/conf.py | 2 +- qiskit/providers/aer/VERSION.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index acd01254f4..9d9f3b146e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -46,7 +46,7 @@ # The short X.Y version version = '' # The full version, including alpha/beta/rc tags -release = '0.7.0' +release = '0.8.0' # -- General configuration --------------------------------------------------- diff --git a/qiskit/providers/aer/VERSION.txt b/qiskit/providers/aer/VERSION.txt index faef31a435..a3df0a6959 100644 --- a/qiskit/providers/aer/VERSION.txt +++ b/qiskit/providers/aer/VERSION.txt @@ -1 +1 @@ -0.7.0 +0.8.0 From cb5f41400f07328b9d4328b39bae3e2d8006f1d7 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Tue, 20 Oct 2020 10:09:23 -0400 Subject: [PATCH 024/126] Add missing sdist release job (#998) In the recent aer 0.7.0 release we noticed that in the migration of CI jobs to github actions in #881 the job to create and publish and sdist at release time was lost. This commit corrects this and adds a new job to create and publish to pypi the qiskit-aer sdist at release time. --- .github/workflows/wheels.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index e08179f5e2..1a877ae9e6 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -40,6 +40,29 @@ jobs: run : | pip install -U twine twine upload wheelhouse/* + sdist: + name: Publish qiskit-aer sdist + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + name: Install Python + with: + python-version: '3.8' + - name: Install Deps + run: pip install -U twine wheel + - name: Build Artifacts + run: | + python setup.py sdist + shell: bash + - uses: actions/upload-artifact@v2 + with: + path: ./dist/qiskit* + - name: Publish to PyPi + env: + TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }} + TWINE_USERNAME: qiskit + run: twine upload dist/qiskit* gpu-build: name: Build qiskit-aer-gpu wheels runs-on: ubuntu-latest From 33f13152ad4b101e7800dfd3cfafe05dc5235f43 Mon Sep 17 00:00:00 2001 From: "Christopher J. Wood" Date: Tue, 27 Oct 2020 15:16:38 -0400 Subject: [PATCH 025/126] Fix bug in unsupported instructions error message (#1005) Fixes bug in how sets of unsupported instructions were constructed. The previous method didn't work properly with std::unordered_set. --- ...basis_gate_error_msg-04862cbd47f5f57f.yaml | 6 ++ src/framework/opset.hpp | 91 ++++++++++--------- 2 files changed, 55 insertions(+), 42 deletions(-) create mode 100644 releasenotes/notes/basis_gate_error_msg-04862cbd47f5f57f.yaml diff --git a/releasenotes/notes/basis_gate_error_msg-04862cbd47f5f57f.yaml b/releasenotes/notes/basis_gate_error_msg-04862cbd47f5f57f.yaml new file mode 100644 index 0000000000..9744aabd11 --- /dev/null +++ b/releasenotes/notes/basis_gate_error_msg-04862cbd47f5f57f.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + Fixes bug in the error message returned when a circuit contains unsupported + simulator instructions. Previously some supported instructions were also + being listed in the error message along with the unsupported instructions. diff --git a/src/framework/opset.hpp b/src/framework/opset.hpp index 66a474e110..ebee35304c 100755 --- a/src/framework/opset.hpp +++ b/src/framework/opset.hpp @@ -36,24 +36,30 @@ class OpSet { } }; - public: // Alias for set of OpTypes using optypeset_t = std::unordered_set; // Public data members - optypeset_t optypes; // A set of op types - stringset_t gates; // A set of names for OpType::gates - stringset_t snapshots; // set of types for OpType::snapshot + optypeset_t optypes; // A set of op types + stringset_t gates; // A set of names for OpType::gates + stringset_t snapshots; // set of types for OpType::snapshot OpSet() = default; - OpSet(const optypeset_t &_optypes, - const stringset_t &_gates, + OpSet(const optypeset_t &_optypes, const stringset_t &_gates, const stringset_t &_snapshots) - : optypes(_optypes), gates(_gates), snapshots(_snapshots) {} - - OpSet(const std::vector &ops) { for (const auto &op : ops) {insert(op);} } + : optypes(_optypes), gates(_gates), snapshots(_snapshots) {} + + OpSet(optypeset_t &&_optypes, stringset_t &&_gates, stringset_t &&_snapshots) + : optypes(std::move(_optypes)), gates(std::move(_gates)), + snapshots(std::move(_snapshots)) {} + + OpSet(const std::vector &ops) { + for (const auto &op : ops) { + insert(op); + } + } //----------------------------------------------------------------------- // Insert operations to the OpSet @@ -64,7 +70,7 @@ class OpSet { // Add additional op to the opset void insert(const Op &_op); - + //----------------------------------------------------------------------- // Check if operations are in the OpSet //----------------------------------------------------------------------- @@ -111,13 +117,17 @@ class OpSet { // Return a set of all gates in a set not contained in the OpSet stringset_t difference_gates(const stringset_t &_gates) const; - + // Return a set of all snapshots in a set not contained in the OpSet stringset_t difference_snapshots(const stringset_t &_snapshots) const; + // Return the difference between two unordered sets + template + static std::unordered_set + unorderedset_difference(const std::unordered_set &first, + const std::unordered_set &second); }; - //------------------------------------------------------------------------------ // OpSet class methods //------------------------------------------------------------------------------ @@ -131,18 +141,14 @@ void OpSet::insert(const Op &op) { } void OpSet::insert(const OpSet &opset) { - optypes.insert(opset.optypes.begin(), - opset.optypes.end()); - gates.insert(opset.gates.begin(), - opset.gates.end()); - snapshots.insert(opset.snapshots.begin(), - opset.snapshots.end()); + optypes.insert(opset.optypes.begin(), opset.optypes.end()); + gates.insert(opset.gates.begin(), opset.gates.end()); + snapshots.insert(opset.snapshots.begin(), opset.snapshots.end()); } bool OpSet::contains(const OpSet &_opset) const { - return (contains(_opset.optypes) - && contains_gates(_opset.gates) - && contains_snapshots(_opset.snapshots)); + return (contains(_opset.optypes) && contains_gates(_opset.gates) && + contains_snapshots(_opset.snapshots)); } bool OpSet::contains(const Op &_op) const { @@ -157,7 +163,7 @@ bool OpSet::contains(const Op &_op) const { } bool OpSet::contains(const std::vector &_ops) const { - for (const auto &op: _ops) { + for (const auto &op : _ops) { if (!contains(op)) return false; } @@ -165,7 +171,7 @@ bool OpSet::contains(const std::vector &_ops) const { } bool OpSet::contains(const OpType &_optype) const { - return !(optypes.find(_optype) == optypes.end()); + return optypes.count(_optype) == 1; } bool OpSet::contains(const optypeset_t &_optypes) const { @@ -177,7 +183,7 @@ bool OpSet::contains(const optypeset_t &_optypes) const { } bool OpSet::contains_gates(const std::string &_gate) const { - return !(gates.find(_gate) == gates.end()); + return gates.count(_gate) == 1; } bool OpSet::contains_gates(const stringset_t &_gates) const { @@ -189,7 +195,7 @@ bool OpSet::contains_gates(const stringset_t &_gates) const { } bool OpSet::contains_snapshots(const std::string &_snapshot) const { - return !(snapshots.find(_snapshot) == snapshots.end()); + return snapshots.count(_snapshot) == 1; } bool OpSet::contains_snapshots(const stringset_t &_snapshots) const { @@ -215,28 +221,29 @@ OpSet OpSet::difference(const OpSet &_opset) const { // Return a set of all optypes in set not contained in the OpSet OpSet::optypeset_t OpSet::difference(const optypeset_t &_optypes) const { - optypeset_t ret; - std::set_difference(_optypes.begin(), _optypes.end(), - optypes.begin(), optypes.end(), - std::inserter(ret, ret.begin())); - return ret; + return unorderedset_difference(optypes, _optypes); } // Return a set of all gates in a set not contained in the OpSet stringset_t OpSet::difference_gates(const stringset_t &_gates) const { - stringset_t ret; - std::set_difference(_gates.begin(), _gates.end(), - gates.begin(), gates.end(), - std::inserter(ret, ret.begin())); - return ret; + return unorderedset_difference(gates, _gates); } // Return a set of all snapshots in a set not contained in the OpSet stringset_t OpSet::difference_snapshots(const stringset_t &_snapshots) const { - stringset_t ret; - std::set_difference(_snapshots.begin(), _snapshots.end(), - snapshots.begin(), snapshots.end(), - std::inserter(ret, ret.begin())); + return unorderedset_difference(snapshots, _snapshots); +} + +template +std::unordered_set +OpSet::unorderedset_difference(const std::unordered_set &first, + const std::unordered_set &second) { + std::unordered_set ret; + for (const auto &item : second) { + if (first.count(item) == 0) { + ret.insert(item); + } + } return ret; } @@ -249,12 +256,12 @@ stringset_t OpSet::difference_snapshots(const stringset_t &_snapshots) const { // Ostream overload for opset //------------------------------------------------------------------------- -inline std::ostream& operator<<(std::ostream& out, - const AER::Operations::OpSet& opset) { +inline std::ostream &operator<<(std::ostream &out, + const AER::Operations::OpSet &opset) { bool first = true; out << "{"; if (!opset.optypes.empty()) { - out << "\"optypes\": " << opset.optypes; + out << "\"instructions\": " << opset.optypes; first = false; } if (!opset.gates.empty()) { From c61ab003aae3358efb03e003e01bbefd2a4e7c4a Mon Sep 17 00:00:00 2001 From: gadial Date: Wed, 28 Oct 2020 18:50:01 +0200 Subject: [PATCH 026/126] Multiple Pauli gates operation (#919) Co-authored-by: doichanj --- contrib/standalone/qasm_simulator.cpp | 2 + .../providers/aer/backends/qasm_simulator.py | 2 +- .../aer/backends/statevector_simulator.py | 2 +- .../aer/backends/unitary_simulator.py | 2 +- .../pauli-instruction-c3aa2c0c634e642e.yaml | 8 + src/controllers/controller.hpp | 25 + src/framework/operations.hpp | 60 ++- src/simulators/statevector/qubitvector.hpp | 107 ++++- .../statevector/qubitvector_thrust.hpp | 429 +++++++++++++++++- .../statevector/statevector_state.hpp | 10 +- src/simulators/unitary/unitary_state.hpp | 12 +- .../backends/qasm_simulator/qasm_cliffords.py | 23 + test/terra/reference/ref_1q_clifford.py | 46 ++ 13 files changed, 665 insertions(+), 63 deletions(-) create mode 100644 releasenotes/notes/pauli-instruction-c3aa2c0c634e642e.yaml diff --git a/contrib/standalone/qasm_simulator.cpp b/contrib/standalone/qasm_simulator.cpp index a821b95edf..9369e85384 100755 --- a/contrib/standalone/qasm_simulator.cpp +++ b/contrib/standalone/qasm_simulator.cpp @@ -20,8 +20,10 @@ #ifdef _MSC_VER #include #elif defined(__GNUC__) +#ifndef __PPC64__ #include #endif +#endif #include "version.hpp" // Simulator diff --git a/qiskit/providers/aer/backends/qasm_simulator.py b/qiskit/providers/aer/backends/qasm_simulator.py index fe9954f25d..b02cb9bf2e 100644 --- a/qiskit/providers/aer/backends/qasm_simulator.py +++ b/qiskit/providers/aer/backends/qasm_simulator.py @@ -264,7 +264,7 @@ class QasmSimulator(AerBackend): 'rzz', 'rzx', 'ccx', 'cswap', 'mcx', 'mcy', 'mcz', 'mcsx', 'mcp', 'mcu1', 'mcu2', 'mcu3', 'mcrx', 'mcry', 'mcrz', 'mcr', 'mcswap', 'unitary', 'diagonal', 'multiplexer', - 'initialize', 'kraus', 'roerror', 'delay' + 'initialize', 'kraus', 'roerror', 'delay', 'pauli' ], 'gates': [] } diff --git a/qiskit/providers/aer/backends/statevector_simulator.py b/qiskit/providers/aer/backends/statevector_simulator.py index 449bcca3ec..1bb5cf8a32 100644 --- a/qiskit/providers/aer/backends/statevector_simulator.py +++ b/qiskit/providers/aer/backends/statevector_simulator.py @@ -127,7 +127,7 @@ class StatevectorSimulator(AerBackend): 'rzz', 'rzx', 'ccx', 'cswap', 'mcx', 'mcy', 'mcz', 'mcsx', 'mcp', 'mcu1', 'mcu2', 'mcu3', 'mcrx', 'mcry', 'mcrz', 'mcr', 'mcswap', 'unitary', 'diagonal', 'multiplexer', - 'initialize', 'kraus', 'roerror', 'delay' + 'initialize', 'kraus', 'roerror', 'delay', 'pauli' ], 'gates': [] } diff --git a/qiskit/providers/aer/backends/unitary_simulator.py b/qiskit/providers/aer/backends/unitary_simulator.py index f7d9b735d7..8b34f71057 100644 --- a/qiskit/providers/aer/backends/unitary_simulator.py +++ b/qiskit/providers/aer/backends/unitary_simulator.py @@ -132,7 +132,7 @@ class UnitarySimulator(AerBackend): 'cy', 'cz', 'csx', 'cp', 'cu1', 'cu2', 'cu3', 'rxx', 'ryy', 'rzz', 'rzx', 'ccx', 'cswap', 'mcx', 'mcy', 'mcz', 'mcsx', 'mcp', 'mcu1', 'mcu2', 'mcu3', 'mcrx', 'mcry', 'mcrz', - 'mcr', 'mcswap', 'unitary', 'diagonal', 'multiplexer', 'delay' + 'mcr', 'mcswap', 'unitary', 'diagonal', 'multiplexer', 'delay', 'pauli' ], 'gates': [] } diff --git a/releasenotes/notes/pauli-instruction-c3aa2c0c634e642e.yaml b/releasenotes/notes/pauli-instruction-c3aa2c0c634e642e.yaml new file mode 100644 index 0000000000..340f0b16ca --- /dev/null +++ b/releasenotes/notes/pauli-instruction-c3aa2c0c634e642e.yaml @@ -0,0 +1,8 @@ +--- + +features: + - | + Adds a new gate, ``PauliGate`` which allows applying several pauli gates + to different qubits at the same time (allowing more efficient implementation + by simulators) + diff --git a/src/controllers/controller.hpp b/src/controllers/controller.hpp index b2c7fccda2..f1c8f0d85f 100755 --- a/src/controllers/controller.hpp +++ b/src/controllers/controller.hpp @@ -209,6 +209,7 @@ class Controller { int max_parallel_experiments_; int max_parallel_shots_; size_t max_memory_mb_; + size_t max_gpu_memory_mb_; // use explicit parallelization bool explicit_parallelization_; @@ -388,6 +389,30 @@ size_t Controller::get_system_memory_mb() { GlobalMemoryStatusEx(&status); total_physical_memory = status.ullTotalPhys; #endif +#ifdef AER_THRUST_CUDA + int iDev,nDev,j; + cudaGetDeviceCount(&nDev); + for(iDev=0;iDev>= 20; +#endif + return total_physical_memory >> 20; } diff --git a/src/framework/operations.hpp b/src/framework/operations.hpp index 916b504a9f..195e1d53ca 100755 --- a/src/framework/operations.hpp +++ b/src/framework/operations.hpp @@ -394,6 +394,7 @@ Op json_to_op_measure(const json_t &js); Op json_to_op_reset(const json_t &js); Op json_to_op_bfunc(const json_t &js); Op json_to_op_initialize(const json_t &js); +Op json_to_op_pauli(const json_t &js); // Snapshots Op json_to_op_snapshot(const json_t &js); @@ -414,7 +415,7 @@ Op json_to_op_roerror(const json_t &js); // Optional instruction parameters enum class Allowed {Yes, No}; -void add_condtional(const Allowed val, Op& op, const json_t &js); +void add_conditional(const Allowed val, Op& op, const json_t &js); //------------------------------------------------------------------------------ @@ -458,6 +459,8 @@ Op json_to_op(const json_t &js) { return json_to_op_kraus(js); if (name == "roerror") return json_to_op_roerror(js); + if (name == "pauli") + return json_to_op_pauli(js); // Default assume gate return json_to_op_gate(js); } @@ -488,7 +491,7 @@ json_t op_to_json(const Op &op) { //------------------------------------------------------------------------------ -void add_condtional(const Allowed allowed, Op& op, const json_t &js) { +void add_conditional(const Allowed allowed, Op& op, const json_t &js) { // Check conditional if (JSON::check_key("conditional", js)) { // If instruction isn't allow to be conditional throw an exception @@ -527,7 +530,7 @@ Op json_to_op_gate(const json_t &js) { op.string_params = {op.name}; // Conditional - add_condtional(Allowed::Yes, op, js); + add_conditional(Allowed::Yes, op, js); // Validation check_empty_name(op); @@ -549,7 +552,7 @@ Op json_to_op_barrier(const json_t &js) { op.name = "barrier"; JSON::get_value(op.qubits, "qubits", js); // Check conditional - add_condtional(Allowed::No, op, js); + add_conditional(Allowed::No, op, js); return op; } @@ -563,7 +566,7 @@ Op json_to_op_measure(const json_t &js) { JSON::get_value(op.registers, "register", js); // Conditional - add_condtional(Allowed::No, op, js); + add_conditional(Allowed::No, op, js); // Validation check_empty_qubits(op); @@ -585,7 +588,7 @@ Op json_to_op_reset(const json_t &js) { JSON::get_value(op.qubits, "qubits", js); // Conditional - add_condtional(Allowed::No, op, js); + add_conditional(Allowed::No, op, js); // Validation check_empty_qubits(op); @@ -602,7 +605,7 @@ Op json_to_op_initialize(const json_t &js) { JSON::get_value(op.params, "params", js); // Conditional - add_condtional(Allowed::No, op, js); + add_conditional(Allowed::No, op, js); // Validation check_empty_qubits(op); @@ -611,6 +614,31 @@ Op json_to_op_initialize(const json_t &js) { return op; } +Op json_to_op_pauli(const json_t &js){ + Op op; + op.type = OpType::gate; + op.name = "pauli"; + JSON::get_value(op.qubits, "qubits", js); + JSON::get_value(op.string_params, "params", js); + + // Check for optional label + // If label is not specified record the gate name as the label + std::string label; + JSON::get_value(label, "label", js); + if (label != "") + op.string_params.push_back(label); + else + op.string_params.push_back(op.name); + + // Conditional + add_conditional(Allowed::No, op, js); + + // Validation + check_empty_qubits(op); + check_duplicate_qubits(op); + + return op; +} //------------------------------------------------------------------------------ // Implementation: Boolean Functions @@ -657,7 +685,7 @@ Op json_to_op_bfunc(const json_t &js) { } // Conditional - add_condtional(Allowed::No, op, js); + add_conditional(Allowed::No, op, js); // Validation if (op.registers.empty()) { @@ -676,7 +704,7 @@ Op json_to_op_roerror(const json_t &js) { JSON::get_value(op.probs, "probabilities", js); // DEPRECATED: Remove in 0.4 JSON::get_value(op.probs, "params", js); // Conditional - add_condtional(Allowed::No, op, js); + add_conditional(Allowed::No, op, js); return op; } @@ -707,7 +735,7 @@ Op json_to_op_unitary(const json_t &js) { op.string_params.push_back(label); // Conditional - add_condtional(Allowed::Yes, op, js); + add_conditional(Allowed::Yes, op, js); return op; } @@ -736,7 +764,7 @@ Op json_to_op_diagonal(const json_t &js) { op.string_params.push_back(label); // Conditional - add_condtional(Allowed::Yes, op, js); + add_conditional(Allowed::Yes, op, js); return op; } @@ -748,7 +776,7 @@ Op json_to_op_superop(const json_t &js) { JSON::get_value(op.qubits, "qubits", js); JSON::get_value(op.mats, "params", js); // Check conditional - add_condtional(Allowed::Yes, op, js); + add_conditional(Allowed::Yes, op, js); // Validation check_empty_qubits(op); check_duplicate_qubits(op); @@ -769,7 +797,7 @@ Op json_to_op_multiplexer(const json_t &js) { // Construct op auto op = make_multiplexer(qubits, mats, label); // Conditional - add_condtional(Allowed::Yes, op, js); + add_conditional(Allowed::Yes, op, js); return op; } @@ -784,7 +812,7 @@ Op json_to_op_kraus(const json_t &js) { check_empty_qubits(op); check_duplicate_qubits(op); // Conditional - add_condtional(Allowed::Yes, op, js); + add_conditional(Allowed::Yes, op, js); return op; } @@ -795,7 +823,7 @@ Op json_to_op_noise_switch(const json_t &js) { op.name = "noise_switch"; JSON::get_value(op.params, "params", js); // Conditional - add_condtional(Allowed::No, op, js); + add_conditional(Allowed::No, op, js); return op; } @@ -814,7 +842,7 @@ Op json_to_op_snapshot(const json_t &js) { // Default snapshot: has "type", "label", "qubits" auto op = json_to_op_snapshot_default(js); // Conditional - add_condtional(Allowed::No, op, js); + add_conditional(Allowed::No, op, js); return op; } diff --git a/src/simulators/statevector/qubitvector.hpp b/src/simulators/statevector/qubitvector.hpp index 2e9223807e..a9644df5b7 100755 --- a/src/simulators/statevector/qubitvector.hpp +++ b/src/simulators/statevector/qubitvector.hpp @@ -24,7 +24,8 @@ #include #include #include -#include +#include + #include #include @@ -211,6 +212,8 @@ class QubitVector { // If N=3 this implements an optimized Fredkin gate void apply_mcswap(const reg_t &qubits); + void apply_pauli(const reg_t &qubits, const std::string &pauli); + //----------------------------------------------------------------------- // Z-measurement outcome probabilities //----------------------------------------------------------------------- @@ -363,6 +366,19 @@ class QubitVector { template void apply_lambda(Lambda&& func); + //----------------------------------------------------------------------- + // Statevector update with Lambda function on a range of entries + //----------------------------------------------------------------------- + // Apply a lambda function to all entries of the statevector + // between start and stop + // The function signature should be: + // + // [&](const int_t k)->void + // + // where k is the index of the vector + template + void apply_lambda(Lambda&& func, size_t start, size_t stop); + //----------------------------------------------------------------------- // Statevector block update with Lambda function //----------------------------------------------------------------------- @@ -908,6 +924,12 @@ void QubitVector::apply_lambda(Lambda&& func, QV::apply_lambda(0, data_size_, omp_threads_managed(), func, qubits, params); } +template +template +void QubitVector::apply_lambda(Lambda&& func, size_t start, size_t stop){ + QV::apply_lambda(start, stop, omp_threads_managed(), func); +} + //------------------------------------------------------------------------------ // Reduction Lambda @@ -1730,12 +1752,10 @@ reg_t QubitVector::sample_measure(const std::vector &rnds) const * EXPECTATION VALUES * ******************************************************************************/ - -template -double QubitVector::expval_pauli(const reg_t &qubits, - const std::string &pauli) const { - // Break string up into Z and X - // With Y being both Z and X (plus a phase) +using pauli_mask_data = std::tuple; +pauli_mask_data pauli_masks_and_phase(const reg_t &qubits, const std::string &pauli){ + // Break string up into Z and X + // With Y being both Z and X (plus a phase) const size_t N = qubits.size(); uint_t x_mask = 0; uint_t z_mask = 0; @@ -1766,18 +1786,17 @@ double QubitVector::expval_pauli(const reg_t &qubits, throw std::invalid_argument("Invalid Pauli \"" + std::to_string(pauli[N - 1 - i]) + "\"."); } } + return std::make_tuple(x_mask, z_mask, num_y, x_max); +} - // Special case for only I Paulis - if (x_mask + z_mask == 0) { - return norm(); - } - +template +void compute_phase(uint_t num_y, std::complex& phase){ // Compute the overall phase of the operator. // This is (-1j) ** number of Y terms modulo 4 - std::complex phase(1, 0); switch (num_y & 3) { case 0: // phase = 1 + phase = std::complex(1, 0); break; case 1: // phase = -1j @@ -1792,6 +1811,21 @@ double QubitVector::expval_pauli(const reg_t &qubits, phase = std::complex(0, 1); break; } +} + +template +double QubitVector::expval_pauli(const reg_t &qubits, + const std::string &pauli) const { + + uint_t x_mask, z_mask, num_y, x_max; + std::tie(x_mask, z_mask, num_y, x_max) = pauli_masks_and_phase(qubits, pauli); + + // Special case for only I Paulis + if (x_mask + z_mask == 0) { + return norm(); + } + std::complex phase; + compute_phase(num_y, phase); // specialize x_max == 0 if (!x_mask) { @@ -1827,6 +1861,53 @@ double QubitVector::expval_pauli(const reg_t &qubits, return std::real(apply_reduction_lambda(std::move(lambda), (size_t) 0, (data_size_ >> 1))); } +/******************************************************************************* + * + * PAULI + * + ******************************************************************************/ +template +void QubitVector::apply_pauli(const reg_t &qubits, const std::string &pauli){ + uint_t x_mask, z_mask, num_y, x_max; + std::tie(x_mask, z_mask, num_y, x_max) = pauli_masks_and_phase(qubits, pauli); + + // Special case for only I Paulis + if (x_mask + z_mask == 0) { + return; + } + std::complex phase; + compute_phase(num_y, phase); + const uint_t DIM = 1ULL << qubits.size(); + + // specialize x_max == 0 + if (!x_mask) { + auto lambda = [&](const int_t i)->void { + if (z_mask && (AER::Utils::popcount(i & z_mask) & 1)) { + data_[i] *= -1; + } + data_[i] *= phase; + }; + apply_lambda(lambda); + return; + } + + const uint_t mask_u = ~MASKS[x_max + 1]; + const uint_t mask_l = MASKS[x_max]; + auto lambda = [&](const int_t i)->void { + int_t idxs[2]; + idxs[0] = ((i << 1) & mask_u) | (i & mask_l); + idxs[1] = idxs[0] ^ x_mask; + for (int_t j = 0; j < 2; ++j) { + if (z_mask && (AER::Utils::popcount(idxs[j] & z_mask) & 1)) { + data_[idxs[j]] *= -1; + } + data_[idxs[j]] *= phase; + } + std::swap(data_[idxs[0]], data_[idxs[1]]); + }; + apply_lambda(lambda, (size_t) 0, (data_size_ >> 1)); +} + //------------------------------------------------------------------------------ } // end namespace QV } // end namespace AER diff --git a/src/simulators/statevector/qubitvector_thrust.hpp b/src/simulators/statevector/qubitvector_thrust.hpp index cbe77d0e80..8047e00ce4 100644 --- a/src/simulators/statevector/qubitvector_thrust.hpp +++ b/src/simulators/statevector/qubitvector_thrust.hpp @@ -999,6 +999,8 @@ class QubitVectorThrust { // If N=3 this implements an optimized Fredkin gate void apply_mcswap(const reg_t &qubits); + void apply_pauli(const reg_t &qubits, const std::string &pauli); + //----------------------------------------------------------------------- // Z-measurement outcome probabilities //----------------------------------------------------------------------- @@ -4570,12 +4572,138 @@ class expval_pauli_func : public GateFuncBase uint_t x_mask_; uint_t z_mask_; thrust::complex phase_; + uint_t nqubits_; public: - expval_pauli_func(uint_t x,uint_t z,thrust::complex p) + expval_pauli_func(uint_t x,uint_t z,thrust::complex p,int nq) { x_mask_ = x; z_mask_ = z; phase_ = p; + nqubits_ = nq; + } + + bool Reduction(void) + { + return true; + } + + __host__ __device__ double operator()(const thrust::tuple> &iter) const + { + uint_t i,j,localMask,iChunk,iPair,nPair,gid; + uint_t idx,ii,mask,t; + thrust::complex* pV; + uint_t* offsets; + uint_t* qubits; + thrust::complex q0; + thrust::complex q1; + thrust::complex q0p; + thrust::complex q1p; + double d0,d1,ret = 0.0; + struct GateParams params; + + i = ExtractIndexFromTuple(iter); + params = ExtractParamsFromTuple(iter); + pV = params.buf_; + offsets = params.offsets_; + qubits = params.params_; + localMask = params.lmask_; + gid = params.gid_; + + i = ExtractIndexFromTuple(iter); + params = ExtractParamsFromTuple(iter); + pV = params.buf_; + offsets = params.offsets_; + qubits = params.params_; + localMask = params.lmask_; + gid = params.gid_; + + idx = 0; + ii = i; + for(j=0;j> j) & 1) == 1){ + gidChunk += (1ull << qubits[j]); + } + } + + //count bits (__builtin_popcountll can not be used on GPU) + count = gidChunk & z_mask_; + count = (count & 0x5555555555555555) + ((count >> 1) & 0x5555555555555555); + count = (count & 0x3333333333333333) + ((count >> 2) & 0x3333333333333333); + count = (count & 0x0f0f0f0f0f0f0f0f) + ((count >> 4) & 0x0f0f0f0f0f0f0f0f); + count = (count & 0x00ff00ff00ff00ff) + ((count >> 8) & 0x00ff00ff00ff00ff); + count = (count & 0x0000ffff0000ffff) + ((count >> 16) & 0x0000ffff0000ffff); + count = (count & 0x00000000ffffffff) + ((count >> 32) & 0x00000000ffffffff); + + if(count & 1){ + d0 = -d0; + } + + count = (gidChunk ^ x_mask_) & z_mask_; + count = (count & 0x5555555555555555) + ((count >> 1) & 0x5555555555555555); + count = (count & 0x3333333333333333) + ((count >> 2) & 0x3333333333333333); + count = (count & 0x0f0f0f0f0f0f0f0f) + ((count >> 4) & 0x0f0f0f0f0f0f0f0f); + count = (count & 0x00ff00ff00ff00ff) + ((count >> 8) & 0x00ff00ff00ff00ff); + count = (count & 0x0000ffff0000ffff) + ((count >> 16) & 0x0000ffff0000ffff); + count = (count & 0x00000000ffffffff) + ((count >> 32) & 0x00000000ffffffff); + + if(count & 1){ + d1 = -d1; + } + } + + if((localMask >> iChunk) & 1){ + ret += d0; + } + if((localMask >> iPair) & 1){ + ret += d1; + } + } + + return ret; + } + const char* Name(void) + { + return "expval_pauli"; + } +}; + +//special case Z only +template +class expval_pauli_Z_func : public GateFuncBase +{ +protected: + uint_t z_mask_; + thrust::complex phase_; +public: + expval_pauli_Z_func(uint_t z,thrust::complex p) + { + z_mask_ = z; + phase_ = p; } bool IsDiagonal(void) @@ -4589,40 +4717,40 @@ class expval_pauli_func : public GateFuncBase __host__ __device__ double operator()(const thrust::tuple> &iter) const { - uint_t i; + uint_t i,gid; thrust::complex* pV; thrust::complex q0; - thrust::complex q1; double ret = 0.0; struct GateParams params; + uint_t count; i = ExtractIndexFromTuple(iter); params = ExtractParamsFromTuple(iter); pV = params.buf_; + gid = params.gid_; q0 = pV[i]; - q1 = pV[i ^ x_mask_]; - q1 = q1 * phase_; - ret = q0.real()*q1.real() + q0.imag()*q1.imag(); - - if(z_mask_ != 0){ - uint_t count; - //count bits (__builtin_popcountll can not be used on GPU) - count = i & z_mask_; - count = (count & 0x5555555555555555) + ((count >> 1) & 0x5555555555555555); - count = (count & 0x3333333333333333) + ((count >> 2) & 0x3333333333333333); - count = (count & 0x0f0f0f0f0f0f0f0f) + ((count >> 4) & 0x0f0f0f0f0f0f0f0f); - count = (count & 0x00ff00ff00ff00ff) + ((count >> 8) & 0x00ff00ff00ff00ff); - count = (count & 0x0000ffff0000ffff) + ((count >> 16) & 0x0000ffff0000ffff); - count = (count & 0x00000000ffffffff) + ((count >> 32) & 0x00000000ffffffff); - if(count & 1) - ret = -ret; + q0 = phase_ * q0; + ret = q0.real()*q0.real() + q0.imag()*q0.imag(); + + //count bits (__builtin_popcountll can not be used on GPU) + count = (i + gid) & z_mask_; + count = (count & 0x5555555555555555) + ((count >> 1) & 0x5555555555555555); + count = (count & 0x3333333333333333) + ((count >> 2) & 0x3333333333333333); + count = (count & 0x0f0f0f0f0f0f0f0f) + ((count >> 4) & 0x0f0f0f0f0f0f0f0f); + count = (count & 0x00ff00ff00ff00ff) + ((count >> 8) & 0x00ff00ff00ff00ff); + count = (count & 0x0000ffff0000ffff) + ((count >> 16) & 0x0000ffff0000ffff); + count = (count & 0x00000000ffffffff) + ((count >> 32) & 0x00000000ffffffff); + + if(count & 1){ + ret = -ret; } + return ret; } const char* Name(void) { - return "expval_pauli"; + return "expval_pauli_Z"; } }; @@ -4630,18 +4758,19 @@ template double QubitVectorThrust::expval_pauli(const reg_t &qubits, const std::string &pauli) const { - // Break string up into Z and X - // With Y being both Z and X (plus a phase) const size_t N = qubits.size(); uint_t x_mask = 0; uint_t z_mask = 0; uint_t num_y = 0; + reg_t x_qubits; + for (size_t i = 0; i < N; ++i) { - const auto bit = BITS[qubits[i]]; + uint_t bit = 1ull << qubits[i]; switch (pauli[N - 1 - i]) { case 'I': break; case 'X': { + x_qubits.push_back(qubits[i]); x_mask += bit; break; } @@ -4650,6 +4779,7 @@ double QubitVectorThrust::expval_pauli(const reg_t &qubits, break; } case 'Y': { + x_qubits.push_back(qubits[i]); x_mask += bit; z_mask += bit; num_y++; @@ -4685,7 +4815,258 @@ double QubitVectorThrust::expval_pauli(const reg_t &qubits, phase = thrust::complex(0, 1); break; } - return apply_function(expval_pauli_func(x_mask, z_mask, phase),qubits); + + if(x_mask == 0){ + return apply_function(expval_pauli_Z_func(z_mask, phase),qubits); + } + else{ + auto qubits_sorted = x_qubits; + std::sort(qubits_sorted.begin(), qubits_sorted.end()); + + set_params(qubits_sorted); + return apply_function(expval_pauli_func(x_mask, z_mask, phase,qubits_sorted.size()),qubits_sorted); + } +} + +/******************************************************************************* + * + * PAULI + * + ******************************************************************************/ + +template +class multi_pauli_func : public GateFuncBase +{ +protected: + uint_t x_mask_; + uint_t z_mask_; + thrust::complex phase_; + uint_t nqubits_; +public: + multi_pauli_func(uint_t x,uint_t z,thrust::complex p,int nq) + { + x_mask_ = x; + z_mask_ = z; + phase_ = p; + nqubits_ = nq; + } + + __host__ __device__ double operator()(const thrust::tuple> &iter) const + { + uint_t i,j,localMask,iChunk,iPair,nPair,gid; + uint_t idx,ii,mask,t; + thrust::complex* pV; + uint_t* offsets; + uint_t* qubits; + thrust::complex q0; + thrust::complex q1; + struct GateParams params; + + i = ExtractIndexFromTuple(iter); + params = ExtractParamsFromTuple(iter); + pV = params.buf_; + offsets = params.offsets_; + qubits = params.params_; + localMask = params.lmask_; + gid = params.gid_; + + idx = 0; + ii = i; + for(j=0;j> j) & 1) == 1){ + gidChunk += (1ull << qubits[j]); + } + } + + //count bits (__builtin_popcountll can not be used on GPU) + count = gidChunk & z_mask_; + count = (count & 0x5555555555555555) + ((count >> 1) & 0x5555555555555555); + count = (count & 0x3333333333333333) + ((count >> 2) & 0x3333333333333333); + count = (count & 0x0f0f0f0f0f0f0f0f) + ((count >> 4) & 0x0f0f0f0f0f0f0f0f); + count = (count & 0x00ff00ff00ff00ff) + ((count >> 8) & 0x00ff00ff00ff00ff); + count = (count & 0x0000ffff0000ffff) + ((count >> 16) & 0x0000ffff0000ffff); + count = (count & 0x00000000ffffffff) + ((count >> 32) & 0x00000000ffffffff); + + if(count & 1){ + q0 = -q0; + } + + count = (gidChunk ^ x_mask_) & z_mask_; + count = (count & 0x5555555555555555) + ((count >> 1) & 0x5555555555555555); + count = (count & 0x3333333333333333) + ((count >> 2) & 0x3333333333333333); + count = (count & 0x0f0f0f0f0f0f0f0f) + ((count >> 4) & 0x0f0f0f0f0f0f0f0f); + count = (count & 0x00ff00ff00ff00ff) + ((count >> 8) & 0x00ff00ff00ff00ff); + count = (count & 0x0000ffff0000ffff) + ((count >> 16) & 0x0000ffff0000ffff); + count = (count & 0x00000000ffffffff) + ((count >> 32) & 0x00000000ffffffff); + + if(count & 1){ + q1 = -q1; + } + } + + if((localMask >> iChunk) & 1){ + pV[offsets[iChunk] + idx] = q1 * phase_; + } + if((localMask >> iPair) & 1){ + pV[offsets[iPair] + idx] = q0 * phase_; + } + } + + return 0.0; + } + const char* Name(void) + { + return "multi_pauli"; + } +}; + +//special case Z only +template +class multi_pauli_Z_func : public GateFuncBase +{ +protected: + uint_t z_mask_; + thrust::complex phase_; +public: + multi_pauli_Z_func(uint_t z,thrust::complex p) + { + z_mask_ = z; + phase_ = p; + } + + bool IsDiagonal(void) + { + return true; + } + + __host__ __device__ double operator()(const thrust::tuple> &iter) const + { + uint_t i,gid; + uint_t count; + thrust::complex* pV; + thrust::complex q0; + double ret = 0.0; + struct GateParams params; + + i = ExtractIndexFromTuple(iter); + params = ExtractParamsFromTuple(iter); + pV = params.buf_; + gid = params.gid_; + + q0 = pV[i]; + + //count bits (__builtin_popcountll can not be used on GPU) + count = (i + gid) & z_mask_; + count = (count & 0x5555555555555555) + ((count >> 1) & 0x5555555555555555); + count = (count & 0x3333333333333333) + ((count >> 2) & 0x3333333333333333); + count = (count & 0x0f0f0f0f0f0f0f0f) + ((count >> 4) & 0x0f0f0f0f0f0f0f0f); + count = (count & 0x00ff00ff00ff00ff) + ((count >> 8) & 0x00ff00ff00ff00ff); + count = (count & 0x0000ffff0000ffff) + ((count >> 16) & 0x0000ffff0000ffff); + count = (count & 0x00000000ffffffff) + ((count >> 32) & 0x00000000ffffffff); + + if(count & 1){ + q0 = -q0; + } + pV[i] = phase_ * q0; + + return 0.0; + } + const char* Name(void) + { + return "multi_pauli_Z"; + } +}; + +template +void QubitVectorThrust::apply_pauli(const reg_t &qubits, const std::string &pauli) +{ + const size_t N = qubits.size(); + uint_t x_mask = 0; + uint_t z_mask = 0; + uint_t num_y = 0; + reg_t x_qubits; + + for (size_t i = 0; i < N; ++i) { + uint_t bit = 1ull << qubits[i]; + switch (pauli[N - 1 - i]) { + case 'I': + break; + case 'X': { + x_qubits.push_back(qubits[i]); + x_mask += bit; + break; + } + case 'Z': { + z_mask += bit; + break; + } + case 'Y': { + x_qubits.push_back(qubits[i]); + x_mask += bit; + z_mask += bit; + num_y++; + break; + } + default: + throw std::invalid_argument("Invalid Pauli \"" + std::to_string(pauli[N - 1 - i]) + "\"."); + } + } + + // Special case for only I Paulis + if (x_mask + z_mask == 0) { + return; + } + + // Compute the overall phase of the operator. + // This is (-1j) ** number of Y terms modulo 4 + thrust::complex phase(1,0); + switch (num_y & 3) { + case 0: + // phase = 1 + break; + case 1: + // phase = -1j + phase = thrust::complex(0, -1); + break; + case 2: + // phase = -1 + phase = thrust::complex(-1, 0); + break; + case 3: + // phase = 1j + phase = thrust::complex(0, 1); + break; + } + + if(x_mask == 0){ + apply_function(multi_pauli_Z_func(z_mask, phase),qubits); + } + else{ + auto qubits_sorted = x_qubits; + std::sort(qubits_sorted.begin(), qubits_sorted.end()); + + set_params(qubits_sorted); + apply_function(multi_pauli_func(x_mask, z_mask, phase,qubits_sorted.size()),qubits_sorted); + } } //------------------------------------------------------------------------------ diff --git a/src/simulators/statevector/statevector_state.hpp b/src/simulators/statevector/statevector_state.hpp index 237f4a96b5..796c90efd4 100755 --- a/src/simulators/statevector/statevector_state.hpp +++ b/src/simulators/statevector/statevector_state.hpp @@ -46,7 +46,7 @@ const Operations::OpSet StateOpSet( "r", "rx", "ry", "rz", "rxx", "ryy", "rzz", "rzx", "ccx", "cswap", "mcx", "mcy", "mcz", "mcu1", "mcu2", "mcu3", "mcswap", "mcphase", "mcr", "mcrx", "mcry", "mcry", "sx", "csx", - "mcsx", "delay"}, + "mcsx", "delay", "pauli"}, // Snapshots {"statevector", "memory", "register", "probabilities", "probabilities_with_variance", "expectation_value_pauli", "density_matrix", @@ -60,7 +60,7 @@ enum class Gates { id, h, s, sdg, t, tdg, rxx, ryy, rzz, rzx, mcx, mcy, mcz, mcr, mcrx, mcry, - mcrz, mcp, mcu2, mcu3, mcswap, mcsx + mcrz, mcp, mcu2, mcu3, mcswap, mcsx, pauli }; // Allowed snapshots enum class @@ -355,7 +355,8 @@ const stringmap_t State::gateset_({ {"mcu3", Gates::mcu3}, // Multi-controlled-u3 {"mcphase", Gates::mcp}, // Multi-controlled-Phase gate {"mcswap", Gates::mcswap},// Multi-controlled SWAP gate - {"mcsx", Gates::mcsx} // Multi-controlled-Sqrt(X) gate + {"mcsx", Gates::mcsx}, // Multi-controlled-Sqrt(X) gate + {"pauli", Gates::pauli} // Multi-qubit Pauli gates }); template @@ -886,6 +887,9 @@ void State::apply_gate(const Operations::Op &op) { // Includes sx, csx, mcsx etc BaseState::qreg_.apply_mcu(op.qubits, Linalg::VMatrix::SX); break; + case Gates::pauli: + BaseState::qreg_.apply_pauli(op.qubits, op.string_params[0]); + break; default: // We shouldn't reach here unless there is a bug in gateset throw std::invalid_argument( diff --git a/src/simulators/unitary/unitary_state.hpp b/src/simulators/unitary/unitary_state.hpp index 9413922fd0..3529f67aed 100755 --- a/src/simulators/unitary/unitary_state.hpp +++ b/src/simulators/unitary/unitary_state.hpp @@ -18,7 +18,7 @@ #include #define _USE_MATH_DEFINES #include - +#include "simulators/state.hpp" #include "framework/json.hpp" #include "framework/utils.hpp" #include "simulators/state.hpp" @@ -43,14 +43,14 @@ const Operations::OpSet StateOpSet( "r", "rx", "ry", "rz", "rxx", "ryy", "rzz", "rzx", "ccx", "cswap", "mcx", "mcy", "mcz", "mcu1", "mcu2", "mcu3", "mcswap", "mcphase", "mcr", "mcrx", "mcry", "mcry", "sx", "csx", - "mcsx", "delay"}, + "mcsx", "delay", "pauli"}, // Snapshots {"unitary"}); // Allowed gates enum class enum class Gates { id, h, s, sdg, t, tdg, rxx, ryy, rzz, rzx, - mcx, mcy, mcz, mcr, mcrx, mcry, mcrz, mcp, mcu2, mcu3, mcswap, mcsx + mcx, mcy, mcz, mcr, mcrx, mcry, mcrz, mcp, mcu2, mcu3, mcswap, mcsx, pauli, }; //========================================================================= @@ -225,7 +225,8 @@ const stringmap_t State::gateset_({ {"mcu3", Gates::mcu3}, // Multi-controlled-u3 {"mcphase", Gates::mcp}, // Multi-controlled-Phase gate {"mcswap", Gates::mcswap},// Multi-controlled SWAP gate - {"mcsx", Gates::mcsx} // Multi-controlled-Sqrt(X) gate + {"mcsx", Gates::mcsx}, // Multi-controlled-Sqrt(X) gate + {"pauli", Gates::pauli} // Multiple pauli operations at once }); //============================================================================ @@ -392,6 +393,9 @@ void State::apply_gate(const Operations::Op &op) { case Gates::sdg: apply_gate_phase(op.qubits[0], complex_t(0., -1.)); break; + case Gates::pauli: + BaseState::qreg_.apply_pauli(op.qubits, op.string_params[0]); + break; case Gates::t: { const double isqrt2{1. / std::sqrt(2)}; apply_gate_phase(op.qubits[0], complex_t(isqrt2, isqrt2)); diff --git a/test/terra/backends/qasm_simulator/qasm_cliffords.py b/test/terra/backends/qasm_simulator/qasm_cliffords.py index a3808e946e..7e1bf840f8 100644 --- a/test/terra/backends/qasm_simulator/qasm_cliffords.py +++ b/test/terra/backends/qasm_simulator/qasm_cliffords.py @@ -237,6 +237,29 @@ def test_swap_gate_nondeterministic_default_basis_gates(self): self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) + # --------------------------------------------------------------------- + # Test pauli gate + # --------------------------------------------------------------------- + def test_pauli_gate_deterministic_default_basis_gates(self): + """Test pauli gate circuits compiling to backend default basis_gates.""" + if 'method' in self.BACKEND_OPTS: + conf = self.SIMULATOR._method_configuration(self.BACKEND_OPTS['method']) + basis_gates = conf.basis_gates + else: + basis_gates = None + shots = 100 + circuits = ref_1q_clifford.pauli_gate_circuits_deterministic( + final_measure=True) + targets = ref_1q_clifford.pauli_gate_counts_deterministic(shots) + job = execute(circuits, + self.SIMULATOR, + shots=shots, + basis_gates=basis_gates, + **self.BACKEND_OPTS) + result = job.result() + self.assertSuccess(result) + self.compare_counts(result, circuits, targets, delta=0) + class QasmCliffordTestsWaltzBasis: """QasmSimulator Clifford gate tests in Waltz u1,u2,u3,cx basis.""" diff --git a/test/terra/reference/ref_1q_clifford.py b/test/terra/reference/ref_1q_clifford.py index 5cbf4ad8c5..f32ffac6fd 100644 --- a/test/terra/reference/ref_1q_clifford.py +++ b/test/terra/reference/ref_1q_clifford.py @@ -721,3 +721,49 @@ def sdg_gate_unitary_nondeterministic(): targets.append(np.array([[1 - 1j, 1 + 1j], [1 + 1j, 1 - 1j]]) / 2) return targets + +# ========================================================================== +# Pauli gate +# ========================================================================== + +def pauli_gate_circuits_deterministic(final_measure=True): + """pauli gate test circuits with deterministic counts.""" + circuits = [] + qr = QuantumRegister(3) + if final_measure: + cr = ClassicalRegister(3) + regs = (qr, cr) + else: + regs = (qr, ) + + circuit = QuantumCircuit(*regs) + circuit.pauli('ZYX', qr) + if final_measure: + circuit.barrier(qr) + circuit.measure(qr, cr) + circuits.append(circuit) + + # HZH = X + circuit = QuantumCircuit(*regs) + circuit.h(qr[0]) + circuit.h(qr[2]) + circuit.pauli('ZZ', [qr[0], qr[2]]) + circuit.h(qr[0]) + circuit.h(qr[2]) + if final_measure: + circuit.barrier(qr) + circuit.measure(qr, cr) + circuits.append(circuit) + + return circuits + +def pauli_gate_counts_deterministic(shots, hex_counts=True): + """multipauli-gate circuits reference counts.""" + targets = [] + if hex_counts: + targets.append({'0x3': shots}) + targets.append({'0x5': shots}) + else: + targets.append({'110': shots}) + targets.append({'101': shots}) + return targets From 85473f0457048ea1ad73656f7996d72021a92957 Mon Sep 17 00:00:00 2001 From: "Christopher J. Wood" Date: Fri, 30 Oct 2020 17:41:50 -0400 Subject: [PATCH 027/126] Fix Aer provider to return new backend instances with backends/get_backend. (#1006) Updates AerProvider to return a new backend instance each time `backend` or `get_backend` is called. This is so that if the backend instance is modified with `set_options` it won't persist pass the scope of where that backend object is used. --- qiskit/providers/aer/aerprovider.py | 24 +++++++++++-------- ...er-provider-instance-38b472f3ea541977.yaml | 11 +++++++++ test/terra/extensions/test_wrappers.py | 4 +++- 3 files changed, 28 insertions(+), 11 deletions(-) create mode 100644 releasenotes/notes/aer-provider-instance-38b472f3ea541977.yaml diff --git a/qiskit/providers/aer/aerprovider.py b/qiskit/providers/aer/aerprovider.py index 2fdba50080..28881492c6 100644 --- a/qiskit/providers/aer/aerprovider.py +++ b/qiskit/providers/aer/aerprovider.py @@ -29,22 +29,26 @@ class AerProvider(BaseProvider): def __init__(self, *args, **kwargs): super().__init__(args, kwargs) - # Populate the list of Aer simulator providers. - self._backends = [QasmSimulator(provider=self), - StatevectorSimulator(provider=self), - UnitarySimulator(provider=self), - PulseSimulator(provider=self)] + # Populate the list of Aer simulator backends. + self._backends = [ + ('qasm_simulator', QasmSimulator), + ('statevector_simulator', StatevectorSimulator), + ('unitary_simulator', UnitarySimulator), + ('pulse_simulator', PulseSimulator) + ] def get_backend(self, name=None, **kwargs): return super().get_backend(name=name, **kwargs) def backends(self, name=None, filters=None, **kwargs): # pylint: disable=arguments-differ - backends = self._backends - if name: - backends = [backend for backend in backends if backend.name() == name] - - return filter_backends(backends, filters=filters, **kwargs) + # Instantiate a new backend instance so if config options + # are set they will only last as long as that backend object exists + backends = [] + for backend_name, backend_cls in self._backends: + if name is None or backend_name == name: + backends.append(backend_cls(provider=self)) + return filter_backends(backends, filters=filters) def __str__(self): return 'AerProvider' diff --git a/releasenotes/notes/aer-provider-instance-38b472f3ea541977.yaml b/releasenotes/notes/aer-provider-instance-38b472f3ea541977.yaml new file mode 100644 index 0000000000..95d97d7c51 --- /dev/null +++ b/releasenotes/notes/aer-provider-instance-38b472f3ea541977.yaml @@ -0,0 +1,11 @@ +--- +fixes: + - | + Fixes bug with :class:`~qiskit.providers.aer.AerProvider` where options set + on the returned backends using + :meth:`~qiskit.providers.aer.QasmSimulator.set_options` were stored in the + provider and would persist for subsequent calls to + :meth:`~qiskit.providers.aer.AerProvider.get_backend` for the same named + backend. Now every call to + and :meth:`~qiskit.providers.aer.AerProvider.backends` returns a new + instance of the simulator backend that can be configured. diff --git a/test/terra/extensions/test_wrappers.py b/test/terra/extensions/test_wrappers.py index 7b863b34f6..0051f17b40 100644 --- a/test/terra/extensions/test_wrappers.py +++ b/test/terra/extensions/test_wrappers.py @@ -21,6 +21,7 @@ from qiskit.providers.aer.backends.controller_wrappers import (qasm_controller_execute, statevector_controller_execute, unitary_controller_execute) +from qiskit.providers.aer.backends.backend_utils import LIBRARY_DIR from test.terra.reference import ref_algorithms, ref_measure, ref_1q_clifford from test.terra.common import QiskitAerTestCase @@ -48,7 +49,8 @@ def _create_qobj(self, backend, noise_model=None): circuit = QuantumCircuit(num_qubits) circuit.x(list(range(num_qubits))) qobj = assemble(transpile(circuit, backend), backend) - opts = {'max_parallel_threads': 1} + opts = {'max_parallel_threads': 1, + 'library_dir': LIBRARY_DIR} fqobj = backend._format_qobj(qobj, **opts, noise_model=noise_model) return fqobj.to_dict() From b9fd62b09aae4f8085cbd4b26537fcecf532a86d Mon Sep 17 00:00:00 2001 From: merav-aharoni <46567124+merav-aharoni@users.noreply.github.com> Date: Mon, 2 Nov 2020 20:43:07 +0200 Subject: [PATCH 028/126] Fixed bug in MPS::apply_kraus (#1003) * Fixed bug from issue 991. apply_kraus was working on the given qubits instead of on the internal qubits * Fixed indexing in computation of density_matrix --- .../notes/kraus-bug-a1940e9b12e40f70.yaml | 7 ++ .../matrix_product_state.hpp | 44 +------------ .../matrix_product_state_internal.cpp | 65 +++++++++++++++++-- .../matrix_product_state_internal.hpp | 8 +++ 4 files changed, 77 insertions(+), 47 deletions(-) create mode 100644 releasenotes/notes/kraus-bug-a1940e9b12e40f70.yaml diff --git a/releasenotes/notes/kraus-bug-a1940e9b12e40f70.yaml b/releasenotes/notes/kraus-bug-a1940e9b12e40f70.yaml new file mode 100644 index 0000000000..2ca171188f --- /dev/null +++ b/releasenotes/notes/kraus-bug-a1940e9b12e40f70.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - | + In MPS, apply_kraus was operating directly on the input bits in the + parameter qubits, instead of on the internal qubits. In the MPS algorithm, + the qubits are constantly moving around so all operations should be applied + to the internal qubits. diff --git a/src/simulators/matrix_product_state/matrix_product_state.hpp b/src/simulators/matrix_product_state/matrix_product_state.hpp index 09f9fb985c..8873533b68 100644 --- a/src/simulators/matrix_product_state/matrix_product_state.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state.hpp @@ -36,6 +36,7 @@ #include "simulators/state.hpp" #include "matrix_product_state_internal.hpp" #include "matrix_product_state_internal.cpp" +#include "framework/linalg/almost_equal.hpp" namespace AER { @@ -715,49 +716,10 @@ void State::apply_matrix(const reg_t &qubits, const cvector_t &vmat) { void State::apply_kraus(const reg_t &qubits, const std::vector &kmats, RngEngine &rng) { - // Check edge case for empty Kraus set (this shouldn't happen) - if (kmats.empty()) - return; // end function early - // Choose a real in [0, 1) to choose the applied kraus operator once - // the accumulated probability is greater than r. - // We know that the Kraus noise must be normalized - // So we only compute probabilities for the first N-1 kraus operators - // and infer the probability of the last one from 1 - sum of the previous - - double r = rng.rand(0., 1.); - double accum = 0.; - bool complete = false; - - cmatrix_t rho = qreg_.density_matrix(qubits); - - cmatrix_t sq_kmat; - double p = 0; - - // Loop through N-1 kraus operators - for (size_t j=0; j < kmats.size() - 1; j++) { - sq_kmat = AER::Utils::dagger(kmats[j]) * kmats[j]; - // Calculate probability - p = real(AER::Utils::trace(rho * sq_kmat)); - accum += p; - - // check if we need to apply this operator - if (accum > r) { - // rescale mat so projection is normalized - cmatrix_t temp_mat = kmats[j] * (1 / std::sqrt(p)); - apply_matrix(qubits, temp_mat); - complete = true; - break; - } - } - // check if we haven't applied a kraus operator yet - if (!complete) { - // Compute probability from accumulated - double renorm = 1 / std::sqrt(1. - accum); - cmatrix_t temp_mat = kmats.back()* renorm; - apply_matrix(qubits, temp_mat); - } + qreg_.apply_kraus(qubits, kmats, rng); } + //========================================================================= // Implementation: Reset and Measurement Sampling //========================================================================= 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 5d95ebab47..f8805db31b 100644 --- a/src/simulators/matrix_product_state/matrix_product_state_internal.cpp +++ b/src/simulators/matrix_product_state/matrix_product_state_internal.cpp @@ -648,6 +648,59 @@ void MPS::apply_diagonal_matrix(const AER::reg_t &qubits, const cvector_t &vmat) apply_matrix(qubits, diag_mat); } +void MPS::apply_kraus(const reg_t &qubits, + const std::vector &kmats, + RngEngine &rng) { + reg_t internal_qubits = get_internal_qubits(qubits); + apply_kraus_internal(qubits, kmats, rng); + +} +void MPS::apply_kraus_internal(const reg_t &qubits, + const std::vector &kmats, + RngEngine &rng) { + // Check edge case for empty Kraus set (this shouldn't happen) + if (kmats.empty()) + return; // end function early + // Choose a real in [0, 1) to choose the applied kraus operator once + // the accumulated probability is greater than r. + // We know that the Kraus noise must be normalized + // So we only compute probabilities for the first N-1 kraus operators + // and infer the probability of the last one from 1 - sum of the previous + + double r = rng.rand(0., 1.); + double accum = 0.; + bool complete = false; + + cmatrix_t rho = density_matrix_internal(qubits); + + cmatrix_t sq_kmat; + double p = 0; + + // Loop through N-1 kraus operators + for (size_t j=0; j < kmats.size() - 1; j++) { + sq_kmat = AER::Utils::dagger(kmats[j]) * kmats[j]; + // Calculate probability + p = real(AER::Utils::trace(rho * sq_kmat)); + accum += p; + + // check if we need to apply this operator + if (accum > r) { + // rescale mat so projection is normalized + cmatrix_t temp_mat = kmats[j] * (1 / std::sqrt(p)); + apply_matrix_internal(qubits, temp_mat); + complete = true; + break; + } + } + // check if we haven't applied a kraus operator yet + if (!complete) { + // Compute probability from accumulated + double renorm = 1 / std::sqrt(1. - accum); + cmatrix_t temp_mat = kmats.back()* renorm; + apply_matrix_internal(qubits, temp_mat); + } +} + void MPS::centralize_qubits(const reg_t &qubits, reg_t &new_indices, bool & ordered) { reg_t sorted_indices; @@ -781,12 +834,10 @@ cmatrix_t MPS::density_matrix_internal(const reg_t &qubits) const { MPS temp_MPS; temp_MPS.initialize(*this); - temp_MPS.centralize_qubits(qubits, new_qubits, ordered); - - MPS_Tensor psi = temp_MPS.state_vec_as_MPS(new_qubits.front(), new_qubits.back()); + MPS_Tensor psi = temp_MPS.state_vec_as_MPS(qubits); uint_t size = psi.get_dim(); cmatrix_t rho(size,size); - + // We do the reordering of qubits on a dummy vector in order to not do the reordering on psi, // since psi is a vector of matrices and this would be more costly in performance reg_t ordered_vector(size), temp_vector(size), actual_vec(size); @@ -799,6 +850,7 @@ cmatrix_t MPS::density_matrix_internal(const reg_t &qubits) const { #else #pragma omp parallel for collapse(2) if (size > omp_threshold_ && omp_threads_ > 1) num_threads(omp_threads_) #endif + for(int_t i = 0; i < static_cast(size); i++) { for(int_t j = 0; j < static_cast(size); j++) { rho(i,j) = AER::Utils::sum( AER::Utils::elementwise_multiplication( @@ -806,6 +858,7 @@ cmatrix_t MPS::density_matrix_internal(const reg_t &qubits) const { AER::Utils::conjugate(psi.get_data(actual_vec[j]))) ); } } + return rho; } @@ -849,7 +902,7 @@ double MPS::expectation_value(const reg_t &qubits, double MPS::expectation_value_internal(const reg_t &qubits, const cmatrix_t &M) const { cmatrix_t rho; - rho = density_matrix(qubits); + rho = density_matrix_internal(qubits); // Trace(rho*M). not using methods for efficiency complex_t res = 0; @@ -1084,7 +1137,7 @@ MPS_Tensor MPS::state_vec_as_MPS(uint_t first_index, uint_t last_index) const 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 + // now temp is a tensor of 2^n matrices if (last_index != num_qubits_-1) temp.mul_Gamma_by_right_Lambda(lambda_reg_[last_index]); return temp; 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 712d407cfa..69cd036817 100644 --- a/src/simulators/matrix_product_state/matrix_product_state_internal.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state_internal.hpp @@ -131,6 +131,10 @@ class MPS{ cmatrix_t density_matrix(const reg_t &qubits) const; + void apply_kraus(const reg_t &qubits, + const std::vector &kmats, + RngEngine &rng); + //--------------------------------------------------------------- // Function: expectation_value // Description: Computes expectation value of the given qubits on the given matrix. @@ -290,6 +294,10 @@ class MPS{ void apply_multi_qubit_gate(const reg_t &qubits, const cmatrix_t &mat); + void apply_kraus_internal(const reg_t &qubits, + const std::vector &kmats, + RngEngine &rng); + // The following two are helper functions for apply_multi_qubit_gate void apply_unordered_multi_qubit_gate(const reg_t &qubits, const cmatrix_t &mat); From d3fee1e8266b1dda786a426aa59cf80f3bd310c4 Mon Sep 17 00:00:00 2001 From: "Christopher J. Wood" Date: Mon, 2 Nov 2020 15:55:19 -0500 Subject: [PATCH 029/126] Add PauliGate to density matrix simulator (#1012) --- .../providers/aer/backends/qasm_simulator.py | 2 +- .../pauli-instruction-c3aa2c0c634e642e.yaml | 10 +- .../density_matrix/densitymatrix.hpp | 99 ------------ .../density_matrix/densitymatrix_state.hpp | 23 ++- .../density_matrix/densitymatrix_thrust.hpp | 147 ------------------ src/simulators/statevector/qubitvector.hpp | 31 ++-- .../statevector/qubitvector_thrust.hpp | 78 +++++----- .../statevector/statevector_state.hpp | 4 +- 8 files changed, 85 insertions(+), 309 deletions(-) diff --git a/qiskit/providers/aer/backends/qasm_simulator.py b/qiskit/providers/aer/backends/qasm_simulator.py index b02cb9bf2e..071e5f15a1 100644 --- a/qiskit/providers/aer/backends/qasm_simulator.py +++ b/qiskit/providers/aer/backends/qasm_simulator.py @@ -414,7 +414,7 @@ def _method_configuration(method=None): 'y', 'z', 'h', 's', 'sdg', 'sx', 't', 'tdg', 'swap', 'cx', 'cy', 'cz', 'csx', 'cp', 'cu1', 'cu2', 'cu3', 'rxx', 'ryy', 'rzz', 'rzx', 'ccx', 'unitary', 'diagonal', 'kraus', 'superop' - 'roerror', 'delay' + 'roerror', 'delay', 'pauli' ] # Matrix product state method diff --git a/releasenotes/notes/pauli-instruction-c3aa2c0c634e642e.yaml b/releasenotes/notes/pauli-instruction-c3aa2c0c634e642e.yaml index 340f0b16ca..7a01c3e25d 100644 --- a/releasenotes/notes/pauli-instruction-c3aa2c0c634e642e.yaml +++ b/releasenotes/notes/pauli-instruction-c3aa2c0c634e642e.yaml @@ -2,7 +2,9 @@ features: - | - Adds a new gate, ``PauliGate`` which allows applying several pauli gates - to different qubits at the same time (allowing more efficient implementation - by simulators) - + Adds support for optimized N-qubit Pauli gate ( + :class:`qiskit.circuit.library.generalized_gates.PauliGate`) to the + :class:`~qiskit.providers.aer.StatevectorSimulator`, + :class:`~qiskit.providers.aer.UnitarySimulator`, and the + statevector and density matrix methods of the + :class:`~qiskit.providers.aer.QasmSimulator`. diff --git a/src/simulators/density_matrix/densitymatrix.hpp b/src/simulators/density_matrix/densitymatrix.hpp index 9db6081360..fb017ec7fb 100755 --- a/src/simulators/density_matrix/densitymatrix.hpp +++ b/src/simulators/density_matrix/densitymatrix.hpp @@ -125,18 +125,6 @@ class DensityMatrix : public UnitaryMatrix { // outcome in [0, 2^num_qubits - 1] virtual double probability(const uint_t outcome) const override; - //----------------------------------------------------------------------- - // Expectation Value - //----------------------------------------------------------------------- - - // These functions return the expectation value for a matrix A. - // If A is hermitian these will return real values, if A is non-Hermitian - // they in general will return complex values. - - // Return the expectation value of an N-qubit Pauli matrix. - // The Pauli is input as a length N string of I,X,Y,Z characters. - double expval_pauli(const reg_t &qubits, const std::string &pauli) const; - protected: // Construct a vectorized superoperator from a vectorized matrix @@ -366,93 +354,6 @@ double DensityMatrix::probability(const uint_t outcome) const { return std::real(BaseVector::data_[outcome * shift]); } -//----------------------------------------------------------------------- -// Pauli expectation value -//----------------------------------------------------------------------- - -template -double DensityMatrix::expval_pauli(const reg_t &qubits, - const std::string &pauli) const { - - // Break string up into Z and X - // With Y being both Z and X (plus a phase) - const size_t N = qubits.size(); - uint_t x_mask = 0; - uint_t z_mask = 0; - uint_t num_y = 0; - for (size_t i = 0; i < N; ++i) { - const auto bit = BITS[qubits[i]]; - switch (pauli[N - 1 - i]) { - case 'I': - break; - case 'X': { - x_mask += bit; - break; - } - case 'Z': { - z_mask += bit; - break; - } - case 'Y': { - x_mask += bit; - z_mask += bit; - num_y++; - break; - } - default: - throw std::invalid_argument("Invalid Pauli \"" + std::to_string(pauli[N - 1 - i]) + "\"."); - } - } - - // Special case for only I Paulis - if (x_mask + z_mask == 0) { - return std::real(BaseMatrix::trace()); - } - - // Compute the overall phase of the operator. - // This is (-1j) ** number of Y terms modulo 4 - std::complex phase(1, 0); - switch (num_y & 3) { - case 0: - // phase = 1 - break; - case 1: - // phase = -1j - phase = std::complex(0, -1); - break; - case 2: - // phase = -1 - phase = std::complex(-1, 0); - break; - case 3: - // phase = 1j - phase = std::complex(0, 1); - break; - } - // The shift for density matrix indices in the vectorized vector - const size_t start = 0; - const size_t stop = BITS[num_qubits()]; - auto lambda = [&](const int_t i, double &val_re, double &val_im)->void { - (void)val_im; // unused - auto val = std::real(phase * BaseVector::data_[i ^ x_mask + stop * i]); - if (z_mask) { - // Portable implementation of __builtin_popcountll - auto count = i & z_mask; - count = (count & 0x5555555555555555) + ((count >> 1) & 0x5555555555555555); - count = (count & 0x3333333333333333) + ((count >> 2) & 0x3333333333333333); - count = (count & 0x0f0f0f0f0f0f0f0f) + ((count >> 4) & 0x0f0f0f0f0f0f0f0f); - count = (count & 0x00ff00ff00ff00ff) + ((count >> 8) & 0x00ff00ff00ff00ff); - count = (count & 0x0000ffff0000ffff) + ((count >> 16) & 0x0000ffff0000ffff); - count = (count & 0x00000000ffffffff) + ((count >> 32) & 0x00000000ffffffff); - if (count & 1) { - val = -val; - } - } - val_re += val; - }; - return std::real(BaseVector::apply_reduction_lambda(lambda, start, stop)); -} - //------------------------------------------------------------------------------ } // end namespace QV } // end namespace AER diff --git a/src/simulators/density_matrix/densitymatrix_state.hpp b/src/simulators/density_matrix/densitymatrix_state.hpp index 8ea57749a4..369565bc07 100644 --- a/src/simulators/density_matrix/densitymatrix_state.hpp +++ b/src/simulators/density_matrix/densitymatrix_state.hpp @@ -44,7 +44,7 @@ const Operations::OpSet StateOpSet( {"U", "CX", "u1", "u2", "u3", "u", "cx", "cy", "cz", "swap", "id", "x", "y", "z", "h", "s", "sdg", "t", "tdg", "ccx", "r", "rx", "ry", "rz", "rxx", "ryy", "rzz", - "rzx", "p", "cp", "cu1", "sx", "x90", "delay"}, + "rzx", "p", "cp", "cu1", "sx", "x90", "delay", "pauli"}, // Snapshots {"density_matrix", "memory", "register", "probabilities", "probabilities_with_variance", "expectation_value_pauli", @@ -53,7 +53,7 @@ const Operations::OpSet StateOpSet( // Allowed gates enum class enum class Gates { u1, u2, u3, r, rx,ry, rz, id, x, y, z, h, s, sdg, sx, t, tdg, - cx, cy, cz, swap, rxx, ryy, rzz, rzx, ccx, cp + cx, cy, cz, swap, rxx, ryy, rzz, rzx, ccx, cp, pauli }; // Allowed snapshots enum class @@ -163,6 +163,9 @@ class State : public Base::State { // Apply a Kraus error operation void apply_kraus(const reg_t &qubits, const std::vector &kraus); + // Apply an N-qubit Pauli gate + void apply_pauli(const reg_t &qubits, const std::string &pauli); + //----------------------------------------------------------------------- // Measurement Helpers //----------------------------------------------------------------------- @@ -292,7 +295,9 @@ const stringmap_t State::gateset_({ {"rzz", Gates::rzz}, // Pauli-ZZ rotation gate {"rzx", Gates::rzx}, // Pauli-ZX rotation gate // Three-qubit gates - {"ccx", Gates::ccx} // Controlled-CX gate (Toffoli) + {"ccx", Gates::ccx}, // Controlled-CX gate (Toffoli) + // Pauli gate + {"pauli", Gates::pauli} // Multi-qubit Pauli gate }); template @@ -761,6 +766,9 @@ void State::apply_gate(const Operations::Op &op) { case Gates::rzx: BaseState::qreg_.apply_unitary_matrix(op.qubits, Linalg::VMatrix::rzx(op.params[0])); break; + case Gates::pauli: + apply_pauli(op.qubits, op.string_params[0]); + break; default: // We shouldn't reach here unless there is a bug in gateset throw std::invalid_argument( @@ -785,6 +793,15 @@ void State::apply_gate_u3(uint_t qubit, double theta, double phi, reg_t({qubit}), Linalg::VMatrix::u3(theta, phi, lambda)); } +template +void State::apply_pauli(const reg_t &qubits, + const std::string &pauli) { + // Pauli as a superoperator is (-1)^num_y P\otimes P + complex_t coeff = (std::count(pauli.begin(), pauli.end(), 'Y') % 2) ? -1 : 1; + BaseState::qreg_.apply_pauli( + BaseState::qreg_.superop_qubits(qubits), pauli + pauli, coeff); +} + //========================================================================= // Implementation: Reset and Measurement Sampling //========================================================================= diff --git a/src/simulators/density_matrix/densitymatrix_thrust.hpp b/src/simulators/density_matrix/densitymatrix_thrust.hpp index ff76c3d762..3bb5bae8e9 100755 --- a/src/simulators/density_matrix/densitymatrix_thrust.hpp +++ b/src/simulators/density_matrix/densitymatrix_thrust.hpp @@ -134,18 +134,6 @@ class DensityMatrixThrust : public UnitaryMatrixThrust { // generating samples. virtual reg_t sample_measure(const std::vector &rnds) const override; - //----------------------------------------------------------------------- - // Expectation Value - //----------------------------------------------------------------------- - - // These functions return the expectation value for a matrix A. - // If A is hermitian these will return real values, if A is non-Hermitian - // they in general will return complex values. - - // Return the expectation value of an N-qubit Pauli matrix. - // The Pauli is input as a length N string of I,X,Y,Z characters. - double expval_pauli(const reg_t &qubits, const std::string &pauli) const; - protected: // Construct a vectorized superoperator from a vectorized matrix @@ -589,141 +577,6 @@ reg_t DensityMatrixThrust::sample_measure(const std::vector &rnd return samples; } -//----------------------------------------------------------------------- -// Pauli expectation value -//----------------------------------------------------------------------- - -template -class density_expval_pauli_func : public GateFuncBase -{ -protected: - int num_qubits_; - uint_t x_mask_; - uint_t z_mask_; - thrust::complex phase_; -public: - density_expval_pauli_func(int nq,uint_t x,uint_t z,thrust::complex p) - { - num_qubits_ = nq; - x_mask_ = x; - z_mask_ = z; - phase_ = p; - } - - bool IsDiagonal(void) - { - return true; - } - bool Reduction(void) - { - return true; - } - - __host__ __device__ double operator()(const thrust::tuple> &iter) const - { - uint_t i, gid; - thrust::complex* pV; - thrust::complex q0; - double ret = 0.0; - struct GateParams params; - - params = ExtractParamsFromTuple(iter); - pV = params.buf_; - i = ExtractIndexFromTuple(iter); - gid = params.gid_ + i; - - //because matrix is distributed in chunks, we have to decode address - uint_t i_row, i_col; - i_row = gid >> num_qubits_; - i_col = gid - (i_row << num_qubits_); - if(i_col != (i_row ^ x_mask_)) { - return 0.0; - } - - q0 = pV[i]; - q0 = q0 * phase_; - ret = q0.real(); - - if(z_mask_ != 0){ - //count bits (__builtin_popcountll can not be used on GPU) - uint_t count = i_row & z_mask_; - count = (count & 0x5555555555555555) + ((count >> 1) & 0x5555555555555555); - count = (count & 0x3333333333333333) + ((count >> 2) & 0x3333333333333333); - count = (count & 0x0f0f0f0f0f0f0f0f) + ((count >> 4) & 0x0f0f0f0f0f0f0f0f); - count = (count & 0x00ff00ff00ff00ff) + ((count >> 8) & 0x00ff00ff00ff00ff); - count = (count & 0x0000ffff0000ffff) + ((count >> 16) & 0x0000ffff0000ffff); - count = (count & 0x00000000ffffffff) + ((count >> 32) & 0x00000000ffffffff); - if(count & 1) - ret = -ret; - } - - return ret; - } -}; - - -template -double DensityMatrixThrust::expval_pauli(const reg_t &qubits, - const std::string &pauli) const -{ - // Break string up into Z and X - // With Y being both Z and X (plus a phase) - const size_t N = qubits.size(); - uint_t x_mask = 0; - uint_t z_mask = 0; - uint_t num_y = 0; - for (size_t i = 0; i < N; ++i) { - const auto bit = BITS[qubits[i]]; - switch (pauli[N - 1 - i]) { - case 'I': - break; - case 'X': { - x_mask += bit; - break; - } - case 'Z': { - z_mask += bit; - break; - } - case 'Y': { - x_mask += bit; - z_mask += bit; - num_y++; - break; - } - default: - throw std::invalid_argument("Invalid Pauli \"" + std::to_string(pauli[N - 1 - i]) + "\"."); - } - } - - // Special case for only I Paulis - if (x_mask + z_mask == 0) { - std::real(BaseMatrix::trace()); - } - - // Compute the overall phase of the operator. - // This is (-1j) ** number of Y terms modulo 4 - thrust::complex phase(1, 0); - switch (num_y & 3) { - case 0: - // phase = 1 - break; - case 1: - // phase = -1j - phase = thrust::complex(0, -1); - break; - case 2: - // phase = -1 - phase = thrust::complex(-1, 0); - break; - case 3: - // phase = 1j - phase = thrust::complex(0, 1); - break; - } - return BaseVector::apply_function(density_expval_pauli_func(num_qubits(),x_mask,z_mask,phase),qubits); -} - //------------------------------------------------------------------------------ } // end namespace QV } // end namespace AER diff --git a/src/simulators/statevector/qubitvector.hpp b/src/simulators/statevector/qubitvector.hpp index a9644df5b7..c3d682c4ad 100755 --- a/src/simulators/statevector/qubitvector.hpp +++ b/src/simulators/statevector/qubitvector.hpp @@ -212,7 +212,8 @@ class QubitVector { // If N=3 this implements an optimized Fredkin gate void apply_mcswap(const reg_t &qubits); - void apply_pauli(const reg_t &qubits, const std::string &pauli); + void apply_pauli(const reg_t &qubits, const std::string &pauli, + const complex_t &coeff = 1); //----------------------------------------------------------------------- // Z-measurement outcome probabilities @@ -278,7 +279,8 @@ class QubitVector { // Return the expectation value of an N-qubit Pauli matrix. // The Pauli is input as a length N string of I,X,Y,Z characters. - double expval_pauli(const reg_t &qubits, const std::string &pauli) const; + double expval_pauli(const reg_t &qubits, const std::string &pauli, + const complex_t &coeff = 1) const; //----------------------------------------------------------------------- // JSON configuration settings @@ -1790,32 +1792,34 @@ pauli_mask_data pauli_masks_and_phase(const reg_t &qubits, const std::string &pa } template -void compute_phase(uint_t num_y, std::complex& phase){ +void add_y_phase(uint_t num_y, std::complex& coeff){ + // Add overall phase to the input coefficient + // Compute the overall phase of the operator. // This is (-1j) ** number of Y terms modulo 4 switch (num_y & 3) { case 0: // phase = 1 - phase = std::complex(1, 0); break; case 1: // phase = -1j - phase = std::complex(0, -1); + coeff = std::complex(coeff.imag(), -coeff.real()); break; case 2: // phase = -1 - phase = std::complex(-1, 0); + coeff = std::complex(-coeff.real(), -coeff.imag()); break; case 3: // phase = 1j - phase = std::complex(0, 1); + coeff = std::complex(-coeff.imag(), coeff.real()); break; } } template double QubitVector::expval_pauli(const reg_t &qubits, - const std::string &pauli) const { + const std::string &pauli, + const complex_t &coeff) const { uint_t x_mask, z_mask, num_y, x_max; std::tie(x_mask, z_mask, num_y, x_max) = pauli_masks_and_phase(qubits, pauli); @@ -1824,8 +1828,8 @@ double QubitVector::expval_pauli(const reg_t &qubits, if (x_mask + z_mask == 0) { return norm(); } - std::complex phase; - compute_phase(num_y, phase); + auto phase = std::complex(coeff); + add_y_phase(num_y, phase); // specialize x_max == 0 if (!x_mask) { @@ -1867,7 +1871,8 @@ double QubitVector::expval_pauli(const reg_t &qubits, * ******************************************************************************/ template -void QubitVector::apply_pauli(const reg_t &qubits, const std::string &pauli){ +void QubitVector::apply_pauli(const reg_t &qubits, const std::string &pauli, + const complex_t &coeff){ uint_t x_mask, z_mask, num_y, x_max; std::tie(x_mask, z_mask, num_y, x_max) = pauli_masks_and_phase(qubits, pauli); @@ -1875,8 +1880,8 @@ void QubitVector::apply_pauli(const reg_t &qubits, const std::string &pa if (x_mask + z_mask == 0) { return; } - std::complex phase; - compute_phase(num_y, phase); + auto phase = std::complex(coeff); + add_y_phase(num_y, phase); const uint_t DIM = 1ULL << qubits.size(); // specialize x_max == 0 diff --git a/src/simulators/statevector/qubitvector_thrust.hpp b/src/simulators/statevector/qubitvector_thrust.hpp index 8047e00ce4..89bf1edfd6 100644 --- a/src/simulators/statevector/qubitvector_thrust.hpp +++ b/src/simulators/statevector/qubitvector_thrust.hpp @@ -999,7 +999,8 @@ class QubitVectorThrust { // If N=3 this implements an optimized Fredkin gate void apply_mcswap(const reg_t &qubits); - void apply_pauli(const reg_t &qubits, const std::string &pauli); + void apply_pauli(const reg_t &qubits, const std::string &pauli, + const complex_t &coeff = 1); //----------------------------------------------------------------------- // Z-measurement outcome probabilities @@ -1065,7 +1066,8 @@ class QubitVectorThrust { // Return the expectation value of an N-qubit Pauli matrix. // The Pauli is input as a length N string of I,X,Y,Z characters. - double expval_pauli(const reg_t &qubits, const std::string &pauli) const; + double expval_pauli(const reg_t &qubits, const std::string &pauli, + const complex_t &coeff = 1) const; //----------------------------------------------------------------------- // JSON configuration settings @@ -4565,6 +4567,31 @@ void QubitVectorThrust::DebugDump(void) const * ******************************************************************************/ +template +void add_y_phase(uint_t num_y, T& coeff){ + // Add overall phase to the input coefficient + + // Compute the overall phase of the operator. + // This is (-1j) ** number of Y terms modulo 4 + switch (num_y & 3) { + case 0: + // phase = 1 + break; + case 1: + // phase = -1j + coeff = T(coeff.imag(), -coeff.real()); + break; + case 2: + // phase = -1 + coeff = T(-coeff.real(), -coeff.imag()); + break; + case 3: + // phase = 1j + coeff = T(-coeff.imag(), coeff.real()); + break; + } +} + template class expval_pauli_func : public GateFuncBase { @@ -4756,7 +4783,8 @@ class expval_pauli_Z_func : public GateFuncBase template double QubitVectorThrust::expval_pauli(const reg_t &qubits, - const std::string &pauli) const + const std::string &pauli, + const complex_t &coeff) const { const size_t N = qubits.size(); uint_t x_mask = 0; @@ -4797,24 +4825,8 @@ double QubitVectorThrust::expval_pauli(const reg_t &qubits, // Compute the overall phase of the operator. // This is (-1j) ** number of Y terms modulo 4 - thrust::complex phase(1,0); - switch (num_y & 3) { - case 0: - // phase = 1 - break; - case 1: - // phase = -1j - phase = thrust::complex(0, -1); - break; - case 2: - // phase = -1 - phase = thrust::complex(-1, 0); - break; - case 3: - // phase = 1j - phase = thrust::complex(0, 1); - break; - } + auto phase = thrust::complex(coeff); + add_y_phase(num_y, phase); if(x_mask == 0){ return apply_function(expval_pauli_Z_func(z_mask, phase),qubits); @@ -4997,7 +5009,9 @@ class multi_pauli_Z_func : public GateFuncBase }; template -void QubitVectorThrust::apply_pauli(const reg_t &qubits, const std::string &pauli) +void QubitVectorThrust::apply_pauli(const reg_t &qubits, + const std::string &pauli, + const complex_t &coeff) { const size_t N = qubits.size(); uint_t x_mask = 0; @@ -5038,24 +5052,8 @@ void QubitVectorThrust::apply_pauli(const reg_t &qubits, const std::stri // Compute the overall phase of the operator. // This is (-1j) ** number of Y terms modulo 4 - thrust::complex phase(1,0); - switch (num_y & 3) { - case 0: - // phase = 1 - break; - case 1: - // phase = -1j - phase = thrust::complex(0, -1); - break; - case 2: - // phase = -1 - phase = thrust::complex(-1, 0); - break; - case 3: - // phase = 1j - phase = thrust::complex(0, 1); - break; - } + auto phase = thrust::complex(coeff); + add_y_phase(num_y, phase); if(x_mask == 0){ apply_function(multi_pauli_Z_func(z_mask, phase),qubits); diff --git a/src/simulators/statevector/statevector_state.hpp b/src/simulators/statevector/statevector_state.hpp index 796c90efd4..3f0b0f37ca 100755 --- a/src/simulators/statevector/statevector_state.hpp +++ b/src/simulators/statevector/statevector_state.hpp @@ -355,8 +355,8 @@ const stringmap_t State::gateset_({ {"mcu3", Gates::mcu3}, // Multi-controlled-u3 {"mcphase", Gates::mcp}, // Multi-controlled-Phase gate {"mcswap", Gates::mcswap},// Multi-controlled SWAP gate - {"mcsx", Gates::mcsx}, // Multi-controlled-Sqrt(X) gate - {"pauli", Gates::pauli} // Multi-qubit Pauli gates + {"mcsx", Gates::mcsx}, // Multi-controlled-Sqrt(X) gate + {"pauli", Gates::pauli} // Multi-qubit Pauli gate }); template From d3b927a01f996e14b742080bdb4f0307f3fc33a0 Mon Sep 17 00:00:00 2001 From: merav-aharoni <46567124+merav-aharoni@users.noreply.github.com> Date: Tue, 3 Nov 2020 09:46:54 +0200 Subject: [PATCH 030/126] Corrected qubits ordering in MPS::sample_measure_using_probabilities. (#1011) --- .../notes/sample_measure-bug-4ce3a1a6553e4900.yaml | 10 ++++++++++ .../matrix_product_state/matrix_product_state.hpp | 10 ++++++---- .../matrix_product_state_internal.cpp | 10 +++++++++- .../matrix_product_state_internal.hpp | 5 ++++- 4 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 releasenotes/notes/sample_measure-bug-4ce3a1a6553e4900.yaml diff --git a/releasenotes/notes/sample_measure-bug-4ce3a1a6553e4900.yaml b/releasenotes/notes/sample_measure-bug-4ce3a1a6553e4900.yaml new file mode 100644 index 0000000000..bb75ccb5cb --- /dev/null +++ b/releasenotes/notes/sample_measure-bug-4ce3a1a6553e4900.yaml @@ -0,0 +1,10 @@ +--- + +fixes: + - | + When invoking MPS::sample_measure, we need to first sort the qubits to the + default ordering because this is the assumption in qasm_controller.This is + done by invoking the method move_all_qubits_to_sorted_ordering. It was + correct in sample_measure_using_apply_measure, but missing in + sample_measure_using_probabilities. + diff --git a/src/simulators/matrix_product_state/matrix_product_state.hpp b/src/simulators/matrix_product_state/matrix_product_state.hpp index 8873533b68..ab76281fb5 100644 --- a/src/simulators/matrix_product_state/matrix_product_state.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state.hpp @@ -141,7 +141,7 @@ class State : public Base::State { std::vector sample_measure_using_probabilities(const reg_t &qubits, uint_t shots, - RngEngine &rng) const; + RngEngine &rng); // Computes sample_measure by copying the MPS to a temporary structure, and // applying a measurement on the temporary MPS. This is done for every shot, @@ -765,9 +765,9 @@ std::vector State::sample_measure(const reg_t &qubits, // The parameters used below are based on experimentation. // The user can override this by setting the parameter "mps_sample_measure_algorithm" uint_t num_qubits = qubits.size(); - - if (MPS::get_sample_measure_alg() == Sample_measure_alg::PROB || num_qubits < 10) + if (MPS::get_sample_measure_alg() == Sample_measure_alg::PROB){ return sample_measure_using_probabilities(qubits, shots, rng); + } if (MPS::get_sample_measure_alg() == Sample_measure_alg::APPLY_MEASURE || num_qubits >26 ) return sample_measure_using_apply_measure(qubits, shots, rng); @@ -778,6 +778,8 @@ std::vector State::sample_measure(const reg_t &qubits, // Sample_measure_alg::HEURISTIC uint_t max_bond_dim = qreg_.get_max_bond_dimensions(); + if (num_qubits <10) + return sample_measure_using_probabilities(qubits, shots, rng); if (max_bond_dim <= 2) { if (shots_dbl < 12.0 * pow(1.85, (num_qubits_dbl-10.0))) return sample_measure_using_apply_measure(qubits, shots, rng); @@ -805,7 +807,7 @@ std::vector State::sample_measure(const reg_t &qubits, std::vector State:: sample_measure_using_probabilities(const reg_t &qubits, uint_t shots, - RngEngine &rng) const { + RngEngine &rng) { // Generate flat register for storing rvector_t rnds; 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 f8805db31b..81982a5d12 100644 --- a/src/simulators/matrix_product_state/matrix_product_state_internal.cpp +++ b/src/simulators/matrix_product_state/matrix_product_state_internal.cpp @@ -1254,7 +1254,15 @@ double MPS::norm(const reg_t &qubits, const cmatrix_t &mat) const { //----------------------------------------------------------------------------- reg_t MPS::sample_measure_using_probabilities(const rvector_t &rnds, - const reg_t &qubits) const { + const reg_t &qubits) { + // since input is always sorted in qasm_controller, therefore, we must return the qubits + // to their original location (sorted) + move_all_qubits_to_sorted_ordering(); + return sample_measure_using_probabilities_internal(rnds, qubits); +} + +reg_t MPS::sample_measure_using_probabilities_internal(const rvector_t &rnds, + const reg_t &qubits) const { const uint_t SHOTS = rnds.size(); reg_t samples; samples.assign(SHOTS, 0); 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 69cd036817..3bba7f7c1e 100644 --- a/src/simulators/matrix_product_state/matrix_product_state_internal.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state_internal.hpp @@ -244,7 +244,7 @@ class MPS{ double norm(const reg_t &qubits, const cmatrix_t &mat) const; reg_t sample_measure_using_probabilities(const rvector_t &rnds, - const reg_t &qubits) const; + const reg_t &qubits); reg_t apply_measure(const reg_t &qubits, RngEngine &rng); @@ -342,6 +342,9 @@ class MPS{ uint_t apply_measure(uint_t qubit, RngEngine &rng); + reg_t sample_measure_using_probabilities_internal(const rvector_t &rnds, + const reg_t &qubits) const; + void initialize_from_matrix(uint_t num_qubits, cmatrix_t mat); //---------------------------------------------------------------- // Function name: centralize_qubits From 721fcb4dbdeda625392f66b479b9868f45b756e2 Mon Sep 17 00:00:00 2001 From: Victor Villar <59838221+vvilpas@users.noreply.github.com> Date: Wed, 4 Nov 2020 15:51:04 +0100 Subject: [PATCH 031/126] Cmake: make conan optional (#999) Co-authored-by: Drew Risinger --- CMakeLists.txt | 61 ++++++++++-------- CONTRIBUTING.md | 35 ++++++++-- cmake/conan_utils.cmake | 34 ++++++++++ cmake/dependency_utils.cmake | 64 +++++++++++++++++++ .../aer/backends/wrappers/CMakeLists.txt | 6 +- ...cmake-optional-conan-bc99a895fc4345e1.yaml | 9 +++ setup.py | 25 +++++--- src/simulators/statevector/qv_avx2.cpp | 2 +- test/CMakeLists.txt | 2 +- 9 files changed, 190 insertions(+), 48 deletions(-) create mode 100644 cmake/dependency_utils.cmake create mode 100644 releasenotes/notes/cmake-optional-conan-bc99a895fc4345e1.yaml diff --git a/CMakeLists.txt b/CMakeLists.txt index 60728b4690..9ee47483b8 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,11 +32,20 @@ option(STATIC_LINKING "Specify if we want statically link the executable (for redistribution mainly)" FALSE) option(BUILD_TESTS "Specify whether we want to build tests or not" FALSE) +# Allow disabling conan for downstream package managers. Requires all libraries to be present in path +# Default is value of environment variable if defined or ON +if(DEFINED ENV{DISABLE_CONAN}) + set(_DISABLE_CONAN_DEFAULT ENV{DISABLE_CONAN}) +else() + set(_DISABLE_CONAN_DEFAULT OFF) +endif() +option(DISABLE_CONAN "Disable Conan package manager to find dependencies. If disabled, you must have all dependencies present on your system." ${_DISABLE_CONAN_DEFAULT}) + include(CTest) include(compiler_utils) include(Linter) include(findBLASInSpecificPath) -include(conan_utils) +include(dependency_utils) # Get version information get_version(${VERSION_NUM}) @@ -124,29 +133,33 @@ endif() # # Looking for external libraries # - -setup_conan() +set(BACKEND_REDIST_DEPS "") # List of redistributable dependencies +setup_dependencies() # If we do not set them with a space CMake fails afterwards if nothing is set for this vars! set(AER_LINKER_FLAGS " ") set(AER_COMPILER_FLAGS " ") -message(STATUS "Looking for OpenMP support...") -if(APPLE) - set(OPENMP_FOUND TRUE) - if(NOT SKBUILD) - set(AER_LIBRARIES ${AER_LIBRARIES} CONAN_PKG::llvm-openmp) - else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CONAN_CXX_FLAGS_LLVM-OPENMP}") - set(AER_SIMULATOR_CPP_EXTERNAL_LIBS ${AER_SIMULATOR_CPP_EXTERNAL_LIBS} ${CONAN_INCLUDE_DIRS_LLVM-OPENMP}) - endif() -else() +if(NOT OPENMP_FOUND) # Could already be setup for macos with conan + message(STATUS "Looking for OpenMP support...") find_package(OpenMP QUIET) if(OPENMP_FOUND) set(AER_COMPILER_FLAGS "${AER_COMPILER_FLAGS} ${OpenMP_CXX_FLAGS}") set(AER_LINKER_FLAGS "${AER_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS} ${OpenMP_CXX_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") + if(APPLE) + set(AER_SIMULATOR_CPP_EXTERNAL_LIBS ${AER_SIMULATOR_CPP_EXTERNAL_LIBS} ${OpenMP_CXX_INCLUDE_DIRS}) + # On Apple and clang, we do need to link against the library unless we are building + # the Terra Addon, see issue: https://github.com/Qiskit/qiskit-aer/issues/1 + if(NOT SKBUILD) + set(AER_LIBRARIES "${AER_LIBRARIES}" "${OpenMP_${OpenMP_CXX_LIB_NAMES}_LIBRARY}") + message(STATUS "Adding Clang: ${OpenMP_${OpenMP_CXX_LIB_NAMES}_LIBRARY}") + else() + get_filename_component(OPENMP_LIB_TO_COPY ${OpenMP_${OpenMP_CXX_LIB_NAMES}_LIBRARY} REALPATH) #Needed to follow symlinks + set(BACKEND_REDIST_DEPS ${BACKEND_REDIST_DEPS} ${OPENMP_LIB_TO_COPY}) + endif() + endif() message(STATUS "OpenMP found!") message(STATUS "OpenMP_CXX_FLAGS = ${OpenMP_CXX_FLAGS}") message(STATUS "OpenMP_EXE_LINKER_FLAGS = ${OpenMP_EXE_LINKER_FLAGS}") @@ -184,7 +197,7 @@ else() set(WIN_ARCH "win32") endif() execute_process(COMMAND ${CMAKE_COMMAND} -E tar "xvfj" "${AER_SIMULATOR_CPP_SRC_DIR}/third-party/${WIN_ARCH}/lib/openblas.7z" WORKING_DIRECTORY "${AER_SIMULATOR_CPP_SRC_DIR}/third-party/${WIN_ARCH}/lib/") - set(OPENBLAS_DLLs "${AER_SIMULATOR_CPP_SRC_DIR}/third-party/${WIN_ARCH}/lib/libopenblas.dll") + set(BACKEND_REDIST_DEPS ${BACKEND_REDIST_DEPS} "${AER_SIMULATOR_CPP_SRC_DIR}/third-party/${WIN_ARCH}/lib/libopenblas.dll") set(BLAS_LIBRARIES "${AER_SIMULATOR_CPP_SRC_DIR}/third-party/${WIN_ARCH}/lib/libopenblas.dll.a") # Seems CMake is unable to find it on its own set(BLAS_FOUND True) else() @@ -236,21 +249,19 @@ if(AER_THRUST_SUPPORTED) endif() endif() set(AER_COMPILER_DEFINITIONS ${AER_COMPILER_DEFINITIONS} THRUST_DEVICE_SYSTEM=THRUST_DEVICE_SYSTEM_CUDA) - set(THRUST_DEPENDANT_LIBS "") + set(THRUST_DEPENDENT_LIBS "") elseif(AER_THRUST_BACKEND STREQUAL "TBB") message(STATUS "TBB Support found!") - set(AER_SIMULATOR_CPP_EXTERNAL_LIBS ${AER_SIMULATOR_CPP_EXTERNAL_LIBS} ${CONAN_INCLUDE_DIRS_THRUST}) - set(THRUST_DEPENDANT_LIBS CONAN_PKG::tbb) + set(THRUST_DEPENDENT_LIBS AER_DEPENDENCY_PKG::tbb) set(AER_COMPILER_DEFINITIONS ${AER_COMPILER_DEFINITIONS} AER_THRUST_CPU=TRUE) elseif(AER_THRUST_BACKEND STREQUAL "OMP") message(STATUS "Thrust library: Setting OMP backend") if(NOT OPENMP_FOUND) message(FATAL_ERROR "There's no OMP support. We cannot set Thrust backend to OMP!!") endif() - set(AER_SIMULATOR_CPP_EXTERNAL_LIBS ${AER_SIMULATOR_CPP_EXTERNAL_LIBS} ${CONAN_INCLUDE_DIRS_THRUST}) set(AER_COMPILER_DEFINITIONS ${AER_COMPILER_DEFINITIONS} AER_THRUST_CPU=TRUE) # We don't need to add OMP because it's already an AER dependency - set(THRUST_DEPENDANT_LIBS "") + set(THRUST_DEPENDENT_LIBS "") else() message(STATUS "No Thrust supported backend") set(AER_THRUST_SUPPORTED FALSE) @@ -268,16 +279,16 @@ endif() set(AER_LIBRARIES ${AER_LIBRARIES} ${BLAS_LIBRARIES} - CONAN_PKG::nlohmann_json + AER_DEPENDENCY_PKG::nlohmann_json + AER_DEPENDENCY_PKG::spdlog Threads::Threads - CONAN_PKG::spdlog ${DL_LIB} - ${THRUST_DEPENDANT_LIBS}) + ${THRUST_DEPENDENT_LIBS}) set(AER_COMPILER_DEFINITIONS ${AER_COMPILER_DEFINITIONS} ${CONAN_DEFINES}) # Cython build is only enabled if building through scikit-build. if(SKBUILD) # Terra Addon build - set(AER_LIBRARIES ${AER_LIBRARIES} CONAN_PKG::muparserx) + set(AER_LIBRARIES ${AER_LIBRARIES} AER_DEPENDENCY_PKG::muparserx) add_subdirectory(qiskit/providers/aer/pulse/qutip_extra_lite/cy) add_subdirectory(qiskit/providers/aer/backends/wrappers) add_subdirectory(src/open_pulse) @@ -320,9 +331,9 @@ else() # Standalone build PRIVATE ${AER_COMPILER_DEFINITIONS}) if(WIN32 AND NOT BLAS_LIB_PATH) add_custom_command(TARGET qasm_simulator POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different - ${OPENBLAS_DLLs} + ${BACKEND_REDIST_DEPS} $) - install(FILES ${OPENBLAS_DLLs} DESTINATION bin) + install(FILES ${BACKEND_REDIST_DEPS} DESTINATION bin) endif() install(TARGETS qasm_simulator DESTINATION bin) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5f8a0ace60..68fc2d0cdf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -249,7 +249,7 @@ window $ git clone https://github.com/Qiskit/qiskit-aer ``` -- Next, install the platform-specific dependencies for your operating system [Linux](#linux-dependencies) | [macOS](#mac-dependencies) | [Windows](#win-dependencies). +- Next, install the platform-specific dependencies for your operating system [Linux](#linux-dependencies) | [macOS](#mac-dependencies) | [Windows](#win-dependencies). - The common dependencies can then be installed via *pip*, using the `requirements-dev.txt` file, e.g.: @@ -258,11 +258,14 @@ window $ pip install -r requirements-dev.txt ``` -This will also install [**Conan**](https://conan.io/), a C/C++ package manager written in Python. This tool will handle -most of the dependencies needed by the C++ source code. Internet connection may be needed for the first build or -when dependencies are added/updated, in order to download the required packages if they are not in your **Conan** local +This will also install [**Conan**](https://conan.io/), a C/C++ package manager written in Python. This tool will handle +most of the dependencies needed by the C++ source code. Internet connection may be needed for the first build or +when dependencies are added/updated, in order to download the required packages if they are not in your **Conan** local repository. +> Note: Conan use can be disabled with the flag or environment variable ``DISABLE_CONAN=ON`` . +This is useful for building from source offline, or to reuse the installed package dependencies. + If we are only building the standalone version and do not want to install all Python requirements you can just install **Conan**: @@ -607,7 +610,7 @@ For example, qiskit-aer$ python ./setup.py bdist_wheel -- -DAER_THRUST_BACKEND=CUDA -If we want to specify the CUDA® architecture instead of letting the build system +If we want to specify the CUDA® architecture instead of letting the build system auto detect it, we can use the AER_CUDA_ARCH flag (can also be set as an ENV variable with the same name, although the flag takes precedence). For example: @@ -661,7 +664,7 @@ These are the flags: Tells CMake the directory to look for the BLAS library instead of the usual paths. If no BLAS library is found under that directory, CMake will raise an error and stop. - + It can also be set as an ENV variable with the same name, although the flag takes precedence. Values: An absolute path. @@ -700,11 +703,29 @@ These are the flags: This flag allows us we to specify the CUDA architecture instead of letting the build system auto detect it. It can also be set as an ENV variable with the same name, although the flag takes precedence. - + Values: Auto | Common | All | List of valid CUDA architecture(s). Default: Auto Example: ``python ./setup.py bdist_wheel -- -DAER_THRUST_BACKEND=CUDA -DAER_CUDA_ARCH="5.2; 5.3"`` +* DISABLE_CONAN + + This flag allows disabling the Conan package manager. This will force CMake to look for + the libraries in use on your system path, relying on FindPackage CMake mechanism and + the appropriate configuration of libraries in order to use it. + If a specific version is not found, the build system will look for any version available, + although this may produce build errors or incorrect behaviour. + + __WARNING__: This is not the official procedure to build AER. Thus, the user is responsible + of providing all needed libraries and corresponding files to make them findable to CMake. + + This is also available as the environment variable ``DISABLE_CONAN``, which overrides + the CMake flag of the same name. + + Values: ON | OFF + Default: OFF + Example: ``python ./setup.py bdist_wheel -- -DDISABLE_CONAN=ON`` + ## Tests Code contribution are expected to include tests that provide coverage for the diff --git a/cmake/conan_utils.cmake b/cmake/conan_utils.cmake index 9f9720a60b..2fbc30f53b 100644 --- a/cmake/conan_utils.cmake +++ b/cmake/conan_utils.cmake @@ -1,13 +1,20 @@ include(conan) +macro(_rename_conan_lib package) + add_library(AER_DEPENDENCY_PKG::${package} INTERFACE IMPORTED) + target_link_libraries(AER_DEPENDENCY_PKG::${package} PUBLIC INTERFACE CONAN_PKG::${package}) +endmacro() + macro(setup_conan) # Right now every dependency shall be static set(CONAN_OPTIONS ${CONAN_OPTIONS} "*:shared=False") set(REQUIREMENTS nlohmann_json/3.1.1 spdlog/1.5.0) + list(APPEND AER_CONAN_LIBS nlohmann_json spdlog) if(APPLE AND CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(REQUIREMENTS ${REQUIREMENTS} llvm-openmp/8.0.1) + list(APPEND AER_CONAN_LIBS llvm-openmp) if(SKBUILD) set(CONAN_OPTIONS ${CONAN_OPTIONS} "llvm-openmp:shared=True") endif() @@ -15,6 +22,7 @@ macro(setup_conan) if(SKBUILD) set(REQUIREMENTS ${REQUIREMENTS} muparserx/4.0.8) + list(APPEND AER_CONAN_LIBS muparserx) if(NOT MSVC) set(CONAN_OPTIONS ${CONAN_OPTIONS} "muparserx:fPIC=True") endif() @@ -22,12 +30,17 @@ macro(setup_conan) if(AER_THRUST_BACKEND AND NOT AER_THRUST_BACKEND STREQUAL "CUDA") set(REQUIREMENTS ${REQUIREMENTS} thrust/1.9.5) + list(APPEND AER_CONAN_LIBS thrust) string(TOLOWER ${AER_THRUST_BACKEND} THRUST_BACKEND) set(CONAN_OPTIONS ${CONAN_OPTIONS} "thrust:device_system=${THRUST_BACKEND}") + if(THRUST_BACKEND MATCHES "tbb") + list(APPEND AER_CONAN_LIBS tbb) + endif() endif() if(BUILD_TESTS) set(REQUIREMENTS ${REQUIREMENTS} catch2/2.12.1) + list(APPEND AER_CONAN_LIBS catch2) endif() # Add Appleclang-12 until officially supported by Conan @@ -40,4 +53,25 @@ macro(setup_conan) CMAKE_TARGETS KEEP_RPATHS BUILD missing) + + # Headers includes + if(AER_THRUST_BACKEND AND NOT AER_THRUST_BACKEND STREQUAL "CUDA") + set(AER_SIMULATOR_CPP_EXTERNAL_LIBS ${AER_SIMULATOR_CPP_EXTERNAL_LIBS} ${CONAN_INCLUDE_DIRS_THRUST}) + endif() + + # Reassign targets from CONAN_PKG to AER_DEPENDENCY_PKG + foreach(CONAN_LIB ${AER_CONAN_LIBS}) + _rename_conan_lib(${CONAN_LIB}) + endforeach() + + if(APPLE) + set(OPENMP_FOUND TRUE) + if(NOT SKBUILD) + set(AER_LIBRARIES ${AER_LIBRARIES} AER_DEPENDENCY_PKG::llvm-openmp) + else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CONAN_CXX_FLAGS_LLVM-OPENMP}") + set(AER_SIMULATOR_CPP_EXTERNAL_LIBS ${AER_SIMULATOR_CPP_EXTERNAL_LIBS} ${CONAN_INCLUDE_DIRS_LLVM-OPENMP}) + set(BACKEND_REDIST_DEPS ${BACKEND_REDIST_DEPS} "${CONAN_LIB_DIRS_LLVM-OPENMP}/libomp.dylib") + endif() + endif() endmacro() diff --git a/cmake/dependency_utils.cmake b/cmake/dependency_utils.cmake new file mode 100644 index 0000000000..0952da0a2e --- /dev/null +++ b/cmake/dependency_utils.cmake @@ -0,0 +1,64 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2020 +# +# 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. + + +macro(setup_dependencies) + # Defines AER_DEPENDENCY_PKG alias which refers to either conan-provided or system libraries. + if(DISABLE_CONAN) + _use_system_libraries() + else() + include(conan_utils) + setup_conan() + endif() +endmacro() + +macro(_use_system_libraries) + # Use system libraries + _import_aer_system_dependency(nlohmann_json 3.1.1) + _import_aer_system_dependency(spdlog 1.5.0) + + if(SKBUILD) + _import_aer_system_dependency(muparserx 4.0.8) + endif() + + if(AER_THRUST_BACKEND AND NOT AER_THRUST_BACKEND STREQUAL "CUDA") + string(TOLOWER ${AER_THRUST_BACKEND} THRUST_BACKEND) + _import_aer_system_dependency(Thrust 1.9.5) + endif() + + if(BUILD_TESTS) + _import_aer_system_dependency(Catch2 2.12.1) + endif() + + if(APPLE) + # Fix linking. See https://stackoverflow.com/questions/54068035 + link_directories(/usr/local/lib) #brew + link_directories(/opt/local/lib) #ports + endif() +endmacro() + +macro(_import_aer_system_dependency package version) + # Arguments: + # package: name of package to search for using find_package() + # version: version of package to search for + + find_package(${package} ${version} EXACT QUIET) + if(NOT ${package}_FOUND) + message(STATUS "${package} ${version} NOT found! Looking for any other version available.") + find_package(${package} REQUIRED) + message(STATUS "${package} version found: ${${package}_VERSION}. WARNING: This version may not work!!!") + endif() + string(TOLOWER ${package} PACKAGE_LOWER) # Conan use lowercase for every lib + add_library(AER_DEPENDENCY_PKG::${PACKAGE_LOWER} INTERFACE IMPORTED) + target_link_libraries(AER_DEPENDENCY_PKG::${PACKAGE_LOWER} PUBLIC INTERFACE ${package}) + message(STATUS "Using system-provided ${PACKAGE_LOWER} library") +endmacro() diff --git a/qiskit/providers/aer/backends/wrappers/CMakeLists.txt b/qiskit/providers/aer/backends/wrappers/CMakeLists.txt index c771c1d2fa..355219dd24 100644 --- a/qiskit/providers/aer/backends/wrappers/CMakeLists.txt +++ b/qiskit/providers/aer/backends/wrappers/CMakeLists.txt @@ -33,8 +33,4 @@ target_compile_definitions(controller_wrappers PRIVATE ${AER_COMPILER_DEFINITION install(TARGETS controller_wrappers LIBRARY DESTINATION qiskit/providers/aer/backends) # Install redistributable dependencies -if(APPLE) - install(FILES "${CONAN_LIB_DIRS_LLVM-OPENMP}/libomp.dylib" DESTINATION qiskit/providers/aer/backends) -elseif(WIN32 AND NOT BLAS_LIB_PATH) - install(FILES ${OPENBLAS_DLLs} DESTINATION qiskit/providers/aer/backends) -endif() +install(FILES ${BACKEND_REDIST_DEPS} DESTINATION qiskit/providers/aer/backends) diff --git a/releasenotes/notes/cmake-optional-conan-bc99a895fc4345e1.yaml b/releasenotes/notes/cmake-optional-conan-bc99a895fc4345e1.yaml new file mode 100644 index 0000000000..ba3343d86f --- /dev/null +++ b/releasenotes/notes/cmake-optional-conan-bc99a895fc4345e1.yaml @@ -0,0 +1,9 @@ +--- +features: + - | + Add the CMake flag ``DISABLE_CONAN`` (default=``OFF``)s. When installing from source, + setting this to ``ON`` allows bypassing the Conan package manager to find libraries + that are already installed on your system. This is also available as an environment + variable ``DISABLE_CONAN``, which takes precedence over the CMake flag. + This is not the official procedure to build AER. Thus, the user is responsible + of providing all needed libraries and corresponding files to make them findable to CMake. diff --git a/setup.py b/setup.py index e0d5ad6cc6..b8a2f5fee1 100644 --- a/setup.py +++ b/setup.py @@ -3,13 +3,17 @@ """ Main setup file for qiskit-aer """ - +import distutils.util +import importlib +import inspect import os +import setuptools import subprocess import sys -import inspect + PACKAGE_NAME = os.getenv('QISKIT_AER_PACKAGE_NAME', 'qiskit-aer') +_DISABLE_CONAN = distutils.util.strtobool(os.getenv("DISABLE_CONAN", "OFF").lower()) try: from Cython.Build import cythonize @@ -18,11 +22,12 @@ subprocess.call([sys.executable, '-m', 'pip', 'install', 'Cython>=0.27.1']) from Cython.Build import cythonize -try: - from conans import client -except ImportError: - subprocess.call([sys.executable, '-m', 'pip', 'install', 'conan']) - from conans import client +if not _DISABLE_CONAN: + try: + from conans import client + except ImportError: + subprocess.call([sys.executable, '-m', 'pip', 'install', 'conan']) + from conans import client try: from skbuild import setup @@ -34,7 +39,8 @@ except ImportError: subprocess.call([sys.executable, '-m', 'pip', 'install', 'pybind11>=2.4']) -import setuptools +from skbuild import setup + # These are requirements that are both runtime/install dependencies and # also build time/setup requirements and will be added to both lists @@ -52,8 +58,9 @@ setup_requirements = common_requirements + [ 'scikit-build', 'cmake!=3.17,!=3.17.0', - 'conan>=1.22.2' ] +if not _DISABLE_CONAN: + setup_requirements.append('conan>=1.22.2') requirements = common_requirements + ['qiskit-terra>=0.12.0'] diff --git a/src/simulators/statevector/qv_avx2.cpp b/src/simulators/statevector/qv_avx2.cpp index adf9f2e60f..8434e037c0 100644 --- a/src/simulators/statevector/qv_avx2.cpp +++ b/src/simulators/statevector/qv_avx2.cpp @@ -22,7 +22,7 @@ /** * DISCLAIMER: We want to compile this code in isolation of the rest of the *codebase, because it contains AVX specific instructions, so is very CPU arch - *dependant. We will detect CPU features at runtime and derive the execution + *dependent. We will detect CPU features at runtime and derive the execution *path over here if AVX is supported, if it's not supported the QubitVector *normal class will be used instead (so no SIMD whatsoever). Because of this, we *don't want to depend on any other library, otherwise the linker could take AVX diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index fe9b1589b1..4bf917e347 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -8,7 +8,7 @@ macro(add_test_executable target_name) PRIVATE ${AER_SIMULATOR_CPP_SRC_DIR} PRIVATE ${AER_SIMULATOR_CPP_EXTERNAL_LIBS}) target_link_libraries(${target_name} - PRIVATE CONAN_PKG::catch2 + PRIVATE AER_DEPENDENCY_PKG::catch2 PRIVATE ${AER_LIBRARIES}) add_test(${target_name} ${target_name}) endmacro() From efefe04be664c3d7a2253a13e6ce52be49aea7c8 Mon Sep 17 00:00:00 2001 From: Victor Villar <59838221+vvilpas@users.noreply.github.com> Date: Wed, 4 Nov 2020 23:28:12 +0100 Subject: [PATCH 032/126] Refactor where avx2 needed headers are included (#1017) Move avx2 needed headers inclusion from qasm_simulator.cpp and bindings.cc to avx2_detect.hpp, where are actually used. --- contrib/standalone/qasm_simulator.cpp | 8 -------- qiskit/providers/aer/backends/wrappers/bindings.cc | 6 ------ src/framework/avx2_detect.hpp | 7 +++++++ 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/contrib/standalone/qasm_simulator.cpp b/contrib/standalone/qasm_simulator.cpp index 9369e85384..46bff6a4ec 100755 --- a/contrib/standalone/qasm_simulator.cpp +++ b/contrib/standalone/qasm_simulator.cpp @@ -17,14 +17,6 @@ #include #include -#ifdef _MSC_VER -#include -#elif defined(__GNUC__) -#ifndef __PPC64__ -#include -#endif -#endif - #include "version.hpp" // Simulator #include "controllers/qasm_controller.hpp" diff --git a/qiskit/providers/aer/backends/wrappers/bindings.cc b/qiskit/providers/aer/backends/wrappers/bindings.cc index 9215cfe740..29572f9c23 100644 --- a/qiskit/providers/aer/backends/wrappers/bindings.cc +++ b/qiskit/providers/aer/backends/wrappers/bindings.cc @@ -1,10 +1,4 @@ #include -#include "misc/common_macros.hpp" -#if defined(_MSC_VER) -#include -#elif defined(GNUC_AVX2) -#include -#endif #include "misc/warnings.hpp" DISABLE_WARNING_PUSH diff --git a/src/framework/avx2_detect.hpp b/src/framework/avx2_detect.hpp index ef4e7b7cb2..49f5d73955 100644 --- a/src/framework/avx2_detect.hpp +++ b/src/framework/avx2_detect.hpp @@ -18,7 +18,14 @@ #include #include #include + #include "misc/common_macros.hpp" +#if defined(_MSC_VER) + #include +#elif defined(GNUC_AVX2) + #include +#endif + namespace { inline void ccpuid(int cpu_info[4], int function_id){ From 0ec5a57ddbcbecf7804b402b798c31e3a3524b87 Mon Sep 17 00:00:00 2001 From: hhorii Date: Thu, 5 Nov 2020 09:08:33 +0900 Subject: [PATCH 033/126] Renew benchmark (#940) --- test/asv.linux.conf.json | 14 +- ...cos.conf.json => asv.linux.cuda.conf.json} | 22 +- test/benchmark/__init__.py | 37 +-- test/benchmark/basic.py | 44 +++ test/benchmark/basic_05q.py | 126 ++++++++ test/benchmark/basic_15q.py | 126 ++++++++ test/benchmark/basic_25q.py | 126 ++++++++ test/benchmark/circuit_library_circuits.py | 107 +++++++ test/benchmark/fusion_benchmarks.py | 111 ------- test/benchmark/noise.py | 47 +++ test/benchmark/noise_12q.py | 85 ++++++ test/benchmark/noise_16q.py | 85 ++++++ test/benchmark/noise_20q.py | 85 ++++++ test/benchmark/output.py | 41 +++ test/benchmark/output_05q.py | 80 ++++++ test/benchmark/output_15q.py | 80 ++++++ test/benchmark/output_25q.py | 80 ++++++ .../quantum_fourier_transform_benchmarks.py | 103 ------- test/benchmark/quantum_volume_benchmarks.py | 83 ------ test/benchmark/randomized_benchmarking.py | 100 ------- test/benchmark/simple_benchmarks.py | 107 ------- test/benchmark/simulator_benchmark.py | 270 ++++++++++++++++++ test/benchmark/tools.py | 216 -------------- test/benchmark/vqe_application.py | 73 +++++ 24 files changed, 1482 insertions(+), 766 deletions(-) rename test/{asv.macos.conf.json => asv.linux.cuda.conf.json} (91%) create mode 100644 test/benchmark/basic.py create mode 100644 test/benchmark/basic_05q.py create mode 100644 test/benchmark/basic_15q.py create mode 100644 test/benchmark/basic_25q.py create mode 100644 test/benchmark/circuit_library_circuits.py delete mode 100644 test/benchmark/fusion_benchmarks.py create mode 100644 test/benchmark/noise.py create mode 100644 test/benchmark/noise_12q.py create mode 100644 test/benchmark/noise_16q.py create mode 100644 test/benchmark/noise_20q.py create mode 100644 test/benchmark/output.py create mode 100644 test/benchmark/output_05q.py create mode 100644 test/benchmark/output_15q.py create mode 100644 test/benchmark/output_25q.py delete mode 100644 test/benchmark/quantum_fourier_transform_benchmarks.py delete mode 100644 test/benchmark/quantum_volume_benchmarks.py delete mode 100644 test/benchmark/randomized_benchmarking.py delete mode 100644 test/benchmark/simple_benchmarks.py create mode 100644 test/benchmark/simulator_benchmark.py delete mode 100644 test/benchmark/tools.py create mode 100644 test/benchmark/vqe_application.py diff --git a/test/asv.linux.conf.json b/test/asv.linux.conf.json index ae937e0944..597cbe453f 100644 --- a/test/asv.linux.conf.json +++ b/test/asv.linux.conf.json @@ -33,17 +33,21 @@ "install_command": [ "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}", - "python -mpip install qiskit-ignis==0.2.0" + "pip install git+https://github.com/Qiskit/qiskit-terra", + "pip install git+https://github.com/Qiskit/qiskit-aqua", + "python -mpip install {wheel_file}" ], "uninstall_command": [ "return-code=any python -mpip uninstall -y qiskit-terra", - "return-code=any python -mpip uninstall -y {project}", - "return-code=any python -mpip uninstall -y qiskit-ignis" + "return-code=any python -mpip uninstall -y qiskit-aqua", + "return-code=any python -mpip uninstall -y {project}" ], "build_command": [ "python -mpip install -U scikit-build cython", - "python -mpip install qiskit-terra", + "pip install git+https://github.com/Qiskit/qiskit-terra", + "pip install git+https://github.com/Qiskit/qiskit-aqua", + "pip install pyscf", + "pip install matplotlib", "python setup.py bdist_wheel --dist-dir={build_cache_dir} -- -DCMAKE_CXX_COMPILER=g++ -- -j" ], diff --git a/test/asv.macos.conf.json b/test/asv.linux.cuda.conf.json similarity index 91% rename from test/asv.macos.conf.json rename to test/asv.linux.cuda.conf.json index 365098511f..5fde993fe7 100644 --- a/test/asv.macos.conf.json +++ b/test/asv.linux.cuda.conf.json @@ -1,5 +1,5 @@ // To use this configuration for running the benchmarks, we have to run asv like this: -// $ asv --connfig asv.macos.conf.json run +// $ asv --connfig asv.linux.conf.json { // The version of the config file format. Do not change, unless // you know what you are doing. @@ -31,20 +31,24 @@ // ], "install_command": [ - "python -c \"import shutil; shutil.rmtree('{build_dir}/qiskit')\"", - "python -c \"import shutil; shutil.rmtree('{build_dir}/qiskit_aer.egg-info')\"", - "python -mpip install {wheel_file}", - "python -mpip install qiskit-ignis==0.2.0" + "python -c \"import shutil; shutil.rmtree('{build_dir}/qiskit', True)\"", + "python -c \"import shutil; shutil.rmtree('{build_dir}/qiskit_aer.egg-info', True)\"", + "pip install git+https://github.com/Qiskit/qiskit-terra", + "pip install git+https://github.com/Qiskit/qiskit-aqua", + "python -mpip install {wheel_file}" ], "uninstall_command": [ "return-code=any python -mpip uninstall -y qiskit-terra", - "return-code=any python -mpip uninstall -y {project}", - "return-code=any python -mpip uninstall -y qiskit-ignis" + "return-code=any python -mpip uninstall -y qiskit-aqua", + "return-code=any python -mpip uninstall -y {project}" ], "build_command": [ "python -mpip install -U scikit-build cython", - "python -mpip install qiskit-terra", - "VERBOSE=1 python setup.py bdist_wheel --dist-dir={build_cache_dir} -- -- -j" + "pip install git+https://github.com/Qiskit/qiskit-terra", + "pip install git+https://github.com/Qiskit/qiskit-aqua", + "pip install pyscf", + "pip install matplotlib", + "python setup.py bdist_wheel --dist-dir={build_cache_dir} -- -DCMAKE_CXX_COMPILER=g++ -DAER_THRUST_BACKEND=CUDA -- -j" ], // List of branches to benchmark. If not provided, defaults to "master" diff --git a/test/benchmark/__init__.py b/test/benchmark/__init__.py index ec84b7a822..d5929de93b 100644 --- a/test/benchmark/__init__.py +++ b/test/benchmark/__init__.py @@ -1,32 +1,5 @@ -# 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. - -""" Some __repr__ hooks for beauty-printing reports """ - -from qiskit.qobj import Qobj -from qiskit.providers.aer.noise import NoiseModel - - -def qobj_repr_hook(self): - """ This is needed for ASV to beauty-printing reports """ - return "Num. qubits: {0}".format(self.config.n_qubits) - - -Qobj.__repr__ = qobj_repr_hook - - -def noise_model_repr_hook(self): - """ This is needed for ASV to beauty-printing reports """ - return self.__class__.__name__.replace("_", " ").capitalize() - - -NoiseModel.__repr__ = noise_model_repr_hook +from .simulator_benchmark import SimulatorBenchmarkSuite +from .basic import BasicSimulatorBenchmarkSuite +from .noise import NoiseSimulatorBenchmarkSuite +from .output import OutputSimulatorBenchmarkSuite +from .circuit_library_circuits import CircuitLibraryCircuits \ No newline at end of file diff --git a/test/benchmark/basic.py b/test/benchmark/basic.py new file mode 100644 index 0000000000..80194dccf8 --- /dev/null +++ b/test/benchmark/basic.py @@ -0,0 +1,44 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2018, 2019, 2020. +# +# 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. +""" +Base Class of Basic Circuit Benchmarking +""" +from qiskit.circuit.library import IntegerComparator, WeightedAdder, QuadraticForm + +from benchmark.simulator_benchmark import SimulatorBenchmarkSuite + +class BasicSimulatorBenchmarkSuite(SimulatorBenchmarkSuite): + + def __init__(self, + name = 'basic', + apps = [], + qubits = [], + runtime_names = [], + measures = [], + measure_counts = [], + noise_model_names = []): + super().__init__(name, + apps, + qubits=qubits, + runtime_names=runtime_names, + measures=measures, + measure_counts=measure_counts, + noise_model_names=noise_model_names) + + def track_statevector(self, app, measure, measure_count, noise_name, qubit): + return self._run(self.RUNTIME_STATEVECTOR_CPU, app, measure, measure_count, noise_name, qubit) + + def track_statevector_gpu(self, app, measure, measure_count, noise_name, qubit): + return self._run(self.RUNTIME_STATEVECTOR_GPU, app, measure, measure_count, noise_name, qubit) + + def track_matrix_product_state(self, app, measure, measure_count, noise_name, qubit): + return self._run(self.RUNTIME_MPS_CPU, app, measure, measure_count, noise_name, qubit) diff --git a/test/benchmark/basic_05q.py b/test/benchmark/basic_05q.py new file mode 100644 index 0000000000..ba3ccfb854 --- /dev/null +++ b/test/benchmark/basic_05q.py @@ -0,0 +1,126 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2018, 2019, 2020. +# +# 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. +""" +Basic Circuit Benchmarking with 5 qubits +""" +from qiskit.circuit.library import IntegerComparator, WeightedAdder, QuadraticForm + +from benchmark.simulator_benchmark import SimulatorBenchmarkSuite +from benchmark.basic import BasicSimulatorBenchmarkSuite + +DEFAULT_QUBITS = [ 5 ] + +DEFAULT_RUNTIME = [ + SimulatorBenchmarkSuite.RUNTIME_STATEVECTOR_CPU, + SimulatorBenchmarkSuite.RUNTIME_MPS_CPU, + SimulatorBenchmarkSuite.RUNTIME_STATEVECTOR_GPU + ] + +DEFAULT_MEASUREMENT_METHODS = [ + SimulatorBenchmarkSuite.MEASUREMENT_SAMPLING + ] + +DEFAULT_MEASUREMENT_COUNTS = SimulatorBenchmarkSuite.DEFAULT_MEASUREMENT_COUNTS + +DEFAULT_NOISE_MODELS = [ + SimulatorBenchmarkSuite.NOISE_IDEAL +] + +class ArithmeticCircuits(BasicSimulatorBenchmarkSuite): + + def __init__(self, + apps = { + 'integer_comparator': 10, + 'weighted_adder': 1, + 'quadratic_form': 10 + }, + qubits = DEFAULT_QUBITS, + runtime_names = DEFAULT_RUNTIME, + measures = DEFAULT_MEASUREMENT_METHODS, + measure_counts = DEFAULT_MEASUREMENT_COUNTS, + noise_model_names = DEFAULT_NOISE_MODELS): + super().__init__('arithmetic_circuits', + apps, + qubits=qubits, + runtime_names=runtime_names, + measures=measures, + measure_counts=measure_counts, + noise_model_names=noise_model_names) + +class BasicChangeCircuits(BasicSimulatorBenchmarkSuite): + + def __init__(self, + apps = {'qft':1 }, + qubits = DEFAULT_QUBITS, + runtime_names = DEFAULT_RUNTIME, + measures = DEFAULT_MEASUREMENT_METHODS, + measure_counts = DEFAULT_MEASUREMENT_COUNTS, + noise_model_names = DEFAULT_NOISE_MODELS): + + super().__init__('basic_change_circuits', + apps, + qubits=qubits, + runtime_names=runtime_names, + measures=measures, + measure_counts=measure_counts, + noise_model_names=noise_model_names) + +class NLocalCircuits(BasicSimulatorBenchmarkSuite): + + def __init__(self, + apps = { + 'real_amplitudes': 10, + 'real_amplitudes_linear': 10, + 'efficient_su2': 10, + 'efficient_su2_linear': 10, + #'excitation_preserving': 10, + #'excitation_preserving_linear': 10 + }, + qubits = DEFAULT_QUBITS, + runtime_names = DEFAULT_RUNTIME, + measures = DEFAULT_MEASUREMENT_METHODS, + measure_counts = DEFAULT_MEASUREMENT_COUNTS, + noise_model_names = DEFAULT_NOISE_MODELS): + super().__init__('n_local_circuits', + apps, + qubits=qubits, + runtime_names=runtime_names, + measures=measures, + measure_counts=measure_counts, + noise_model_names=noise_model_names) + +class ParticularQuantumCircuits(BasicSimulatorBenchmarkSuite): + + def __init__(self, + apps = { + 'fourier_checking': 10, + 'graph_state': 10, + 'hidden_linear_function': 10, + 'iqp': 10, + 'quantum_volume': 1, + 'phase_estimation': 1 }, + qubits = DEFAULT_QUBITS, + runtime_names = DEFAULT_RUNTIME, + measures = DEFAULT_MEASUREMENT_METHODS, + measure_counts = DEFAULT_MEASUREMENT_COUNTS, + noise_model_names=DEFAULT_NOISE_MODELS): + super().__init__('particular_quantum_circuits', + apps, qubits=qubits, + runtime_names=runtime_names, + measures=measures, + measure_counts=measure_counts, + noise_model_names=noise_model_names) + +if __name__ == "__main__": + benrhmarks = [ ArithmeticCircuits(), BasicChangeCircuits(), NLocalCircuits(), ParticularQuantumCircuits() ] + for benrhmark in benrhmarks: + benrhmark.run_manual() diff --git a/test/benchmark/basic_15q.py b/test/benchmark/basic_15q.py new file mode 100644 index 0000000000..3ff2b811b6 --- /dev/null +++ b/test/benchmark/basic_15q.py @@ -0,0 +1,126 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2018, 2019, 2020. +# +# 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. +""" +Basic Circuit Benchmarking with 15 qubits +""" +from qiskit.circuit.library import IntegerComparator, WeightedAdder, QuadraticForm + +from benchmark.simulator_benchmark import SimulatorBenchmarkSuite +from benchmark.basic import BasicSimulatorBenchmarkSuite + +DEFAULT_QUBITS = [ 15 ] + +DEFAULT_RUNTIME = [ + SimulatorBenchmarkSuite.RUNTIME_STATEVECTOR_CPU, + SimulatorBenchmarkSuite.RUNTIME_MPS_CPU, + SimulatorBenchmarkSuite.RUNTIME_STATEVECTOR_GPU + ] + +DEFAULT_MEASUREMENT_METHODS = [ + SimulatorBenchmarkSuite.MEASUREMENT_SAMPLING + ] + +DEFAULT_MEASUREMENT_COUNTS = SimulatorBenchmarkSuite.DEFAULT_MEASUREMENT_COUNTS + +DEFAULT_NOISE_MODELS = [ + SimulatorBenchmarkSuite.NOISE_IDEAL +] + +class ArithmeticCircuits(BasicSimulatorBenchmarkSuite): + + def __init__(self, + apps = { + 'integer_comparator': 10, + 'weighted_adder': 1, + 'quadratic_form': 10 + }, + qubits = DEFAULT_QUBITS, + runtime_names = DEFAULT_RUNTIME, + measures = DEFAULT_MEASUREMENT_METHODS, + measure_counts = DEFAULT_MEASUREMENT_COUNTS, + noise_model_names = DEFAULT_NOISE_MODELS): + super().__init__('arithmetic_circuits', + apps, + qubits=qubits, + runtime_names=runtime_names, + measures=measures, + measure_counts=measure_counts, + noise_model_names=noise_model_names) + +class BasicChangeCircuits(BasicSimulatorBenchmarkSuite): + + def __init__(self, + apps = {'qft':1 }, + qubits = DEFAULT_QUBITS, + runtime_names = DEFAULT_RUNTIME, + measures = DEFAULT_MEASUREMENT_METHODS, + measure_counts = DEFAULT_MEASUREMENT_COUNTS, + noise_model_names = DEFAULT_NOISE_MODELS): + + super().__init__('basic_change_circuits', + apps, + qubits=qubits, + runtime_names=runtime_names, + measures=measures, + measure_counts=measure_counts, + noise_model_names=noise_model_names) + +class NLocalCircuits(BasicSimulatorBenchmarkSuite): + + def __init__(self, + apps = { + 'real_amplitudes': 10, + 'real_amplitudes_linear': 10, + 'efficient_su2': 10, + 'efficient_su2_linear': 10, + #'excitation_preserving': 10, + #'excitation_preserving_linear': 10 + }, + qubits = DEFAULT_QUBITS, + runtime_names = DEFAULT_RUNTIME, + measures = DEFAULT_MEASUREMENT_METHODS, + measure_counts = DEFAULT_MEASUREMENT_COUNTS, + noise_model_names = DEFAULT_NOISE_MODELS): + super().__init__('n_local_circuits', + apps, + qubits=qubits, + runtime_names=runtime_names, + measures=measures, + measure_counts=measure_counts, + noise_model_names=noise_model_names) + +class ParticularQuantumCircuits(BasicSimulatorBenchmarkSuite): + + def __init__(self, + apps = { + 'fourier_checking': 10, + 'graph_state': 10, + 'hidden_linear_function': 10, + 'iqp': 10, + 'quantum_volume': 1, + 'phase_estimation': 1 }, + qubits = DEFAULT_QUBITS, + runtime_names = DEFAULT_RUNTIME, + measures = DEFAULT_MEASUREMENT_METHODS, + measure_counts = DEFAULT_MEASUREMENT_COUNTS, + noise_model_names=DEFAULT_NOISE_MODELS): + super().__init__('particular_quantum_circuits', + apps, qubits=qubits, + runtime_names=runtime_names, + measures=measures, + measure_counts=measure_counts, + noise_model_names=noise_model_names) + +if __name__ == "__main__": + benrhmarks = [ ArithmeticCircuits(), BasicChangeCircuits(), NLocalCircuits(), ParticularQuantumCircuits() ] + for benrhmark in benrhmarks: + benrhmark.run_manual() diff --git a/test/benchmark/basic_25q.py b/test/benchmark/basic_25q.py new file mode 100644 index 0000000000..de7443e43d --- /dev/null +++ b/test/benchmark/basic_25q.py @@ -0,0 +1,126 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2018, 2019, 2020. +# +# 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. +""" +Basic Circuit Benchmarking with 25 qubits +""" +from qiskit.circuit.library import IntegerComparator, WeightedAdder, QuadraticForm + +from benchmark.simulator_benchmark import SimulatorBenchmarkSuite +from benchmark.basic import BasicSimulatorBenchmarkSuite + +DEFAULT_QUBITS = [ 25 ] + +DEFAULT_RUNTIME = [ + SimulatorBenchmarkSuite.RUNTIME_STATEVECTOR_CPU, + #SimulatorBenchmarkSuite.RUNTIME_MPS_CPU, + SimulatorBenchmarkSuite.RUNTIME_STATEVECTOR_GPU + ] + +DEFAULT_MEASUREMENT_METHODS = [ + SimulatorBenchmarkSuite.MEASUREMENT_SAMPLING + ] + +DEFAULT_MEASUREMENT_COUNTS = SimulatorBenchmarkSuite.DEFAULT_MEASUREMENT_COUNTS + +DEFAULT_NOISE_MODELS = [ + SimulatorBenchmarkSuite.NOISE_IDEAL +] + +class ArithmeticCircuits(BasicSimulatorBenchmarkSuite): + + def __init__(self, + apps = { + 'integer_comparator': 10, + 'weighted_adder': 1, + 'quadratic_form': 10 + }, + qubits = DEFAULT_QUBITS, + runtime_names = DEFAULT_RUNTIME, + measures = DEFAULT_MEASUREMENT_METHODS, + measure_counts = DEFAULT_MEASUREMENT_COUNTS, + noise_model_names = DEFAULT_NOISE_MODELS): + super().__init__('arithmetic_circuits', + apps, + qubits=qubits, + runtime_names=runtime_names, + measures=measures, + measure_counts=measure_counts, + noise_model_names=noise_model_names) + +class BasicChangeCircuits(BasicSimulatorBenchmarkSuite): + + def __init__(self, + apps = {'qft':1 }, + qubits = DEFAULT_QUBITS, + runtime_names = DEFAULT_RUNTIME, + measures = DEFAULT_MEASUREMENT_METHODS, + measure_counts = DEFAULT_MEASUREMENT_COUNTS, + noise_model_names = DEFAULT_NOISE_MODELS): + + super().__init__('basic_change_circuits', + apps, + qubits=qubits, + runtime_names=runtime_names, + measures=measures, + measure_counts=measure_counts, + noise_model_names=noise_model_names) + +class NLocalCircuits(BasicSimulatorBenchmarkSuite): + + def __init__(self, + apps = { + 'real_amplitudes': 10, + 'real_amplitudes_linear': 10, + 'efficient_su2': 10, + 'efficient_su2_linear': 10, + #'excitation_preserving': 10, + #'excitation_preserving_linear': 10 + }, + qubits = DEFAULT_QUBITS, + runtime_names = DEFAULT_RUNTIME, + measures = DEFAULT_MEASUREMENT_METHODS, + measure_counts = DEFAULT_MEASUREMENT_COUNTS, + noise_model_names = DEFAULT_NOISE_MODELS): + super().__init__('n_local_circuits', + apps, + qubits=qubits, + runtime_names=runtime_names, + measures=measures, + measure_counts=measure_counts, + noise_model_names=noise_model_names) + +class ParticularQuantumCircuits(BasicSimulatorBenchmarkSuite): + + def __init__(self, + apps = { + 'fourier_checking': 10, + 'graph_state': 10, + 'hidden_linear_function': 10, + 'iqp': 10, + 'quantum_volume': 1, + 'phase_estimation': 1 }, + qubits = DEFAULT_QUBITS, + runtime_names = DEFAULT_RUNTIME, + measures = DEFAULT_MEASUREMENT_METHODS, + measure_counts = DEFAULT_MEASUREMENT_COUNTS, + noise_model_names=DEFAULT_NOISE_MODELS): + super().__init__('particular_quantum_circuits', + apps, qubits=qubits, + runtime_names=runtime_names, + measures=measures, + measure_counts=measure_counts, + noise_model_names=noise_model_names) + +if __name__ == "__main__": + benrhmarks = [ ArithmeticCircuits(), BasicChangeCircuits(), NLocalCircuits(), ParticularQuantumCircuits() ] + for benrhmark in benrhmarks: + benrhmark.run_manual() diff --git a/test/benchmark/circuit_library_circuits.py b/test/benchmark/circuit_library_circuits.py new file mode 100644 index 0000000000..969a9aa5ac --- /dev/null +++ b/test/benchmark/circuit_library_circuits.py @@ -0,0 +1,107 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2018, 2019, 2020. +# +# 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. +""" +Circuit Generator +""" +import numpy as np + +from qiskit.circuit.library import * + +class CircuitLibraryCircuits(): + + def _repeat(self, circ, repeats): + if repeats is not None and repeats > 1: + circ = circ.repeat(repeats).decompose() + return circ + + def integer_comparator(self, qubit, repeats): + if qubit < 2: + raise ValueError('qubit is too small: {0}'.format(qubit)) + half = int(qubit / 2) + return self._repeat(IntegerComparator(num_state_qubits=half, value=1), repeats) + + def weighted_adder(self, qubit, repeats): + if qubit > 20: + raise ValueError('qubit is too big: {0}'.format(qubit)) + return self._repeat(WeightedAdder(num_state_qubits=qubit).decompose(), repeats) + + def quadratic_form(self, qubit, repeats): + if qubit < 4: + raise ValueError('qubit is too small: {0}'.format(qubit)) + return self._repeat(QuadraticForm(num_result_qubits=(qubit - 3), linear=[1, 1, 1], little_endian=True).decompose(), repeats) + + def qft(self, qubit, repeats): + return self._repeat(QFT(qubit), repeats) + + def real_amplitudes(self, qubit, repeats): + return self.transpile(RealAmplitudes(qubit, reps=repeats)) + + def real_amplitudes_linear(self, qubit, repeats): + return self.transpile(RealAmplitudes(qubit, reps=repeats, entanglement='linear')) + + def efficient_su2(self, qubit, repeats): + return self.transpile(EfficientSU2(qubit).decompose()) + + def efficient_su2_linear(self, qubit, repeats): + return self.transpile(EfficientSU2(qubit, reps=repeats, entanglement='linear')) + + def excitation_preserving(self, qubit, repeats): + return self.transpile(ExcitationPreserving(qubit, reps=repeats).decompose()) + + def excitation_preserving_linear(self, qubit, repeats): + return self.transpile(ExcitationPreserving(qubit, reps=repeats, entanglement='linear')) + + def fourier_checking(self, qubit, repeats): + if qubit > 20: + raise ValueError('qubit is too big: {0}'.format(qubit)) + f = [-1, 1] * (2 ** (qubit - 1)) + g = [1, -1] * (2 ** (qubit - 1)) + return self._repeat(FourierChecking(f, g), repeats) + + def graph_state(self, qubit, repeats): + a = np.reshape([0] * (qubit ** 2), [qubit] * 2) + for _ in range(qubit): + while True: + i = np.random.randint(0, qubit) + j = np.random.randint(0, qubit) + if a[i][j] == 0: + a[i][j] = 1 + a[j][i] = 1 + break + return self._repeat(GraphState(a), repeats) + + def hidden_linear_function(self, qubit, repeats): + a = np.reshape([0] * (qubit ** 2), [qubit] * 2) + for _ in range(qubit): + while True: + i = np.random.randint(0, qubit) + j = np.random.randint(0, qubit) + if a[i][j] == 0: + a[i][j] = 1 + a[j][i] = 1 + break + return self._repeat(HiddenLinearFunction(a), repeats) + + def iqp(self, qubit, repeats): + interactions = np.random.randint(-1024, 1024, (qubit, qubit)) + for i in range(qubit): + for j in range(i + 1, qubit): + interactions[j][i] = interactions[i][j] + return self._repeat(IQP(interactions).decompose(), repeats) + + def quantum_volume(self, qubit, repeats): + return self._repeat(QuantumVolume(qubit).decompose(), repeats) + + def phase_estimation(self, qubit, repeats): + if qubit < 5: + raise ValueError('qubit is too small: {0}'.format(qubit)) + return self._repeat(PhaseEstimation(2, QuantumVolume(qubit - 2).decompose()).decompose(), repeats) diff --git a/test/benchmark/fusion_benchmarks.py b/test/benchmark/fusion_benchmarks.py deleted file mode 100644 index 490df2b89f..0000000000 --- a/test/benchmark/fusion_benchmarks.py +++ /dev/null @@ -1,111 +0,0 @@ -import numpy as np -import math -from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit, QiskitError -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)], - 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, fusion_enable=fusion_enable).result() - if result.status != 'COMPLETED': - raise QiskitError("Simulation failed. Status: " + result.status) diff --git a/test/benchmark/noise.py b/test/benchmark/noise.py new file mode 100644 index 0000000000..9bed10f321 --- /dev/null +++ b/test/benchmark/noise.py @@ -0,0 +1,47 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2018, 2019, 2020. +# +# 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. +""" +Base Class of Noise Benchmarking +""" +from qiskit.circuit.library import IntegerComparator, WeightedAdder, QuadraticForm + +from benchmark.simulator_benchmark import SimulatorBenchmarkSuite + +class NoiseSimulatorBenchmarkSuite(SimulatorBenchmarkSuite): + + def __init__(self, + name = 'noise', + apps = [], + qubits = [], + runtime_names = [], + measures = [], + measure_counts = [], + noise_model_names = []): + super().__init__(name, + apps, + qubits=qubits, + runtime_names=runtime_names, + measures=measures, + measure_counts=measure_counts, + noise_model_names=noise_model_names) + + def track_statevector(self, app, measure, measure_count, noise_name, qubit): + return self._run(self.RUNTIME_STATEVECTOR_CPU, app, measure, measure_count, noise_name, qubit) + + def track_statevector_gpu(self, app, measure, measure_count, noise_name, qubit): + return self._run(self.RUNTIME_STATEVECTOR_GPU, app, measure, measure_count, noise_name, qubit) + + def track_density_matrix(self, app, measure, measure_count, noise_name, qubit): + return self._run(self.RUNTIME_DENSITY_MATRIX_CPU, app, measure, measure_count, noise_name, qubit) + + def track_density_matrix_gpu(self, app, measure, measure_count, noise_name, qubit): + return self._run(self.RUNTIME_DENSITY_MATRIX_GPU, app, measure, measure_count, noise_name, qubit) \ No newline at end of file diff --git a/test/benchmark/noise_12q.py b/test/benchmark/noise_12q.py new file mode 100644 index 0000000000..752d364e5f --- /dev/null +++ b/test/benchmark/noise_12q.py @@ -0,0 +1,85 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2018, 2019, 2020. +# +# 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. +""" +Noise Benchmarking with 12 qubits +""" +from benchmark.simulator_benchmark import SimulatorBenchmarkSuite +from benchmark.noise import NoiseSimulatorBenchmarkSuite + +DEFAULT_APPS = { +# 'fourier_checking', +# 'graph_state', +# 'hidden_linear_function', +# 'iqp', + 'quantum_volume': 1 +# 'phase_estimation' + } + +DEFAULT_QUBITS = [12] + +DEFAULT_RUNTIME = [ + SimulatorBenchmarkSuite.RUNTIME_STATEVECTOR_CPU, + SimulatorBenchmarkSuite.RUNTIME_STATEVECTOR_GPU, + SimulatorBenchmarkSuite.RUNTIME_DENSITY_MATRIX_CPU, + SimulatorBenchmarkSuite.RUNTIME_DENSITY_MATRIX_GPU + ] + +DEFAULT_MEASUREMENT_METHODS = [ + SimulatorBenchmarkSuite.MEASUREMENT_SAMPLING + ] + +DEFAULT_MEASUREMENT_COUNTS = [ 1000 ] + +DEFAULT_NOISE_MODELS = [ + SimulatorBenchmarkSuite.NOISE_DAMPING, + SimulatorBenchmarkSuite.NOISE_DEPOLARIZING + ] + +class DampingError(NoiseSimulatorBenchmarkSuite): + + def __init__(self, + apps = DEFAULT_APPS, + qubits = DEFAULT_QUBITS, + runtime_names = DEFAULT_RUNTIME, + measures = DEFAULT_MEASUREMENT_METHODS, + measure_counts = DEFAULT_MEASUREMENT_COUNTS, + noise_model_names = [SimulatorBenchmarkSuite.NOISE_DAMPING] ): + super().__init__('damping_error', + apps, + qubits=qubits, + runtime_names=runtime_names, + measures=measures, + measure_counts=measure_counts, + noise_model_names=noise_model_names) + self.__name__ = 'damping_error' + +class DepolarizingError(NoiseSimulatorBenchmarkSuite): + + def __init__(self, + apps = DEFAULT_APPS, + qubits = DEFAULT_QUBITS, + runtime_names = DEFAULT_RUNTIME, + measures = DEFAULT_MEASUREMENT_METHODS, + measure_counts = DEFAULT_MEASUREMENT_COUNTS, + noise_model_names = [SimulatorBenchmarkSuite.NOISE_DEPOLARIZING] ): + super().__init__('depolarizing_error', + apps, + qubits=qubits, + runtime_names=runtime_names, + measures=measures, + measure_counts=measure_counts, + noise_model_names=noise_model_names) + self.__name__ = 'depolarizing_error' + +if __name__ == "__main__": + DampingError().run_manual() + DepolarizingError().run_manual() \ No newline at end of file diff --git a/test/benchmark/noise_16q.py b/test/benchmark/noise_16q.py new file mode 100644 index 0000000000..90317340c2 --- /dev/null +++ b/test/benchmark/noise_16q.py @@ -0,0 +1,85 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2018, 2019, 2020. +# +# 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. +""" +Noise Benchmarking with 16 qubits +""" +from benchmark.simulator_benchmark import SimulatorBenchmarkSuite +from benchmark.noise import NoiseSimulatorBenchmarkSuite + +DEFAULT_APPS = { +# 'fourier_checking', +# 'graph_state', +# 'hidden_linear_function', +# 'iqp', + 'quantum_volume': 1 +# 'phase_estimation' + } + +DEFAULT_QUBITS = [16] + +DEFAULT_RUNTIME = [ + SimulatorBenchmarkSuite.RUNTIME_STATEVECTOR_CPU, + SimulatorBenchmarkSuite.RUNTIME_STATEVECTOR_GPU, + #SimulatorBenchmarkSuite.RUNTIME_DENSITY_MATRIX_CPU, + #SimulatorBenchmarkSuite.RUNTIME_DENSITY_MATRIX_GPU + ] + +DEFAULT_MEASUREMENT_METHODS = [ + SimulatorBenchmarkSuite.MEASUREMENT_SAMPLING + ] + +DEFAULT_MEASUREMENT_COUNTS = [ 1000 ] + +DEFAULT_NOISE_MODELS = [ + SimulatorBenchmarkSuite.NOISE_DAMPING, + SimulatorBenchmarkSuite.NOISE_DEPOLARIZING + ] + +class DampingError(NoiseSimulatorBenchmarkSuite): + + def __init__(self, + apps = DEFAULT_APPS, + qubits = DEFAULT_QUBITS, + runtime_names = DEFAULT_RUNTIME, + measures = DEFAULT_MEASUREMENT_METHODS, + measure_counts = DEFAULT_MEASUREMENT_COUNTS, + noise_model_names = [SimulatorBenchmarkSuite.NOISE_DAMPING] ): + super().__init__('damping_error', + apps, + qubits=qubits, + runtime_names=runtime_names, + measures=measures, + measure_counts=measure_counts, + noise_model_names=noise_model_names) + self.__name__ = 'damping_error' + +class DepolarizingError(NoiseSimulatorBenchmarkSuite): + + def __init__(self, + apps = DEFAULT_APPS, + qubits = DEFAULT_QUBITS, + runtime_names = DEFAULT_RUNTIME, + measures = DEFAULT_MEASUREMENT_METHODS, + measure_counts = DEFAULT_MEASUREMENT_COUNTS, + noise_model_names = [SimulatorBenchmarkSuite.NOISE_DEPOLARIZING] ): + super().__init__('depolarizing_error', + apps, + qubits=qubits, + runtime_names=runtime_names, + measures=measures, + measure_counts=measure_counts, + noise_model_names=noise_model_names) + self.__name__ = 'depolarizing_error' + +if __name__ == "__main__": + DampingError().run_manual() + DepolarizingError().run_manual() \ No newline at end of file diff --git a/test/benchmark/noise_20q.py b/test/benchmark/noise_20q.py new file mode 100644 index 0000000000..153bae564f --- /dev/null +++ b/test/benchmark/noise_20q.py @@ -0,0 +1,85 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2018, 2019, 2020. +# +# 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. +""" +Noise Benchmarking with 20 qubits +""" +from benchmark.simulator_benchmark import SimulatorBenchmarkSuite +from benchmark.noise import NoiseSimulatorBenchmarkSuite + +DEFAULT_APPS = { +# 'fourier_checking', +# 'graph_state', +# 'hidden_linear_function', +# 'iqp', + 'quantum_volume': 1 +# 'phase_estimation' + } + +DEFAULT_QUBITS = [20] + +DEFAULT_RUNTIME = [ + SimulatorBenchmarkSuite.RUNTIME_STATEVECTOR_CPU, + SimulatorBenchmarkSuite.RUNTIME_STATEVECTOR_GPU, + #SimulatorBenchmarkSuite.RUNTIME_DENSITY_MATRIX_CPU, + #SimulatorBenchmarkSuite.RUNTIME_DENSITY_MATRIX_GPU + ] + +DEFAULT_MEASUREMENT_METHODS = [ + SimulatorBenchmarkSuite.MEASUREMENT_SAMPLING + ] + +DEFAULT_MEASUREMENT_COUNTS = [ 1000 ] + +DEFAULT_NOISE_MODELS = [ + SimulatorBenchmarkSuite.NOISE_DAMPING, + SimulatorBenchmarkSuite.NOISE_DEPOLARIZING + ] + +class DampingError(NoiseSimulatorBenchmarkSuite): + + def __init__(self, + apps = DEFAULT_APPS, + qubits = DEFAULT_QUBITS, + runtime_names = DEFAULT_RUNTIME, + measures = DEFAULT_MEASUREMENT_METHODS, + measure_counts = DEFAULT_MEASUREMENT_COUNTS, + noise_model_names = [SimulatorBenchmarkSuite.NOISE_DAMPING] ): + super().__init__('damping_error', + apps, + qubits=qubits, + runtime_names=runtime_names, + measures=measures, + measure_counts=measure_counts, + noise_model_names=noise_model_names) + self.__name__ = 'damping_error' + +class DepolarizingError(NoiseSimulatorBenchmarkSuite): + + def __init__(self, + apps = DEFAULT_APPS, + qubits = DEFAULT_QUBITS, + runtime_names = DEFAULT_RUNTIME, + measures = DEFAULT_MEASUREMENT_METHODS, + measure_counts = DEFAULT_MEASUREMENT_COUNTS, + noise_model_names = [SimulatorBenchmarkSuite.NOISE_DEPOLARIZING] ): + super().__init__('depolarizing_error', + apps, + qubits=qubits, + runtime_names=runtime_names, + measures=measures, + measure_counts=measure_counts, + noise_model_names=noise_model_names) + self.__name__ = 'depolarizing_error' + +if __name__ == "__main__": + DampingError().run_manual() + DepolarizingError().run_manual() \ No newline at end of file diff --git a/test/benchmark/output.py b/test/benchmark/output.py new file mode 100644 index 0000000000..36018fd946 --- /dev/null +++ b/test/benchmark/output.py @@ -0,0 +1,41 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2018, 2019, 2020. +# +# 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. +""" +Base Class of Output Benchmarking +""" +from qiskit.circuit.library import IntegerComparator, WeightedAdder, QuadraticForm + +from benchmark.simulator_benchmark import SimulatorBenchmarkSuite + +class OutputSimulatorBenchmarkSuite(SimulatorBenchmarkSuite): + + def __init__(self, + name = 'output', + apps = [], + qubits = [], + runtime_names = [], + measures = [], + measure_counts = [], + noise_model_names = []): + super().__init__(name, + apps, + qubits=qubits, + runtime_names=runtime_names, + measures=measures, + measure_counts=measure_counts, + noise_model_names=noise_model_names) + + def track_statevector(self, app, measure, measure_count, noise_name, qubit): + return self._run(self.RUNTIME_STATEVECTOR_CPU, app, measure, measure_count, noise_name, qubit) + + def track_statevector_gpu(self, app, measure, measure_count, noise_name, qubit): + return self._run(self.RUNTIME_STATEVECTOR_GPU, app, measure, measure_count, noise_name, qubit) \ No newline at end of file diff --git a/test/benchmark/output_05q.py b/test/benchmark/output_05q.py new file mode 100644 index 0000000000..7de05c33d2 --- /dev/null +++ b/test/benchmark/output_05q.py @@ -0,0 +1,80 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2018, 2019, 2020. +# +# 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. +""" +Output Benchmarking with 5 qubits +""" +from benchmark.simulator_benchmark import SimulatorBenchmarkSuite +from benchmark.output import OutputSimulatorBenchmarkSuite + +DEFAULT_APPS = { +# 'fourier_checking', +# 'graph_state', +# 'hidden_linear_function', +# 'iqp', + 'quantum_volume': 1, +# 'phase_estimation' + } + +DEFAULT_QUBITS = [ 5 ] + +DEFAULT_RUNTIME = [ + SimulatorBenchmarkSuite.RUNTIME_STATEVECTOR_CPU, + SimulatorBenchmarkSuite.RUNTIME_STATEVECTOR_GPU, + #SimulatorBenchmarkSuite.RUNTIME_MPS_CPU, + ] + +DEFAULT_MEASUREMENT_COUNTS = [ 1, 10, 100, 1000, 10000 ] + +DEFAULT_NOISE_MODELS = [ + SimulatorBenchmarkSuite.NOISE_IDEAL + ] + +class Sampling(OutputSimulatorBenchmarkSuite): + + def __init__(self, + apps = DEFAULT_APPS, + qubits = DEFAULT_QUBITS, + runtime_names = DEFAULT_RUNTIME, + measures = [SimulatorBenchmarkSuite.MEASUREMENT_SAMPLING], + measure_counts = DEFAULT_MEASUREMENT_COUNTS, + noise_model_names = DEFAULT_NOISE_MODELS): + super().__init__( 'sampling', + apps, + qubits=qubits, + runtime_names=runtime_names, + measures=measures, + measure_counts=measure_counts, + noise_model_names=noise_model_names) + self.__name__ = 'sampling' + +class ExpVal(OutputSimulatorBenchmarkSuite): + + def __init__(self, + apps = DEFAULT_APPS, + qubits = DEFAULT_QUBITS, + runtime_names = DEFAULT_RUNTIME, + measures = [SimulatorBenchmarkSuite.MEASUREMENT_EXPVAL], + measure_counts = DEFAULT_MEASUREMENT_COUNTS, + noise_model_names = DEFAULT_NOISE_MODELS): + super().__init__( 'expval', + apps, + qubits=qubits, + runtime_names=runtime_names, + measures=measures, + measure_counts=measure_counts, + noise_model_names=noise_model_names) + self.__name__ = 'expval' + + +if __name__ == "__main__": + Sampling().run_manual() + ExpVal().run_manual() \ No newline at end of file diff --git a/test/benchmark/output_15q.py b/test/benchmark/output_15q.py new file mode 100644 index 0000000000..f5e13907f6 --- /dev/null +++ b/test/benchmark/output_15q.py @@ -0,0 +1,80 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2018, 2019, 2020. +# +# 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. +""" +Output Benchmarking with 15 qubits +""" +from benchmark.simulator_benchmark import SimulatorBenchmarkSuite +from benchmark.output import OutputSimulatorBenchmarkSuite + +DEFAULT_APPS = { +# 'fourier_checking', +# 'graph_state', +# 'hidden_linear_function', +# 'iqp', + 'quantum_volume': 1, +# 'phase_estimation' + } + +DEFAULT_QUBITS = [ 15 ] + +DEFAULT_RUNTIME = [ + SimulatorBenchmarkSuite.RUNTIME_STATEVECTOR_CPU, + SimulatorBenchmarkSuite.RUNTIME_STATEVECTOR_GPU, + #SimulatorBenchmarkSuite.RUNTIME_MPS_CPU, + ] + +DEFAULT_MEASUREMENT_COUNTS = [ 1, 10, 100, 1000, 10000 ] + +DEFAULT_NOISE_MODELS = [ + SimulatorBenchmarkSuite.NOISE_IDEAL + ] + +class Sampling(OutputSimulatorBenchmarkSuite): + + def __init__(self, + apps = DEFAULT_APPS, + qubits = DEFAULT_QUBITS, + runtime_names = DEFAULT_RUNTIME, + measures = [SimulatorBenchmarkSuite.MEASUREMENT_SAMPLING], + measure_counts = DEFAULT_MEASUREMENT_COUNTS, + noise_model_names = DEFAULT_NOISE_MODELS): + super().__init__( 'sampling', + apps, + qubits=qubits, + runtime_names=runtime_names, + measures=measures, + measure_counts=measure_counts, + noise_model_names=noise_model_names) + self.__name__ = 'sampling' + +class ExpVal(OutputSimulatorBenchmarkSuite): + + def __init__(self, + apps = DEFAULT_APPS, + qubits = DEFAULT_QUBITS, + runtime_names = DEFAULT_RUNTIME, + measures = [SimulatorBenchmarkSuite.MEASUREMENT_EXPVAL], + measure_counts = DEFAULT_MEASUREMENT_COUNTS, + noise_model_names = DEFAULT_NOISE_MODELS): + super().__init__( 'expval', + apps, + qubits=qubits, + runtime_names=runtime_names, + measures=measures, + measure_counts=measure_counts, + noise_model_names=noise_model_names) + self.__name__ = 'expval' + + +if __name__ == "__main__": + Sampling().run_manual() + ExpVal().run_manual() \ No newline at end of file diff --git a/test/benchmark/output_25q.py b/test/benchmark/output_25q.py new file mode 100644 index 0000000000..27683b2dd2 --- /dev/null +++ b/test/benchmark/output_25q.py @@ -0,0 +1,80 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2018, 2019, 2020. +# +# 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. +""" +Output Benchmarking with 25 qubits +""" +from benchmark.simulator_benchmark import SimulatorBenchmarkSuite +from benchmark.output import OutputSimulatorBenchmarkSuite + +DEFAULT_APPS = { +# 'fourier_checking', +# 'graph_state', +# 'hidden_linear_function', +# 'iqp', + 'quantum_volume': 1, +# 'phase_estimation' + } + +DEFAULT_QUBITS = [ 25 ] + +DEFAULT_RUNTIME = [ + SimulatorBenchmarkSuite.RUNTIME_STATEVECTOR_CPU, + SimulatorBenchmarkSuite.RUNTIME_STATEVECTOR_GPU, + #SimulatorBenchmarkSuite.RUNTIME_MPS_CPU, + ] + +DEFAULT_MEASUREMENT_COUNTS = [ 1, 10, 100, 1000, 10000 ] + +DEFAULT_NOISE_MODELS = [ + SimulatorBenchmarkSuite.NOISE_IDEAL + ] + +class Sampling(OutputSimulatorBenchmarkSuite): + + def __init__(self, + apps = DEFAULT_APPS, + qubits = DEFAULT_QUBITS, + runtime_names = DEFAULT_RUNTIME, + measures = [SimulatorBenchmarkSuite.MEASUREMENT_SAMPLING], + measure_counts = DEFAULT_MEASUREMENT_COUNTS, + noise_model_names = DEFAULT_NOISE_MODELS): + super().__init__( 'sampling', + apps, + qubits=qubits, + runtime_names=runtime_names, + measures=measures, + measure_counts=measure_counts, + noise_model_names=noise_model_names) + self.__name__ = 'sampling' + +class ExpVal(OutputSimulatorBenchmarkSuite): + + def __init__(self, + apps = DEFAULT_APPS, + qubits = DEFAULT_QUBITS, + runtime_names = DEFAULT_RUNTIME, + measures = [SimulatorBenchmarkSuite.MEASUREMENT_EXPVAL], + measure_counts = DEFAULT_MEASUREMENT_COUNTS, + noise_model_names = DEFAULT_NOISE_MODELS): + super().__init__( 'expval', + apps, + qubits=qubits, + runtime_names=runtime_names, + measures=measures, + measure_counts=measure_counts, + noise_model_names=noise_model_names) + self.__name__ = 'expval' + + +if __name__ == "__main__": + Sampling().run_manual() + ExpVal().run_manual() \ No newline at end of file diff --git a/test/benchmark/quantum_fourier_transform_benchmarks.py b/test/benchmark/quantum_fourier_transform_benchmarks.py deleted file mode 100644 index 4aaa282fdd..0000000000 --- a/test/benchmark/quantum_fourier_transform_benchmarks.py +++ /dev/null @@ -1,103 +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. - -"""Quantum Fourier Transform benchmark suite""" -# Write the benchmarking functions here. -# See "Writing benchmarks" in the asv docs for more information. - -from qiskit import QiskitError -from qiskit.compiler import transpile, assemble -from qiskit.providers.aer import QasmSimulator -from .tools import quantum_fourier_transform_circuit, \ - mixed_unitary_noise_model, reset_noise_model, \ - kraus_noise_model, no_noise - - -class QuantumFourierTransformQasmSimulatorBenchSuite: - """ - Benchmarking times for Quantum Fourier Transform with various noise - configurations: - - ideal (no noise) - - mixed state - - reset - - kraus - - and different simulator methods - - For each noise model, we want to test various configurations of number of - qubits - - The methods defined in this class will be executed by ASV framework as many - times as the combination of all parameters exist in `self.params`, for - exmaple: self.params = ([1,2,3],[4,5,6]), will run all methdos 9 times: - time_method(1,4) - time_method(1,5) - time_method(1,6) - time_method(2,4) - time_method(2,5) - time_method(2,6) - time_method(3,4) - time_method(3,5) - time_method(3,6) - """ - - def __init__(self): - self.timeout = 60 * 20 - self.qft_circuits = [] - self.backend = QasmSimulator() - for num_qubits in (5, 10, 15, 20): - circ = quantum_fourier_transform_circuit(num_qubits) - circ = transpile(circ, basis_gates=['u1', 'u2', 'u3', 'cx'], - optimization_level=0, seed_transpiler=1) - qobj = assemble(circ, self.backend, shots=1) - self.qft_circuits.append(qobj) - - self.param_names = ["Quantum Fourier Transform", "Noise Model", - "Simulator Method"] - - # This will run every benchmark for one of the combinations we have: - # bench(qft_circuits, None) => bench(qft_circuits, mixed()) => - # bench(qft_circuits, reset) => bench(qft_circuits, kraus()) - self.params = ( - self.qft_circuits, [no_noise(), mixed_unitary_noise_model(), - reset_noise_model(), kraus_noise_model()], - ['statevector', 'density_matrix', 'stabilizer', - 'extended_stabilizer', 'matrix_product_state']) - - def setup(self, qobj, noise_model_wrapper, simulator_method): - """ Setup env before benchmarks start """ - - def time_quantum_fourier_transform(self, qobj, noise_model_wrapper, - simulator_method): - """ Benchmark QFT """ - backend_options = { - 'method': simulator_method, - 'noise_model': noise_model_wrapper(), - } - result = self.backend.run( - qobj, noise_model=noise_model_wrapper() - ).result() - if result.status != 'COMPLETED': - raise QiskitError("Simulation failed. Status: " + result.status) - - def peakmem_quantum_fourier_transform(self, qobj, noise_model_wrapper, - simulator_method): - """ Benchmark QFT """ - backend_options = { - 'method': simulator_method, - 'noise_model': noise_model_wrapper(), - } - result = self.backend.run( - qobj, noise_model=noise_model_wrapper() - ).result() - if result.status != 'COMPLETED': - raise QiskitError("Simulation failed. Status: " + result.status) diff --git a/test/benchmark/quantum_volume_benchmarks.py b/test/benchmark/quantum_volume_benchmarks.py deleted file mode 100644 index cb90e350f9..0000000000 --- a/test/benchmark/quantum_volume_benchmarks.py +++ /dev/null @@ -1,83 +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. - -"""Quantum Voluming benchmark suite""" -# Write the benchmarking functions here. -# See "Writing benchmarks" in the asv docs for more information. - -from qiskit import QiskitError -from qiskit.compiler import transpile, assemble -from qiskit.providers.aer import QasmSimulator -from .tools import quantum_volume_circuit, mixed_unitary_noise_model, \ - reset_noise_model, kraus_noise_model, no_noise - - -class QuantumVolumeTimeSuite: - """ - Benchmarking times for Quantum Volume with various noise configurations - - ideal (no noise) - - mixed state - - reset - - kraus - - For each noise model, we want to test various configurations of number of - qubits - - The methods defined in this class will be executed by ASV framework as many - times as the combination of all parameters exist in `self.params`, for - exmaple: self.params = ([1,2,3],[4,5,6]), will run all methdos 9 times: - time_method(1,4) - time_method(1,5) - time_method(1,6) - time_method(2,4) - time_method(2,5) - time_method(2,6) - time_method(3,4) - time_method(3,5) - time_method(3,6) - """ - - def __init__(self): - self.timeout = 60 * 20 - self.qv_circuits = [] - self.backend = QasmSimulator() - for num_qubits in (5, 10, 15): - for depth in (10, ): - # We want always the same seed, as we want always the same - # circuits for the same value pairs of qubits and depth - circ = quantum_volume_circuit(num_qubits, depth, seed=1) - circ = transpile(circ, basis_gates=['u1', 'u2', 'u3', 'cx'], - optimization_level=0, seed_transpiler=1) - qobj = assemble(circ, self.backend, shots=1) - self.qv_circuits.append(qobj) - self.param_names = ["Quantum Volume", "Noise Model"] - - # This will run every benchmark for one of the combinations we have: - # bench(qv_circuits, None) => bench(qv_circuits, mixed()) => - # bench(qv_circuits, reset) => bench(qv_circuits, kraus()) - self.params = (self.qv_circuits, [ - no_noise(), - mixed_unitary_noise_model(), - reset_noise_model(), - kraus_noise_model() - ]) - - def setup(self, qobj, noise_model_wrapper): - """ Setup enviornment before running the tests """ - - def time_quantum_volume(self, qobj, noise_model_wrapper): - """ Benchmark for quantum volume """ - result = self.backend.run( - qobj, noise_model=noise_model_wrapper() - ).result() - if result.status != 'COMPLETED': - raise QiskitError("Simulation failed. Status: " + result.status) diff --git a/test/benchmark/randomized_benchmarking.py b/test/benchmark/randomized_benchmarking.py deleted file mode 100644 index 5069c2760b..0000000000 --- a/test/benchmark/randomized_benchmarking.py +++ /dev/null @@ -1,100 +0,0 @@ -# -*- coding: utf-8 -*- - -# This code is part of Qiskit. -# -# (C) Copyright IBM 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. - -# pylint: disable=no-member,invalid-name,missing-docstring,no-name-in-module -# pylint: disable=attribute-defined-outside-init,unsubscriptable-object - -import numpy as np - -from qiskit import assemble -from qiskit import transpile -from qiskit import Aer -import qiskit.ignis.verification.randomized_benchmarking as rb - -from .tools import kraus_noise_model, no_noise, mixed_unitary_noise_model, \ - reset_noise_model - - -def build_rb_circuit(nseeds=1, length_vector=None, - rb_pattern=None, length_multiplier=1, - seed_offset=0, align_cliffs=False, seed=None): - """ - Randomized Benchmarking sequences. - """ - if not seed: - np.random.seed(10) - else: - np.random.seed(seed) - rb_opts = {} - rb_opts['nseeds'] = nseeds - rb_opts['length_vector'] = length_vector - rb_opts['rb_pattern'] = rb_pattern - rb_opts['length_multiplier'] = length_multiplier - rb_opts['seed_offset'] = seed_offset - rb_opts['align_cliffs'] = align_cliffs - - # Generate the sequences - try: - rb_circs, _ = rb.randomized_benchmarking_seq(**rb_opts) - except OSError: - skip_msg = ('Skipping tests because ' - 'tables are missing') - raise NotImplementedError(skip_msg) - all_circuits = [] - for seq in rb_circs: - all_circuits += seq - return all_circuits - - -class RandomizedBenchmarkingQasmSimBenchmark: - # parameters for RB (1&2 qubits): - params = ([[[0]], [[0, 1]], [[0, 2], [1]]], - ['statevector', 'density_matrix', 'stabilizer', - 'extended_stabilizer', 'matrix_product_state'], - [no_noise(), mixed_unitary_noise_model(), reset_noise_model(), - kraus_noise_model()]) - param_names = ['rb_pattern', 'simulator_method', 'noise_model'] - version = '0.2.0' - timeout = 600 - - def setup(self, rb_pattern, _, __): - length_vector = np.arange(1, 200, 4) - nseeds = 1 - self.seed = 10 - self.circuits = build_rb_circuit(nseeds=nseeds, - length_vector=length_vector, - rb_pattern=rb_pattern, - seed=self.seed) - self.sim_backend = Aer.get_backend('qasm_simulator') - trans_circ = transpile(self.circuits, backend=self.sim_backend, - seed_transpiler=self.seed) - self.qobj = assemble(trans_circ, backend=self.sim_backend) - - def time_run_rb_circuit(self, _, simulator_method, noise_model): - backend_options = { - 'method': simulator_method, - 'noise_model': noise_model(), - } - job = self.sim_backend.run(self.qobj, - **backend_options) - job.result() - - def peakmem_run_rb_circuit(self, _, simulator_method, noise_model): - backend_options = { - 'method': simulator_method, - 'noise_model': noise_model(), - } - job = self.sim_backend.run(self.qobj, - **backend_options) - job.result() diff --git a/test/benchmark/simple_benchmarks.py b/test/benchmark/simple_benchmarks.py deleted file mode 100644 index c72944c0c3..0000000000 --- a/test/benchmark/simple_benchmarks.py +++ /dev/null @@ -1,107 +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. - -""" -Airspeed Velocity (ASV) benchmarks suite for simple 1-qubit/2-qubit gates -""" - -from qiskit import QiskitError -from qiskit.compiler import assemble -from qiskit.providers.aer import QasmSimulator -from .tools import mixed_unitary_noise_model, \ - reset_noise_model, kraus_noise_model, no_noise, \ - simple_cnot_circuit, simple_u3_circuit - -# Write the benchmarking functions here. -# See "Writing benchmarks" in the asv docs for more information. - - -class SimpleU3TimeSuite: - """ - Benchmark simple circuits with just one U3 gate - - The methods defined in this class will be executed by ASV framework as many - times as the combination of all parameters exist in `self.params`, for - exmaple: self.params = ([1,2,3],[4,5,6]), will run all methdos 9 times: - time_method(1,4) - time_method(1,5) - time_method(1,6) - time_method(2,4) - time_method(2,5) - time_method(2,6) - time_method(3,4) - time_method(3,5) - time_method(3,6) - - For each noise model, we want to test various configurations of number of - qubits - """ - - def __init__(self): - self.timeout = 60 * 20 - self.backend = QasmSimulator() - self.circuits = [] - for i in 5, 10, 15: - circuit = simple_u3_circuit(i) - self.circuits.append(assemble(circuit, self.backend, shots=1)) - - self.param_names = [ - "Simple u3 circuits", "Noise Model" - ] - self.params = (self.circuits, [ - no_noise(), - mixed_unitary_noise_model(), - reset_noise_model(), - kraus_noise_model() - ]) - - def time_simple_u3(self, qobj, noise_model_wrapper): - """ Benchmark for circuits with a simple u3 gate """ - result = self.backend.run( - qobj, noise_model=noise_model_wrapper() - ).result() - if result.status != 'COMPLETED': - raise QiskitError("Simulation failed. Status: " + result.status) - - -class SimpleCxTimeSuite: - """ - Benchmark simple circuits with just on CX gate - - For each noise model, we want to test various configurations of number of - qubits - """ - - def __init__(self): - self.timeout = 60 * 20 - self.backend = QasmSimulator() - self.circuits = [] - self.param_names = [ - "Simple cnot circuits", "Noise Model" - ] - for i in 5, 10, 15: - circuit = simple_cnot_circuit(i) - self.circuits.append(assemble(circuit, self.backend, shots=1)) - self.params = (self.circuits, [ - no_noise(), - mixed_unitary_noise_model(), - reset_noise_model(), - kraus_noise_model() - ]) - - def time_simple_cx(self, qobj, noise_model_wrapper): - """ Benchmark for circuits with a simple cx gate """ - result = self.backend.run( - qobj, noise_model=noise_model_wrapper() - ).result() - if result.status != 'COMPLETED': - raise QiskitError("Simulation failed. Status: " + result.status) diff --git a/test/benchmark/simulator_benchmark.py b/test/benchmark/simulator_benchmark.py new file mode 100644 index 0000000000..0ad2c2b6af --- /dev/null +++ b/test/benchmark/simulator_benchmark.py @@ -0,0 +1,270 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2018, 2019, 2020. +# +# 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. +""" +Base class of Qiskit Aer Benchmarking +""" +import sys +import numpy as np +from time import time +from qiskit.compiler import transpile, assemble +from qiskit.providers.aer import QasmSimulator, UnitarySimulator +from qiskit.providers.aer.noise import NoiseModel, amplitude_damping_error, depolarizing_error + +from benchmark.circuit_library_circuits import CircuitLibraryCircuits + +QOBJS = {} +QASM_SIMULATOR = QasmSimulator() + +class SimulatorBenchmarkSuite(CircuitLibraryCircuits): + + RUNTIME_STATEVECTOR_CPU = 'statevector' + RUNTIME_STATEVECTOR_GPU = 'statevector_gpu' + RUNTIME_MPS_CPU = 'matrix_product_state' + RUNTIME_DENSITY_MATRIX_CPU = 'density_matrix' + RUNTIME_DENSITY_MATRIX_GPU = 'density_matrix_gpu' + RUNTIME_STABILIZER_CPU = 'stabilizer' + RUNTIME_EXTENDED_STABILIZER_CPU = 'extended_stabilizer' + RUNTIME_UNITARY_MATRIX_CPU = 'unitary_matrix' + RUNTIME_UNITARY_MATRIX_GPU = 'unitary_matrix_gpu' + + RUNTIME_CPU = [ + RUNTIME_STATEVECTOR_CPU, + RUNTIME_MPS_CPU, + RUNTIME_DENSITY_MATRIX_CPU, + RUNTIME_STABILIZER_CPU, + RUNTIME_EXTENDED_STABILIZER_CPU, + RUNTIME_UNITARY_MATRIX_CPU + ] + + RUNTIME_GPU = [ + RUNTIME_STATEVECTOR_GPU, + RUNTIME_DENSITY_MATRIX_GPU, + RUNTIME_UNITARY_MATRIX_GPU + ] + + DEFAULT_RUNTIME = [ + RUNTIME_STATEVECTOR_CPU, + RUNTIME_MPS_CPU, + RUNTIME_DENSITY_MATRIX_CPU, + RUNTIME_STATEVECTOR_GPU + ] + + TRANSPLIERS = { + RUNTIME_MPS_CPU: 'self.transpile_for_mps' + } + + DEFAULT_QUBITS = [10, 15, 20, 25] + + MEASUREMENT_SAMPLING = 'sampling' + MEASUREMENT_EXPVAL = 'expval' + + DEFAULT_MEASUREMENT_METHODS = [ MEASUREMENT_SAMPLING ] + DEFAULT_MEASUREMENT_COUNTS = [ 1000 ] + + NOISE_IDEAL = 'ideal' + NOISE_DAMPING = 'damping' + NOISE_DEPOLARIZING = 'depolarizing' + + DEFAULT_NOISE_MODELS = [ NOISE_IDEAL ] + + def __init__(self, + name = 'simulator_benchmark', + apps = {}, + qubits = DEFAULT_QUBITS, + runtime_names = DEFAULT_RUNTIME, + measures = DEFAULT_MEASUREMENT_METHODS, + measure_counts = DEFAULT_MEASUREMENT_COUNTS, + noise_model_names = DEFAULT_NOISE_MODELS): + self.timeout = 60 * 10 + self.__name__ = name + + self.apps = apps if isinstance(apps, list) else [app for app in apps] + self.app2rep = {} if isinstance(apps, list) else apps + self.qubits = qubits + self.runtime_names = runtime_names + self.measures = measures + self.measure_counts = measure_counts + self.noise_model_names = noise_model_names + + self.params = (self.apps, self.measures, self.measure_counts, self.noise_model_names, self.qubits) + self.param_names = ["application", "measure_method", "measure_counts", "noise", "qubit"] + + all_simulators = [ QASM_SIMULATOR ] + + self.simulators = {} + self.backend_options_list = {} + self.backend_qubits = {} + + self.noise_models = {} + self.noise_models[self.NOISE_IDEAL] = None + if self.NOISE_DAMPING in self.noise_model_names: + noise_model = NoiseModel() + error = amplitude_damping_error(1e-3) + noise_model.add_all_qubit_quantum_error(error, ['u3']) + self.noise_models[self.NOISE_DAMPING] = noise_model + if self.NOISE_DEPOLARIZING in self.noise_model_names: + noise_model = NoiseModel() + noise_model.add_all_qubit_quantum_error(depolarizing_error(1e-3, 1), ['u3']) + noise_model.add_all_qubit_quantum_error(depolarizing_error(1e-2, 2), ['cx']) + self.noise_models[self.NOISE_DEPOLARIZING] = noise_model + + if self.RUNTIME_STATEVECTOR_CPU in runtime_names: + self.simulators[self.RUNTIME_STATEVECTOR_CPU] = QASM_SIMULATOR + self.backend_options_list[self.RUNTIME_STATEVECTOR_CPU] = { 'method': self.RUNTIME_STATEVECTOR_CPU } + self.backend_qubits[self.RUNTIME_STATEVECTOR_CPU] = self.qubits + + if self.RUNTIME_STATEVECTOR_GPU in runtime_names: + self.simulators[self.RUNTIME_STATEVECTOR_GPU] = QASM_SIMULATOR + self.backend_options_list[self.RUNTIME_STATEVECTOR_GPU] = { 'method': self.RUNTIME_STATEVECTOR_GPU } + self.backend_qubits[self.RUNTIME_STATEVECTOR_GPU] = self.qubits + + if self.RUNTIME_MPS_CPU in runtime_names: + self.simulators[self.RUNTIME_MPS_CPU] = QASM_SIMULATOR + self.backend_options_list[self.RUNTIME_MPS_CPU] = { 'method': self.RUNTIME_MPS_CPU } + self.backend_qubits[self.RUNTIME_MPS_CPU] = self.qubits + + if self.RUNTIME_DENSITY_MATRIX_CPU in runtime_names: + self.simulators[self.RUNTIME_DENSITY_MATRIX_CPU] = QASM_SIMULATOR + self.backend_options_list[self.RUNTIME_DENSITY_MATRIX_CPU] = { 'method': self.RUNTIME_DENSITY_MATRIX_CPU } + self.backend_qubits[self.RUNTIME_DENSITY_MATRIX_CPU] = [qubit for qubit in qubits if qubit <= 15] + + if self.RUNTIME_DENSITY_MATRIX_GPU in runtime_names: + self.simulators[self.RUNTIME_DENSITY_MATRIX_GPU] = QASM_SIMULATOR + self.backend_options_list[self.RUNTIME_DENSITY_MATRIX_GPU] = { 'method': self.RUNTIME_DENSITY_MATRIX_GPU } + self.backend_qubits[self.RUNTIME_DENSITY_MATRIX_GPU] = [qubit for qubit in qubits if qubit <= 15] + + def gen_qobj(self, runtime, app, measure, measure_count, qubit): + + def add_measure_all(base): + circuit = base.copy() + circuit.measure_all() + return circuit + + def add_expval(base, num_terms): + circuit = base.copy() + from qiskit.providers.aer.extensions import snapshot_expectation_value + from numpy.random import default_rng + rng = default_rng(1) + paulis = [''.join(s) for s in + rng.choice(['I', 'X', 'Y', 'Z'], size=(num_terms, qubit))] + pauli_op = [(1 / num_terms, pauli) for pauli in paulis] + circuit.snapshot_expectation_value('expval', pauli_op, range(qubit)) + + circuit = eval('self.{0}'.format(app))(qubit, None if app not in self.app2rep else self.app2rep[app]) + if len(circuit.parameters) > 0: + param_binds = {} + for param in circuit.parameters: + param_binds[param] = np.random.random() + circuit = circuit.bind_parameters(param_binds) + + simulator = self.simulators[runtime] + if measure == self.MEASUREMENT_SAMPLING: + if runtime in self.TRANSPLIERS: + runtime_circuit = eval(self.TRANSPLIERS[runtime])(circuit) + if (runtime, app, measure, measure_count, qubit) not in QOBJS: + QOBJS[(runtime, app, measure, measure_count, qubit)] = assemble(runtime_circuit, simulator, shots=measure_count) + return QOBJS[(runtime, app, measure, measure_count, qubit)] + else: + runtime_circuit = circuit + if (simulator, app, measure, measure_count, qubit) not in QOBJS: + QOBJS[(simulator, app, measure, measure_count, qubit)] = assemble(runtime_circuit, simulator, shots=measure_count) + return QOBJS[(simulator, app, measure, measure_count, qubit)] + elif measure == self.MEASUREMENT_EXPVAL: + if runtime in self.TRANSPLIERS: + runtime_circuit = eval(self.TRANSPLIERS[runtime])(circuit) + if (runtime, app, measure, measure_count, qubit) not in QOBJS: + QOBJS[(runtime, app, measure, measure_count, qubit)] = assemble(runtime_circuit, simulator, shots=1) + return QOBJS[(runtime, app, measure, measure_count, qubit)] + else: + runtime_circuit = circuit + if (simulator, app, measure, measure_count, qubit) not in QOBJS: + QOBJS[(simulator, app, measure, measure_count, qubit)] = assemble(runtime_circuit, simulator, shots=1) + return QOBJS[(simulator, app, measure, measure_count, qubit)] + + def _transpile(self, circuit, basis_gates): + from qiskit import transpile + return transpile(circuit, basis_gates=basis_gates) + + def transpile(self, circuit): + return self._transpile(circuit, [ + 'u1', 'u2', 'u3', 'cx', 'cz', 'id', 'x', 'y', 'z', 'h', 's', 'sdg', + 't', 'tdg', 'swap', 'ccx', 'unitary', 'diagonal', 'initialize', + 'cu1', 'cu2', 'cu3', 'cswap', 'mcx', 'mcy', 'mcz', + 'mcu1', 'mcu2', 'mcu3', 'mcswap', 'multiplexer', 'kraus', 'roerror']) + + def transpile_for_mps(self, circuit): + return self._transpile(circuit, [ + 'u1', 'u2', 'u3', 'cx', 'cz', 'id', 'x', 'y', 'z', 'h', 's', 'sdg', + 't', 'tdg', 'swap', 'ccx'#, 'unitary', 'diagonal', 'initialize', + 'cu1', #'cu2', 'cu3', 'cswap', 'mcx', 'mcy', 'mcz', + #'mcu1', 'mcu2', 'mcu3', 'mcswap', 'multiplexer', 'kraus', + 'roerror' + ]) + + def _run(self, runtime, app, measure, measure_count, noise_name, qubit): + if runtime not in self.simulators or runtime not in self.backend_options_list: + raise ValueError('unknown runtime: {0}'.format(runtime)) + simulator = self.simulators[runtime] + backend_options = self.backend_options_list[runtime] + noise_model = self.noise_models[noise_name] + + if qubit not in self.backend_qubits[runtime]: + raise ValueError('out of qubit range: qubit={0}, list={1}'.format(qubit, self.backend_qubits[runtime])) + + qobj = self.gen_qobj(runtime, app, measure, measure_count, qubit) + if qobj is None: + raise ValueError('no qobj: measure={0}:{1}, qubit={2}'.format(measure, measure_count, qubit)) + + start = time() + result = simulator.run(qobj, backend_options=backend_options, noise_model=noise_model).result() + if result.status != 'COMPLETED': + try: + reason = None + ret_dict = result.to_dict() + if 'results' in ret_dict: + if len (ret_dict['results']) > 0 and 'status' in ret_dict['results'][0]: + reason = ret_dict['results'][0]['status'] + if reason is None and 'status' in ret_dict: + reason = ret_dict['status'] + if reason is None: + reason = 'unknown' + except: + reason = 'unknown' + raise ValueError('simulation error ({0})'.format(reason)) + return time() - start + + def run_manual(self): + import timeout_decorator + @timeout_decorator.timeout(self.timeout) + def run_with_timeout (suite, runtime, app, measure, measure_count, noise_name, qubit): + start = time() + return eval('suite.track_{0}'.format(runtime))(app, measure, measure_count, noise_name, qubit) + + #for runtime in self.runtime_names: + for noise_name in self.noise_model_names: + for runtime in self.runtime_names: + for app in self.apps: + repeats = None if app not in self.app2rep else self.app2rep[app] + app_name = app if repeats is None else '{0}:{1}'.format(app, repeats) + for qubit in self.qubits: + for measure in self.measures: + for measure_count in self.measure_counts: + print ('{0},{1},{2},{3},{4},{5},{6},'.format(self.__name__, app_name, runtime, measure, measure_count, noise_name, qubit), end="") + try: + elapsed = run_with_timeout(self, runtime, app, measure, measure_count, noise_name, qubit) + print ('{0}'.format(elapsed)) + except ValueError as e: + print ('{0}'.format(e)) + except: + import traceback + traceback.print_exc(file=sys.stderr) + print ('unknown error') diff --git a/test/benchmark/tools.py b/test/benchmark/tools.py deleted file mode 100644 index cd541285cb..0000000000 --- a/test/benchmark/tools.py +++ /dev/null @@ -1,216 +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. -""" -Benchmarking utility functions. -""" - -import math -from itertools import repeat -from numpy import random -from scipy import linalg -from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit -from qiskit.providers.aer.noise import NoiseModel -from qiskit.providers.aer.noise.errors import depolarizing_error -from qiskit.providers.aer.noise.errors import amplitude_damping_error -from qiskit.providers.aer.noise.errors import thermal_relaxation_error - - -class NoiseWithDescription: - """ This is just a wrapper for adding a descriptive text to the noise model - so ASV can print this text in its reports - """ - def __init__(self, noise_model, description): - self._noise_model = noise_model - self._description = description - - def __repr__(self): - return self._description - - def __call__(self): - return self._noise_model - - -# pylint: disable=no-member -def _add_measurements(circuit, qr): - cr = ClassicalRegister(qr.size) - meas = QuantumCircuit(qr, cr) - meas.barrier(qr) - meas.measure(qr, cr) - return circuit + meas - - -def no_noise(): - """ No noise at all """ - return NoiseWithDescription(None, "No Noise") - - -def mixed_unitary_noise_model(): - """Return test rest mixed unitary noise model""" - noise_model = NoiseModel() - error1 = depolarizing_error(0.1, 1) - noise_model.add_all_qubit_quantum_error(error1, ['u1', 'u2', 'u3']) - error2 = depolarizing_error(0.1, 2) - noise_model.add_all_qubit_quantum_error(error2, ['cx']) - return NoiseWithDescription(noise_model, "Mixed Unitary Noise") - - -def reset_noise_model(): - """Return test reset noise model""" - noise_model = NoiseModel() - error1 = thermal_relaxation_error(50, 50, 0.1) - noise_model.add_all_qubit_quantum_error(error1, ['u1', 'u2', 'u3']) - error2 = error1.tensor(error1) - noise_model.add_all_qubit_quantum_error(error2, ['cx']) - return NoiseWithDescription(noise_model, "Reset Noise") - - -def kraus_noise_model(): - """Return test Kraus noise model""" - noise_model = NoiseModel() - error1 = amplitude_damping_error(0.1) - noise_model.add_all_qubit_quantum_error(error1, ['u1', 'u2', 'u3']) - error2 = error1.tensor(error1) - noise_model.add_all_qubit_quantum_error(error2, ['cx']) - return NoiseWithDescription(noise_model, "Kraus Noise") - - -def quantum_volume_circuit(num_qubits, depth, measure=True, seed=None): - """Create a quantum volume circuit without measurement. - - The model circuits consist of layers of Haar random - elements of SU(4) applied between corresponding pairs - of qubits in a random bipartition. - - Args: - num_qubits (int): number of qubits - depth (int): ideal depth of each model circuit (over SU(4)) - measure (bool): include measurement in circuit. - seed (int): the seed for the random number generator - - Returns: - QuantumCircuit: A quantum volume circuit. - """ - # Create random number generator with possibly fixed seed - rng = random.RandomState(seed) - # Create quantum/classical registers of size n - qr = QuantumRegister(num_qubits) - circuit = QuantumCircuit(qr) - # For each layer - for _ in repeat(None, depth): - # Generate uniformly random permutation Pj of [0...n-1] - perm = rng.permutation(num_qubits) - # For each consecutive pair in Pj, generate Haar random SU(4) - # Decompose each SU(4) into CNOT + SU(2) and add to Ci - for k in range(math.floor(num_qubits / 2)): - # Generate random SU(4) matrix - # pylint: disable=invalid-name - X = (rng.randn(4, 4) + 1j * rng.randn(4, 4)) - SU4, _ = linalg.qr(X) # Q is a unitary matrix - SU4 /= pow(linalg.det(SU4), 1 / 4) # make Q a special unitary - qubits = [qr[int(perm[2 * k])], qr[int(perm[2 * k + 1])]] - circuit.unitary(SU4, qubits) - if measure is True: - circuit = _add_measurements(circuit, qr) - return circuit - - -def qft_circuit(num_qubits, measure=True): - """Create a qft circuit. - - Args: - num_qubits (int): number of qubits - measure (bool): include measurement in circuit. - - Returns: - QftCircuit: A qft circuit. - """ - # Create quantum/classical registers of size n - qr = QuantumRegister(num_qubits) - circuit = QuantumCircuit(qr) - - for i in range(num_qubits): - for j in range(i): - circuit.cu1(math.pi/float(2**(i-j)), qr[i], qr[j]) - circuit.h(qr[i]) - - if measure is True: - circuit = _add_measurements(circuit, qr) - return circuit - - -def simple_u3_circuit(num_qubits, measure=True): - """Creates a simple circuit composed by u3 gates, with measurements or not - at the end of each qubit. - - Args: - num_qubits (int): Number of qubits - measure (bool): Add measurements at the end of each qubit - - Returns: - QuantumCircuit: The simple quantum circuit - """ - qr = QuantumRegister(num_qubits) - circuit = QuantumCircuit(qr) - for i in range(num_qubits): - circuit.u3(1.1, 2.2, 3.3, qr[i]) - - if measure: - circuit = _add_measurements(circuit, qr) - return circuit - - -def simple_cnot_circuit(num_qubits, measure=True): - """Creates a simple circuit composed by cnot gates, with measurements or - not at the end of each qubit. - - Args: - num_qubits (int): Number of qubits - measure (bool): Add measurements at the end of each qubit - - Returns: - QuantumCircuit: The simple quantum circuit - """ - qr = QuantumRegister(num_qubits) - circuit = QuantumCircuit(qr) - for i in range(num_qubits): - # for the last qubit, we exchange control and target qubits - target_qubit = i + 1 if num_qubits - 1 > i else i - 1 - circuit.cx(qr[i], qr[target_qubit]) - - if measure: - circuit = _add_measurements(circuit, qr) - return circuit - - -# pylint: disable=invalid-name -def quantum_fourier_transform_circuit(num_qubits): - """Create quantum fourier transform circuit. - - Args: - num_qubits (int): Number of qubits - - Returns: - QuantumCircuit: QFT circuit - """ - qreg = QuantumRegister(num_qubits) - creg = ClassicalRegister(num_qubits) - - circuit = QuantumCircuit(qreg, creg, name="qft") - - n = len(qreg) - - for i in range(n): - for j in range(i): - circuit.cu1(math.pi/float(2**(i-j)), qreg[i], qreg[j]) - circuit.h(qreg[i]) - circuit.measure(qreg, creg) - return circuit diff --git a/test/benchmark/vqe_application.py b/test/benchmark/vqe_application.py new file mode 100644 index 0000000000..775855ec9b --- /dev/null +++ b/test/benchmark/vqe_application.py @@ -0,0 +1,73 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2018, 2019, 2020. +# +# 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. +""" +Base class of Qiskit Aer Benchmarking +""" +import sys +import numpy as np +import multiprocessing +from time import time +from qiskit import Aer +from qiskit.aqua.algorithms import VQE +from qiskit.aqua.components.optimizers import SLSQP +from qiskit.chemistry.applications import MolecularGroundStateEnergy +from qiskit.chemistry.components.initial_states import HartreeFock +from qiskit.chemistry.components.variational_forms import UCCSD +from qiskit.chemistry.drivers import PySCFDriver, UnitsType + +class UCCSDBenchmarkSuite: + + def __init__(self, + name = 'uccsd_benchmark'): + + self.mol_strings = { + 'H2': ('H .0 .0 .0; H .0 .0 0.735', 2), # qubits: 2 + 'LiH': ('H .0 .0 .0; Li .0 .0 2.5', 10), # qubits: 10 + 'HF': ('H .0 .0 .0; F .0 .0 1.25', 10), # qubits: 10 + } + + self.timeout = 60 * 60 + self.__name__ = name + self.params = ([mol_name for mol_name in self.mol_strings]) + self.param_names = ["mol"] + + def _run_uccsd_vqe(self, mol_string, method, threads): + driver = PySCFDriver(atom=mol_string, unit=UnitsType.ANGSTROM, charge=0, spin=0, basis='sto3g') + def cb_create_solver(num_particles, num_orbitals, + qubit_mapping, two_qubit_reduction, z2_symmetries): + initial_state = HartreeFock(num_orbitals, num_particles, qubit_mapping, + two_qubit_reduction, z2_symmetries.sq_list) + var_form = UCCSD(num_orbitals=num_orbitals, + num_particles=num_particles, + initial_state=initial_state, + qubit_mapping=qubit_mapping, + two_qubit_reduction=two_qubit_reduction, + z2_symmetries=z2_symmetries) + vqe = VQE(var_form=var_form, include_custom=True, optimizer=SLSQP(maxiter=5000), max_evals_grouped=256) + vqe.quantum_instance = Aer.get_backend('qasm_simulator') + vqe.quantum_instance.backend_options['backend_options'] = {'max_parallel_experiments':threads, 'method': method} + + return vqe + mgse = MolecularGroundStateEnergy(driver) + result = mgse.compute_energy(cb_create_solver) + + def time_statevector(self, mol_name): + threads = multiprocessing.cpu_count() + mol_string = self.mol_strings[mol_name][0] + qubit = self.mol_strings[mol_name][1] + self._run_uccsd_vqe(mol_string, 'statevector', threads) + + def time_statevector_gpu(self, mol_name): + threads = 1 + mol_string = self.mol_strings[mol_name][0] + qubit = self.mol_strings[mol_name][1] + self._run_uccsd_vqe(mol_string, 'statevector_gpu', threads) From 7ef7a44dfeaa5a9e71c01713ec604b3d6d8cf769 Mon Sep 17 00:00:00 2001 From: hhorii Date: Thu, 5 Nov 2020 16:40:18 +0900 Subject: [PATCH 034/126] add SIMD optimization of diagonal matrix multiplication (#982) --- src/simulators/statevector/qubitvector.hpp | 3 +- src/simulators/statevector/qv_avx2.cpp | 237 +++++++++++++++++- src/simulators/statevector/qv_avx2.hpp | 9 + .../statevector/transformer_avx2.hpp | 23 ++ 4 files changed, 270 insertions(+), 2 deletions(-) diff --git a/src/simulators/statevector/qubitvector.hpp b/src/simulators/statevector/qubitvector.hpp index c3d682c4ad..71bea6d67e 100755 --- a/src/simulators/statevector/qubitvector.hpp +++ b/src/simulators/statevector/qubitvector.hpp @@ -1031,7 +1031,8 @@ void QubitVector::apply_multiplexer(const reg_t &control_qubits, template void QubitVector::apply_diagonal_matrix(const reg_t &qubits, const cvector_t &diag) { - transformer_->apply_diagonal_matrix(data_, data_size_, omp_threads_managed(), qubits, diag); + + transformer_->apply_diagonal_matrix(data_, data_size_, omp_threads_managed(), qubits, diag); } template diff --git a/src/simulators/statevector/qv_avx2.cpp b/src/simulators/statevector/qv_avx2.cpp index 8434e037c0..6c6bba4161 100644 --- a/src/simulators/statevector/qv_avx2.cpp +++ b/src/simulators/statevector/qv_avx2.cpp @@ -11,13 +11,17 @@ * copyright notice, and modified files need to carry a notice indicating * that they have been altered from the originals. */ - #include "qv_avx2.hpp" #include #include #include #include #include +#include + +#ifdef _OPENMP +#include +#endif /** * DISCLAIMER: We want to compile this code in isolation of the rest of the @@ -151,6 +155,18 @@ void avx_apply_lambda(const uint64_t data_size, } } +template +void avx_apply_lambda(const uint64_t data_size, + const uint64_t skip, + Lambda&& func, + const size_t omp_threads, + const param_t& params) { +#pragma omp parallel for if (omp_threads > 1) num_threads(omp_threads) + for (int64_t k = 0; k < data_size; k += skip) { + std::forward(func)(k, params); + } +} + template using m256_t = typename std:: conditional::value, __m256d, __m256>::type; @@ -255,6 +271,49 @@ static void _mm256_store(double* d, const m256_t& c) { _mm256_store_pd(d, c); } +static m256_t_mm256_hsub(m256_t& vec1, m256_t& vec2) { + return _mm256_hsub_pd(vec1, vec2); +} + +static m256_t _mm256_hsub(m256_t& vec1, m256_t& vec2) { + return _mm256_hsub_ps(vec1, vec2); +} + +static m256_t _mm256_swith_real_and_imag(m256_t& vec) { + return _mm256_permute_pd(vec, 0b0101); +} + +static m256_t _mm256_swith_real_and_imag(m256_t& vec) { + return _mm256_permute_ps(vec, _MM_SHUFFLE(2, 3, 0, 1)); +} + +static m256_t _mm256_neg(double dummy) { + return _mm256_setr_pd(1.0, -1.0, 1.0, -1.0); +} + +static m256_t _mm256_neg(float dummy) { + return _mm256_setr_ps(1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0); +} + +static m256_t _mm256_align(m256_t& vec) { + return vec; +} + +static m256_t _mm256_align(m256_t& vec) { + return _mm256_permute_ps(vec, _MM_SHUFFLE(3, 1, 2, 0)); +} + +template +static inline void _mm_complex_multiply(m256_t& vec1, + m256_t& vec2) { + m256_t vec3 = _mm256_mul(vec1, vec2); + vec2 = _mm256_swith_real_and_imag(vec2); + vec2 = _mm256_mul(vec2, _mm256_neg((FloatType) .0)); + m256_t vec4 = _mm256_mul(vec1, vec2); + vec1 = _mm256_hsub(vec3, vec4); + vec1 = _mm256_align(vec1); +} + template static inline void _mm_complex_multiply(m256_t& real_ret, m256_t& imag_ret, @@ -1045,6 +1104,7 @@ template Avx apply_matrix_avx(double*, const size_t qregs_size, const double* mat, const size_t omp_threads); + template Avx apply_matrix_avx(float* data, const uint64_t data_size, const uint64_t* qregs, @@ -1052,5 +1112,180 @@ template Avx apply_matrix_avx(float* data, const float* mat, const size_t omp_threads); +template +std::complex* _to_complex(data_t* vec) { + return reinterpret_cast*>(vec); +} + +template +const std::complex* _to_complex(const data_t* vec) { + return reinterpret_cast*>(vec); +} + +inline int _omp_get_thread_num() { +#ifdef _OPENMP + return omp_get_thread_num(); +#else + return 0; +#endif +} + +m256_t _load_diagonal_input(const std::complex* input_vec, + std::complex* tmp, + const uint64_t i, + const uint64_t* qregs, + const size_t qregs_size, + const size_t q0_mask) { + uint64_t vec_idx0 = 0; + for (size_t j = 0; j < qregs_size; ++j) + if (i & (MASKS[qregs[j]] + 1UL)) + vec_idx0 += (MASKS[j] + 1UL); + tmp[0] = input_vec[vec_idx0]; + tmp[1] = input_vec[vec_idx0 | q0_mask]; + return _mm256_load(reinterpret_cast(tmp)); +} + +m256_t _load_diagonal_input(const std::complex* input_vec, + std::complex* tmp, + const uint64_t i, + const uint64_t* qregs, + const size_t qregs_size, + const size_t q0_mask, + const size_t q1_mask) { + uint64_t vec_idx0 = 0; + for (size_t j = 0; j < qregs_size; ++j) + if (i & (MASKS[qregs[j]] + 1UL)) + vec_idx0 += (MASKS[j] + 1UL); + tmp[0] = input_vec[vec_idx0]; + tmp[1] = input_vec[vec_idx0 | q0_mask]; + tmp[2] = input_vec[vec_idx0 | q1_mask]; + tmp[3] = input_vec[vec_idx0 | q0_mask | q1_mask]; + return _mm256_load(reinterpret_cast(tmp)); +} + +template <> +Avx apply_diagonal_matrix_avx(double* qv_data_, + const uint64_t data_size, + const uint64_t* qregs, + const size_t qregs_size, + const double* vec_, + const size_t omp_threads) { + + auto qv_data = _to_complex(qv_data_); + const auto input_vec = _to_complex(vec_); + + std::complex** tmps; + tmps = reinterpret_cast**>(malloc(sizeof(std::complex*) * omp_threads)); + +#pragma omp parallel if (omp_threads > 1) num_threads(omp_threads) + { +#if !defined(_WIN64) && !defined(_WIN32) + void* data; + posix_memalign(&data, 64, sizeof(std::complex) * 2); + tmps[_omp_get_thread_num()] = reinterpret_cast*>(data); +#else + tmps[_omp_get_thread_num()] = reinterpret_cast*>(malloc(sizeof(std::complex) * 2)); +#endif + } + + size_t q0_mask_ = 0; + for (int i = 0; i < qregs_size; ++i) { + if (qregs[i] == 0) { + q0_mask_ = 1UL << i; + break; + } + } + const size_t q0_mask = q0_mask_; + const auto batch = (data_size <= (1UL << 5) ? 0 : 4); + + auto lambda = [&](const uint64_t i_, const std::complex* input_vec) -> void { + const auto base = i_ << (batch + 1); + const auto until = base + (1UL << (batch + 1)); + std::complex* tmp = tmps[_omp_get_thread_num()]; + for (auto i = base; i < until; i+=2) { + auto tgt_qv_data = _mm256_load(reinterpret_cast(&(qv_data[i]))); + auto input_data = _load_diagonal_input(input_vec, tmp, i, qregs, qregs_size, q0_mask); + _mm_complex_multiply(tgt_qv_data, input_data); + _mm256_store(reinterpret_cast(&(qv_data[i])), tgt_qv_data); + } + }; + + avx_apply_lambda(data_size >> (batch + 1), 1, lambda, omp_threads, input_vec); + +#pragma omp parallel for if (omp_threads > 1) num_threads(omp_threads) + for (int i = 0; i < omp_threads; ++i) { + free(tmps[_omp_get_thread_num()]); + } + + free(tmps); + + return Avx::Applied; +} + +template <> +Avx apply_diagonal_matrix_avx(float* qv_data_, + const uint64_t data_size, + const uint64_t* qregs, + const size_t qregs_size, + const float* vec_, + const size_t omp_threads) { + + if (data_size < (1UL << 2)) + return Avx::NotApplied; + + auto qv_data = _to_complex(qv_data_); + const auto input_vec = _to_complex(vec_); + + auto tmps = reinterpret_cast**>(malloc(sizeof(std::complex*) * omp_threads)); + +#pragma omp parallel if (omp_threads > 1) num_threads(omp_threads) + { + #if !defined(_WIN64) && !defined(_WIN32) + void* data; + posix_memalign(&data, 64, sizeof(std::complex) * 4); + tmps[_omp_get_thread_num()] = reinterpret_cast*>(data); + #else + tmps[_omp_get_thread_num()] = reinterpret_cast*>(malloc(sizeof(std::complex) * 4)); + #endif + } + + size_t q0_mask_ = 0; + size_t q1_mask_ = 0; + for (size_t i = 0; i < qregs_size; ++i) { + if (qregs[i] == 0) { + q0_mask_ = 1UL << i; + } else if (qregs[i] == 1) { + q1_mask_ = 1UL << i; + } + } + + const size_t q0_mask = q0_mask_; + const size_t q1_mask = q1_mask_; + const auto batch = (data_size <= (1UL << 6) ? 0 : 4); + + auto lambda = [&](const uint64_t i_, const std::complex* input_vec) -> void { + const auto base = i_ << (batch + 2); + const auto until = base + (1UL << (batch + 2)); + std::complex* tmp = tmps[_omp_get_thread_num()]; + for (auto i = base; i < until; i+=4) { + m256_t tgt_qv_data = _mm256_load(reinterpret_cast(&(qv_data[i]))); + auto input_data = _load_diagonal_input(input_vec, tmp, i, qregs, qregs_size, q0_mask, q1_mask); + _mm_complex_multiply(tgt_qv_data, input_data); + _mm256_store(reinterpret_cast(&(qv_data[i])), tgt_qv_data); + } + }; + + avx_apply_lambda(data_size >> (batch + 2), 1, lambda, omp_threads, input_vec); + +#pragma omp parallel for if (omp_threads > 1) num_threads(omp_threads) + for (int i = 0; i < omp_threads; ++i) { + free(tmps[_omp_get_thread_num()]); + } + + free(tmps); + + return Avx::Applied; +} + } /* End namespace QV */ } /* End namespace AER */ diff --git a/src/simulators/statevector/qv_avx2.hpp b/src/simulators/statevector/qv_avx2.hpp index a04dcdc305..4fbbd24acd 100644 --- a/src/simulators/statevector/qv_avx2.hpp +++ b/src/simulators/statevector/qv_avx2.hpp @@ -31,6 +31,15 @@ Avx apply_matrix_avx(FloatType* data, const FloatType* mat, const size_t omp_threads); + +template +Avx apply_diagonal_matrix_avx(FloatType* data, + const uint64_t data_size, + const uint64_t* qregs, + const size_t qregs_size, + const FloatType* vec, + const size_t omp_threads); + } // end namespace QV } // end namespace AER #endif diff --git a/src/simulators/statevector/transformer_avx2.hpp b/src/simulators/statevector/transformer_avx2.hpp index bce6bf4aea..5faf3b8b4c 100755 --- a/src/simulators/statevector/transformer_avx2.hpp +++ b/src/simulators/statevector/transformer_avx2.hpp @@ -36,6 +36,10 @@ class TransformerAVX2 : public Transformer { // matrix. void apply_matrix(Container &data, size_t data_size, int threads, const reg_t &qubits, const cvector_t &mat) const override; + + void apply_diagonal_matrix(Container &data, size_t data_size, int threads, + const reg_t &qubits, const cvector_t &diag) const override; + }; /******************************************************************************* @@ -68,6 +72,25 @@ void TransformerAVX2::apply_matrix(Container &data, size_t da Base::apply_matrix(data, data_size, threads, qubits, mat); } + +template +void TransformerAVX2::apply_diagonal_matrix(Container &data, + size_t data_size, + int threads, + const reg_t &qubits, + const cvector_t &diag) const { + + if (apply_diagonal_matrix_avx( + reinterpret_cast(data), data_size, qubits.data(), + qubits.size(), reinterpret_cast(Base::convert(diag).data()), + threads) == Avx::Applied) { + return; + } + + Base::apply_diagonal_matrix(data, data_size, threads, qubits, diag); +} + + #endif // AVX2 Code //------------------------------------------------------------------------------ From 93cef6cf524bf78250415726d905ba729a3531c4 Mon Sep 17 00:00:00 2001 From: merav-aharoni <46567124+merav-aharoni@users.noreply.github.com> Date: Fri, 6 Nov 2020 12:03:04 +0200 Subject: [PATCH 035/126] MPS: Support apply_diagonal_matrix (#1013) --- .../notes/diagnoal-b06c925f44540f8e.yaml | 8 +++ .../matrix_product_state.hpp | 12 +++-- .../matrix_product_state_internal.cpp | 51 ++++++++++--------- .../matrix_product_state_internal.hpp | 24 ++++++--- .../matrix_product_state_tensor.hpp | 30 ++++++----- ...est_qasm_simulator_matrix_product_state.py | 2 + 6 files changed, 80 insertions(+), 47 deletions(-) create mode 100644 releasenotes/notes/diagnoal-b06c925f44540f8e.yaml diff --git a/releasenotes/notes/diagnoal-b06c925f44540f8e.yaml b/releasenotes/notes/diagnoal-b06c925f44540f8e.yaml new file mode 100644 index 0000000000..c2d86c5942 --- /dev/null +++ b/releasenotes/notes/diagnoal-b06c925f44540f8e.yaml @@ -0,0 +1,8 @@ +--- + +features: + - | + Added support for MPS::apply_diagonal_matrix. + + + diff --git a/src/simulators/matrix_product_state/matrix_product_state.hpp b/src/simulators/matrix_product_state/matrix_product_state.hpp index ab76281fb5..4470772ddb 100644 --- a/src/simulators/matrix_product_state/matrix_product_state.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state.hpp @@ -45,10 +45,11 @@ namespace MatrixProductState { // OpSet of supported instructions const Operations::OpSet StateOpSet( {Operations::OpType::gate, Operations::OpType::measure, - Operations::OpType::reset, Operations::OpType::initialize, - Operations::OpType::snapshot, Operations::OpType::barrier, - Operations::OpType::bfunc, Operations::OpType::roerror, - Operations::OpType::matrix, Operations::OpType::kraus}, + Operations::OpType::reset, Operations::OpType::initialize, + Operations::OpType::snapshot, Operations::OpType::barrier, + Operations::OpType::bfunc, Operations::OpType::roerror, + Operations::OpType::matrix, Operations::OpType::diagonal_matrix, + Operations::OpType::kraus}, // Gates {"id", "x", "y", "z", "s", "sdg", "h", "t", "tdg", "p", "u1", "u2", "u3", "u", "U", "CX", "cx", "cz", "cp", "cu1", "swap", "ccx"}, @@ -485,6 +486,9 @@ void State::apply_ops(const std::vector &ops, case Operations::OpType::matrix: apply_matrix(op.qubits, op.mats[0]); break; + case Operations::OpType::diagonal_matrix: + BaseState::qreg_.apply_diagonal_matrix(op.qubits, op.params); + break; case Operations::OpType::kraus: apply_kraus(op.qubits, op.mats, rng); break; 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 81982a5d12..9c06aa22fb 100644 --- a/src/simulators/matrix_product_state/matrix_product_state_internal.cpp +++ b/src/simulators/matrix_product_state/matrix_product_state_internal.cpp @@ -410,7 +410,7 @@ void MPS::apply_swap_internal(uint_t index_A, uint_t index_B, bool swap_gate) { // V is split by columns to yield two MPS_Tensors representing qubit B (in reshape_V_after_SVD), // the diagonal of S becomes the Lambda-vector in between A and B. //------------------------------------------------------------------------- -void MPS::apply_2_qubit_gate(uint_t index_A, uint_t index_B, Gates gate_type, const cmatrix_t &mat) +void MPS::apply_2_qubit_gate(uint_t index_A, uint_t index_B, Gates gate_type, const cmatrix_t &mat, bool is_diagonal) { // 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 @@ -434,7 +434,8 @@ void MPS::apply_2_qubit_gate(uint_t index_A, uint_t index_B, Gates gate_type, co void MPS::common_apply_2_qubit_gate(uint_t A, // the gate is applied to A and A+1 Gates gate_type, const cmatrix_t &mat, - bool swapped) { + bool swapped, + bool is_diagonal) { // After we moved the qubits as necessary, // the operation is always between qubits A and A+1 @@ -470,7 +471,7 @@ void MPS::common_apply_2_qubit_gate(uint_t A, // the gate is applied to A and A 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); + temp.apply_matrix(mat, !swapped, is_diagonal); break; default: @@ -490,7 +491,8 @@ void MPS::common_apply_2_qubit_gate(uint_t A, // the gate is applied to A and A } void MPS::apply_3_qubit_gate(const reg_t &qubits, - Gates gate_type, const cmatrix_t &mat) + Gates gate_type, const cmatrix_t &mat, + bool is_diagonal) { if (qubits.size() != 3) { std::stringstream ss; @@ -552,40 +554,44 @@ void MPS::apply_3_qubit_gate(const reg_t &qubits, q_reg_[first+2].div_Gamma_by_right_Lambda(lambda_reg_[first+2]); } -void MPS::apply_matrix(const reg_t & qubits, const cmatrix_t &mat) { +void MPS::apply_matrix(const reg_t & qubits, const cmatrix_t &mat, + bool is_diagonal) { reg_t internal_qubits = get_internal_qubits(qubits); - apply_matrix_internal(internal_qubits, mat); + apply_matrix_internal(internal_qubits, mat, is_diagonal); } -void MPS::apply_matrix_internal(const reg_t & qubits, const cmatrix_t &mat) +void MPS::apply_matrix_internal(const reg_t & qubits, const cmatrix_t &mat, + bool is_diagonal) { switch (qubits.size()) { case 1: - q_reg_[qubits[0]].apply_matrix(mat); + q_reg_[qubits[0]].apply_matrix(mat, is_diagonal); break; case 2: - apply_2_qubit_gate(qubits[0], qubits[1], su4, mat); + apply_2_qubit_gate(qubits[0], qubits[1], su4, mat, is_diagonal); break; default: - apply_multi_qubit_gate(qubits, mat); + apply_multi_qubit_gate(qubits, mat, is_diagonal); } } void MPS::apply_multi_qubit_gate(const reg_t &qubits, - const cmatrix_t &mat) { + const cmatrix_t &mat, + bool is_diagonal) { // need to reverse qubits because that is the way they // are defined in the Qiskit interface reg_t reversed_qubits = qubits; std::reverse(reversed_qubits.begin(), reversed_qubits.end()); if (is_ordered(reversed_qubits)) - apply_matrix_to_target_qubits(reversed_qubits, mat); + apply_matrix_to_target_qubits(reversed_qubits, mat, is_diagonal); else - apply_unordered_multi_qubit_gate(reversed_qubits, mat); + apply_unordered_multi_qubit_gate(reversed_qubits, mat, is_diagonal); } void MPS::apply_unordered_multi_qubit_gate(const reg_t &qubits, - const cmatrix_t &mat){ + const cmatrix_t &mat, + bool is_diagonal){ reg_t actual_indices(num_qubits_); std::iota( std::begin(actual_indices), std::end(actual_indices), 0); reg_t target_qubits(qubits.size()); @@ -593,16 +599,17 @@ void MPS::apply_unordered_multi_qubit_gate(const reg_t &qubits, move_qubits_to_right_end(qubits, target_qubits, actual_indices); - apply_matrix_to_target_qubits(target_qubits, mat); + apply_matrix_to_target_qubits(target_qubits, mat, is_diagonal); } void MPS::apply_matrix_to_target_qubits(const reg_t &target_qubits, - const cmatrix_t &mat) { + const cmatrix_t &mat, + bool is_diagonal) { uint_t num_qubits = target_qubits.size(); uint_t first = target_qubits.front(); MPS_Tensor sub_tensor(state_vec_as_MPS(first, first+num_qubits-1)); - sub_tensor.apply_matrix(mat); + sub_tensor.apply_matrix(mat, is_diagonal); // state_mat is a matrix containing the flattened representation of the sub-tensor // into a single matrix. E.g., sub_tensor will contain 8 matrices for 3-qubit @@ -637,15 +644,13 @@ void MPS::apply_matrix_to_target_qubits(const reg_t &target_qubits, } void MPS::apply_diagonal_matrix(const AER::reg_t &qubits, const cvector_t &vmat) { - //temporarily support by converting the vector to a full matrix whose diagonal is vmat + // converting the vector to a 1xn matrix whose first (and single) row is vmat uint_t dim = vmat.size(); - cmatrix_t diag_mat(dim, dim); + cmatrix_t diag_mat(1, dim); for (uint_t i=0; i &kmats, @@ -300,9 +306,11 @@ class MPS{ // The following two are helper functions for apply_multi_qubit_gate void apply_unordered_multi_qubit_gate(const reg_t &qubits, - const cmatrix_t &mat); + const cmatrix_t &mat, + bool is_diagonal=false); void apply_matrix_to_target_qubits(const reg_t &target_qubits, - const cmatrix_t &mat); + const cmatrix_t &mat, + bool is_diagonal=false); cmatrix_t density_matrix_internal(const reg_t &qubits) const; rvector_t diagonal_of_density_matrix(const reg_t &qubits) const; 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 4e784402f2..d16319db5d 100644 --- a/src/simulators/matrix_product_state/matrix_product_state_tensor.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state_tensor.hpp @@ -143,7 +143,8 @@ 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, bool swapped=false); + void apply_matrix(const cmatrix_t &mat, bool swapped=false, + bool is_diagonal=false); void apply_cnot(bool swapped = false); void apply_swap(); void apply_cz(); @@ -323,23 +324,28 @@ void MPS_Tensor::apply_tdg() data_[1] = data_[1] * complex_t(SQR_HALF, -SQR_HALF); } -void MPS_Tensor::apply_matrix(const cmatrix_t &mat, bool swapped) + void MPS_Tensor::apply_matrix(const cmatrix_t &mat, bool is_diagonal, bool swapped) { 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: Tue, 10 Nov 2020 11:14:01 -0500 Subject: [PATCH 036/126] Remove cache step from azure-pipelines windows jobs (#1029) A recent change in the disk layout of the azure pipelines windows images has moved where the pip cache is stored on disk. This breaks the cache step in the job which tries to upload from the old path to a share cache between jobs. This commit removes the cache step to unblock CI since without this all CI jobs are blocked while try to upload the local pip cache. While this will increase the run time for the job and network traffic (which means the jobs are more prone to network errors), it is still better than a non-working CI. --- azure-pipelines.yml | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index a3e0787417..1f1f7b4299 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -147,15 +147,6 @@ stages: submodules: true - powershell: Write-Host "##vso[task.prependpath]$env:CONDA\Scripts" displayName: Add conda to PATH - - task: Cache@2 - inputs: - key: 'pip | "$(Agent.OS)" | "$(python.version)" |"$(Build.BuildNumber)"' - restoreKeys: | - pip | "$(Agent.OS)" | "$(python.version)" - pip | "$(Agent.OS)" - pip - path: $(PIP_CACHE_DIR) - displayName: Cache pip - bash: | set -x set -e @@ -193,15 +184,6 @@ stages: submodules: true - powershell: Write-Host "##vso[task.prependpath]$env:CONDA\Scripts" displayName: Add conda to PATH - - task: Cache@2 - inputs: - key: 'pip | "$(Agent.OS)" | "$(python.version)" |"$(Build.BuildNumber)"' - restoreKeys: | - pip | "$(Agent.OS)" | "$(python.version)" - pip | "$(Agent.OS)" - pip - path: $(PIP_CACHE_DIR) - displayName: Cache pip - bash: | set -x set -e @@ -254,15 +236,6 @@ stages: submodules: true - powershell: Write-Host "##vso[task.prependpath]$env:CONDA\Scripts" displayName: Add conda to PATH - - task: Cache@2 - inputs: - key: 'pip | "$(Agent.OS)" | "$(python.version)" |"$(Build.BuildNumber)"' - restoreKeys: | - pip | "$(Agent.OS)" | "$(python.version)" - pip | "$(Agent.OS)" - pip - path: $(PIP_CACHE_DIR) - displayName: Cache pip - bash: | set -x set -e From 0e5f01c8aa9e96b48a5c756733d8c103eac4251f Mon Sep 17 00:00:00 2001 From: "Christopher J. Wood" Date: Tue, 10 Nov 2020 16:04:26 -0500 Subject: [PATCH 037/126] Fix opset difference (#1028) --- src/framework/opset.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/framework/opset.hpp b/src/framework/opset.hpp index ebee35304c..850b1e6bfd 100755 --- a/src/framework/opset.hpp +++ b/src/framework/opset.hpp @@ -215,7 +215,7 @@ OpSet OpSet::difference(const OpSet &_opset) const { OpSet ret; ret.optypes = difference(_opset.optypes); ret.gates = difference_gates(_opset.gates); - ret.snapshots = difference_gates(_opset.snapshots); + ret.snapshots = difference_snapshots(_opset.snapshots); return ret; } From 8ef3708c856708496dc54a1326fa6127097afab7 Mon Sep 17 00:00:00 2001 From: Victor Villar <59838221+vvilpas@users.noreply.github.com> Date: Wed, 11 Nov 2020 12:55:32 +0100 Subject: [PATCH 038/126] Fix conan dependency problem with urllib3 (#1031) urllib3 1.26.0 has been released, causing a dependency error when installing conan. Here I add urllib3 add as a dependency and cosntrainit it <1.26 to avoid this problem. --- .github/workflows/main.yml | 2 +- pyproject.toml | 2 +- requirements-dev.txt | 3 +++ setup.py | 4 ++++ 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5111b9e875..c24711f277 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -81,7 +81,7 @@ jobs: with: python-version: 3.7 - name: Install deps - run: pip install conan + run: pip install "urllib3<1.26" conan - name: Install openblas run: | set -e diff --git a/pyproject.toml b/pyproject.toml index 04b39f580f..0e00e6d818 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,2 +1,2 @@ [build-system] -requires = ["setuptools", "wheel", "conan>=1.22.2", "scikit-build", "cmake!=3.17.1,!=3.17.0", "ninja", "pybind11>2.4", "Cython>0.27.1"] +requires = ["setuptools", "wheel", "urllib3<1.26", "conan>=1.22.2", "scikit-build", "cmake!=3.17.1,!=3.17.0", "ninja", "pybind11>2.4", "Cython>0.27.1"] diff --git a/requirements-dev.txt b/requirements-dev.txt index 0b1eb58f5a..201ca40425 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -14,3 +14,6 @@ sphinx-automodapi jupyter-sphinx;python_version<'3.8' reno>=3.1.0 ddt>=1.2.0,!=1.4.0 + +# Problem with Conan and urllib3==1.26 +urllib3<1.26 diff --git a/setup.py b/setup.py index b8a2f5fee1..cf88f2b5e9 100644 --- a/setup.py +++ b/setup.py @@ -26,6 +26,9 @@ try: from conans import client except ImportError: + # Problem with Conan and urllib3 1.26 + subprocess.call([sys.executable, '-m', 'pip', 'install', 'urllib3<1.26']) + subprocess.call([sys.executable, '-m', 'pip', 'install', 'conan']) from conans import client @@ -60,6 +63,7 @@ 'cmake!=3.17,!=3.17.0', ] if not _DISABLE_CONAN: + setup_requirements.append('urllib3<1.26') setup_requirements.append('conan>=1.22.2') requirements = common_requirements + ['qiskit-terra>=0.12.0'] From 3455bf719d736e88e2d88ce7564f9ffe76ad1673 Mon Sep 17 00:00:00 2001 From: Yael Ben-Haim Date: Wed, 11 Nov 2020 16:50:11 +0200 Subject: [PATCH 039/126] Fixed the tests and the revealed bugs (#1026) Co-authored-by: Christopher J. Wood --- qiskit/providers/aer/backends/qasm_simulator.py | 2 +- .../notes/fix-basis-gates-3b5c64c3bbfee1c7.yaml | 14 ++++++++++++++ .../matrix_product_state/matrix_product_state.hpp | 13 ++++++------- .../matrix_product_state_internal.cpp | 11 ++++++----- .../matrix_product_state_tensor.hpp | 10 +++++----- .../backends/qasm_simulator/qasm_standard_gates.py | 5 +++-- 6 files changed, 35 insertions(+), 20 deletions(-) create mode 100644 releasenotes/notes/fix-basis-gates-3b5c64c3bbfee1c7.yaml diff --git a/qiskit/providers/aer/backends/qasm_simulator.py b/qiskit/providers/aer/backends/qasm_simulator.py index 071e5f15a1..e76802eb9a 100644 --- a/qiskit/providers/aer/backends/qasm_simulator.py +++ b/qiskit/providers/aer/backends/qasm_simulator.py @@ -412,7 +412,7 @@ def _method_configuration(method=None): config.basis_gates = [ 'u1', 'u2', 'u3', 'u', 'p', 'r', 'rx', 'ry', 'rz', 'id', 'x', 'y', 'z', 'h', 's', 'sdg', 'sx', 't', 'tdg', 'swap', 'cx', - 'cy', 'cz', 'csx', 'cp', 'cu1', 'cu2', 'cu3', 'rxx', 'ryy', + 'cy', 'cz', 'cp', 'cu1', 'rxx', 'ryy', 'rzz', 'rzx', 'ccx', 'unitary', 'diagonal', 'kraus', 'superop' 'roerror', 'delay', 'pauli' ] diff --git a/releasenotes/notes/fix-basis-gates-3b5c64c3bbfee1c7.yaml b/releasenotes/notes/fix-basis-gates-3b5c64c3bbfee1c7.yaml new file mode 100644 index 0000000000..4ea46d74fc --- /dev/null +++ b/releasenotes/notes/fix-basis-gates-3b5c64c3bbfee1c7.yaml @@ -0,0 +1,14 @@ +--- +fixes: + - | + Fix bug where the `"sx"`` gate :class:`~qiskit.circuit.library.SXGate` was + not listed as a supported gate in the C++ code, in `StateOpSet` of + `matrix_product_state.hp`. + - | + Fix bug where ``"csx"``, ``"cu2"``, ``"cu3"`` were incorrectly listed as + supported basis gates for the ``"density_matrix"`` method of the + :class:`~qiskit.providers.aer.QasmSimulator`. + - | + Fix bug where parameters were passed incorrectly between functions in + `matrix_product_state_internal.cpp`, causing wrong simulation, as well + as reaching invalid states, which in turn caused an infinite loop. diff --git a/src/simulators/matrix_product_state/matrix_product_state.hpp b/src/simulators/matrix_product_state/matrix_product_state.hpp index 4470772ddb..2a24361d0a 100644 --- a/src/simulators/matrix_product_state/matrix_product_state.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state.hpp @@ -52,7 +52,8 @@ const Operations::OpSet StateOpSet( Operations::OpType::kraus}, // Gates {"id", "x", "y", "z", "s", "sdg", "h", "t", "tdg", "p", "u1", - "u2", "u3", "u", "U", "CX", "cx", "cz", "cp", "cu1", "swap", "ccx"}, + "u2", "u3", "u", "U", "CX", "cx", "cz", "cp", "cu1", "swap", "ccx", + "sx"}, // Snapshots {"statevector", "memory", "register", "probabilities", "expectation_value_pauli", "expectation_value_pauli_with_variance", @@ -701,12 +702,10 @@ void State::apply_gate(const Operations::Op &op) { } } - void State::apply_matrix(const reg_t &qubits, const cmatrix_t &mat) { - if (!qubits.empty() && mat.size() > 0) { - qreg_.apply_matrix(qubits, mat); - return; - } - } +void State::apply_matrix(const reg_t &qubits, const cmatrix_t &mat) { + if (!qubits.empty() && mat.size() > 0) + qreg_.apply_matrix(qubits, mat); +} void State::apply_matrix(const reg_t &qubits, const cvector_t &vmat) { // Check if diagonal matrix 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 9c06aa22fb..7895f94bb1 100644 --- a/src/simulators/matrix_product_state/matrix_product_state_internal.cpp +++ b/src/simulators/matrix_product_state/matrix_product_state_internal.cpp @@ -384,7 +384,7 @@ void MPS::apply_swap_internal(uint_t index_A, uint_t index_B, bool swap_gate) { } // when actual_A+1 == actual_B then we can really do the swap between A and A+1 common_apply_2_qubit_gate(actual_A, Gates::swap, - cmatrix_t(1, 1) /*dummy matrix*/, false /*swapped*/); + cmatrix_t(1, 1) /*dummy matrix*/, false /*swapped*/); if (!swap_gate) { // we move the qubit at index_A one position to the right @@ -392,7 +392,7 @@ void MPS::apply_swap_internal(uint_t index_A, uint_t index_B, bool swap_gate) { //to the left std::swap(qubit_ordering_.order_[index_A], qubit_ordering_.order_[index_B]); - // update qubit locations after all the swaps + // update qubit locations after all the swaps for (uint_t i=0; i Date: Thu, 12 Nov 2020 15:57:39 +0100 Subject: [PATCH 040/126] Fix gpu wheel build (#1035) * Fix gpu wheel build There is a bug in the code that makes the verify_wheel.py script run forever when we build the gpu wheel. The problem is the check of memory available on CUDA devices when there are no CUDA devices available, as is the case for our GPU wheel build action. --- src/controllers/controller.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/controller.hpp b/src/controllers/controller.hpp index f1c8f0d85f..4d620c0f3e 100755 --- a/src/controllers/controller.hpp +++ b/src/controllers/controller.hpp @@ -391,7 +391,7 @@ size_t Controller::get_system_memory_mb() { #endif #ifdef AER_THRUST_CUDA int iDev,nDev,j; - cudaGetDeviceCount(&nDev); + if(cudaGetDeviceCount(&nDev) != cudaSuccess) nDev = 0; for(iDev=0;iDev Date: Thu, 12 Nov 2020 11:42:36 -0800 Subject: [PATCH 041/126] Switch to using native support for CUDA instead of FindCUDA macros. (#859) * Switch to using native support for CUDA instead of FindCUDA macros. * Move check for AER_THRUST_BACKEND being communicated via an environment variable to the top of the file. That is because there is a check added in this branch to see if CUDA support should be enabled. This check is needed to avoid probing for nvcc unless needed, because that check may fail and abort the build. * Add x86_64 checks for issue 856, pull #864. * Avoid compiling SIMD_SOURCE_FILE if there is not one. * Use AMD64 as a synonym for x86_64. * Add AMD64 as a synonym for x86_64. * Pull fixes from vvilpas's issue-856-build-ppc * Unconditinally use add_library even with CUDA (not cuda_add_library). * Unconditinally use add_library, not cuda_add_library for CUDA. Transform arguments for --compiler-options. * pulled from revive_CUDA_windows * no-op commit to force rebuild * note some places to refactor * Fix all but the last suggested changes by vvilpas * Still need AER_COMPILER_FLAGS initialized. * Use functions for prepending --compiler-options to pass default inherited options to NVCC. One is for when a list is prepared, and one is for when a list is not prepared. * Move include of nvcc_add_compiler_options to be adjacent to the FindCUDA call. * Likewise include nvcc_add_compiler_options inside the CUDA conditional. * Include nvcc_add_compiler_options.cmake after CMAKE environment variable assignments. * Added file. * space -> tab tweaks for local consistency * fix typo in argument name * Use an intermediate temporary variable, and an explicit set. * Remove an indirect * Follow change to remove an indirect from nvcc functions. * More quoting needed for list conversion. * More quoting needed for list conversion. * Enable gpu wheel to check that wheel building works * Do not include the whole FindCUDA, just the architecture selection bits. Assume that CUDA will be found. * force CMAKE_CUDA_COMPILER to nvcc. Trying to figure out what is wrong with qiskit-aer-gpu builds. * force CMAKE_CUDA_COMPILER to /usr/local/cuda/nvcc. Trying to figure out what is wrong with qiskit-aer-gpu builds. * remove hardcoded /usr/local/cuda/bin/nvcc in CMakeLists.txt and put a path extension in the wheels.yml workflow. * Nope, try CUDACXX instead. * Nope, try adding -- -DCMAKE_CUDA_COMPILER=/usr/local/cuda/bin/nvcc * Nope, try adding PATH in CIBW_ENVIRONMENT. * do not run verify_wheels for GPU build * return to standard file * Fix terminate call. Enable CI test * disable the CONAN patch to see if that is the cause of the build failure * reapply the CONAN patch -- there is something else wrong * add this back * Set CUDACXX for CUDA wheel build * Set AER_CUDA_ARCH to 5.2 to make a quick test on CI wheel build * Fix gpu wheel build There is a bug in the code that makes the verify_wheel.py script run forever when we build the gpu wheel. The problem is the check of memory available on CUDA devices when there are no CUDA devices available, as is the case for our GPU wheel build action. * Enable gpu wheel build temporarily to check that it works * Revert "Enable gpu wheel build temporarily to check that it works" This reverts commit 7a9b5f638cd4d6ffd1f7b28894bae2165ab994cd. * Set cuda devices to 0 in case of error for consistency * Recover cmake-optiona-conan release note * Default CUDA archs to Auto again * disable gpu build test Co-authored-by: vvilpas Co-authored-by: Victor Villar <59838221+vvilpas@users.noreply.github.com> Co-authored-by: Christopher J. Wood --- .github/workflows/wheels.yml | 2 +- CMakeLists.txt | 99 ++++++++++++------- cmake/FindPybind11.cmake | 6 +- cmake/cython_utils.cmake | 30 ++++-- cmake/nvcc_add_compiler_options.cmake | 13 +++ .../aer/backends/wrappers/CMakeLists.txt | 41 +++++--- .../statevector/qubitvector_thrust.hpp | 2 +- 7 files changed, 124 insertions(+), 69 deletions(-) create mode 100644 cmake/nvcc_add_compiler_options.cmake diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 1a877ae9e6..932f0f8249 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -82,7 +82,7 @@ jobs: CIBW_SKIP: "cp27-* cp34-* cp35-* *-manylinux_i686 pp*" CIBW_MANYLINUX_X86_64_IMAGE: "manylinux2010" CIBW_MANYLINUX_I686_IMAGE: "manylinux2010" - CIBW_ENVIRONMENT: QISKIT_AER_PACKAGE_NAME=qiskit-aer-gpu AER_THRUST_BACKEND=CUDA + CIBW_ENVIRONMENT: QISKIT_AER_PACKAGE_NAME=qiskit-aer-gpu AER_THRUST_BACKEND=CUDA CUDACXX=/usr/local/cuda/bin/nvcc CIBW_TEST_COMMAND: "python3 {project}/tools/verify_wheels.py" CIBW_TEST_REQUIRES: "git+https://github.com/Qiskit/qiskit-terra.git" run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ee47483b8..505b20c7b5 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,8 +8,10 @@ # For Mac, statically linking only happens with user libraries, system libraries cannot # be linked statically per Apple's indications. -cmake_minimum_required(VERSION 3.6) +cmake_minimum_required(VERSION 3.8 FATAL_ERROR) file(STRINGS "qiskit/providers/aer/VERSION.txt" VERSION_NUM) + +include(CheckLanguage) project(qasm_simulator VERSION ${VERSION_NUM} LANGUAGES CXX C) list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) @@ -23,6 +25,17 @@ if(NOT DEFINED AER_THRUST_BACKEND AND DEFINED ENV{AER_THRUST_BACKEND}) set(AER_THRUST_BACKEND $ENV{AER_THRUST_BACKEND}) endif() +if(AER_THRUST_BACKEND STREQUAL "CUDA") + include(nvcc_add_compiler_options) + set(CUDA_FOUND TRUE) + #include(FindCUDA) # for cuda_select_nvcc_arch_flags, CUDA_FOUND + include(FindCUDA/select_compute_arch) + enable_language(CUDA) +else() + # idiosyncrasy of CMake that it still creates a reference to this + set(CMAKE_CUDA_COMPILE_WHOLE_COMPILATION "") +endif() + # Warning: Because of a bug on CMake's FindBLAS or (it's not clear who's fault is) # libopenblas.a for Ubuntu (maybe others) we need to copy the file: @@ -222,6 +235,14 @@ if(NOT MSVC) endif() endif() +if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64" OR CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "AMD64") + if(APPLE OR UNIX) + set(SIMD_FLAGS_LIST "-mfma;-mavx2") + elseif(MSVC) + set(SIMD_FLAGS_LIST "/arch:AVX2") + endif() +endif() + set(AER_THRUST_SUPPORTED TRUE) if(AER_THRUST_SUPPORTED) if(AER_THRUST_BACKEND STREQUAL "CUDA") @@ -236,18 +257,10 @@ if(AER_THRUST_SUPPORTED) endif() endif() cuda_select_nvcc_arch_flags(AER_CUDA_ARCH_FLAGS ${AER_CUDA_ARCH}) - set(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS} -ccbin \"${CMAKE_CXX_COMPILER}\" ${AER_CUDA_ARCH_FLAGS} -DAER_THRUST_CUDA -std=c++14 -I${AER_SIMULATOR_CPP_SRC_DIR} -isystem ${AER_SIMULATOR_CPP_SRC_DIR}/third-party/headers -use_fast_math --expt-extended-lambda") - # We have to set SIMD flags globally because there seems to be a bug in FindCUDA which doesn't allow us to set per-file compilation flags. - # The implications is that users downloading the PyPi wheel package for the GPU, need to have a CPU with AVX2 support otherwise - # Aer will crash with: "Unknow instruction" exception. - # This will be fixed here: https://github.com/Qiskit/qiskit-aer/ - if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64" OR CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "AMD64") - if(APPLE OR UNIX) - set(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS}; --compiler-options;-mfma,-mavx2") - elseif(MSVC) - set(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS} /arch:AVX2") - endif() - endif() + + string(REPLACE ";" " " AER_CUDA_ARCH_FLAGS_EXPAND "${AER_CUDA_ARCH_FLAGS}") + set(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS} -ccbin \"${CMAKE_CXX_COMPILER}\" ${AER_CUDA_ARCH_FLAGS_EXPAND} -DAER_THRUST_CUDA -I${AER_SIMULATOR_CPP_SRC_DIR} -isystem ${AER_SIMULATOR_CPP_SRC_DIR}/third-party/headers -use_fast_math --expt-extended-lambda") + set(AER_COMPILER_DEFINITIONS ${AER_COMPILER_DEFINITIONS} THRUST_DEVICE_SYSTEM=THRUST_DEVICE_SYSTEM_CUDA) set(THRUST_DEPENDENT_LIBS "") elseif(AER_THRUST_BACKEND STREQUAL "TBB") @@ -294,36 +307,46 @@ if(SKBUILD) # Terra Addon build add_subdirectory(src/open_pulse) else() # Standalone build - # We build SIMD filed separately, because they will be reached only if the - # machine running the code has SIMD support if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64" OR CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "AMD64") - set(SIMD_SOURCE_FILE "${PROJECT_SOURCE_DIR}/src/simulators/statevector/qv_avx2.cpp") - if(APPLE OR UNIX) - set_source_files_properties(${SIMD_SOURCE_FILE} PROPERTIES COMPILE_FLAGS "-mfma -mavx2") - elseif(MSVC) - set_source_files_properties(${SIMD_SOURCE_FILE} PROPERTIES COMPILE_FLAGS "/arch:AVX2") - endif() - endif() - - set(AER_SIMULATOR_SOURCES "${PROJECT_SOURCE_DIR}/contrib/standalone/qasm_simulator.cpp" - "${SIMD_SOURCE_FILE}") - set_source_files_properties(${AER_SIMULATOR_SOURCES} PROPERTIES CUDA_SOURCE_PROPERTY_FORMAT OBJ) + # We build SIMD filed separately, because they will be reached only if the + # machine running the code has SIMD support + set(SIMD_SOURCE_FILE "${PROJECT_SOURCE_DIR}/src/simulators/statevector/qv_avx2.cpp") + endif() + set(AER_SIMULATOR_SOURCES "${PROJECT_SOURCE_DIR}/contrib/standalone/qasm_simulator.cpp") set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) - if(CUDA_FOUND) - cuda_add_executable(qasm_simulator ${AER_SIMULATOR_SOURCES}) + if(CUDA_FOUND AND AER_THRUST_BACKEND STREQUAL "CUDA") + set_source_files_properties(${SIMD_SOURCE_FILE} PROPERTIES LANGUAGE CUDA) + set_source_files_properties(${AER_SIMULATOR_SOURCES} PROPERTIES LANGUAGE CUDA) + set_source_files_properties(${AER_SIMULATOR_SOURCES} PROPERTIES COMPILE_FLAGS "${CUDA_NVCC_FLAGS}") + nvcc_add_compiler_options_list("${SIMD_FLAGS_LIST}" SIMD_FLAGS) + set_source_files_properties(${SIMD_SOURCE_FILE} PROPERTIES COMPILE_FLAGS "${CUDA_NVCC_FLAGS} ${SIMD_FLAGS}") + + add_executable(qasm_simulator ${AER_SIMULATOR_SOURCES} ${SIMD_SOURCE_FILE}) target_link_libraries(qasm_simulator ${AER_LIBRARIES}) - else(CUDA_FOUND) - add_executable(qasm_simulator ${AER_SIMULATOR_SOURCES}) + string(STRIP ${AER_COMPILER_FLAGS} AER_COMPILER_FLAGS_STRIPPED) + nvcc_add_compiler_options(${AER_COMPILER_FLAGS_STRIPPED} AER_COMPILER_FLAGS_OUT) + + set_target_properties(qasm_simulator PROPERTIES + LINKER_LANGUAGE CXX + CXX_STANDARD 14 + COMPILE_FLAGS ${AER_COMPILER_FLAGS_OUT} + LINK_FLAGS ${AER_LINKER_FLAGS} + RUNTIME_OUTPUT_DIRECTORY_DEBUG Debug + RUNTIME_OUTPUT_DIRECTORY_RELEASE Release) + else() + string(REPLACE ";" " " SIMD_FLAGS "${SIMD_FLAGS_LIST}") + set_source_files_properties(${SIMD_SOURCE_FILE} PROPERTIES COMPILE_FLAGS "${SIMD_FLAGS}") + add_executable(qasm_simulator ${AER_SIMULATOR_SOURCES} ${SIMD_SOURCE_FILE}) target_link_libraries(qasm_simulator PRIVATE ${AER_LIBRARIES}) - endif(CUDA_FOUND) - set_target_properties(qasm_simulator PROPERTIES - LINKER_LANGUAGE CXX - CXX_STANDARD 14 - COMPILE_FLAGS ${AER_COMPILER_FLAGS} - LINK_FLAGS ${AER_LINKER_FLAGS} - RUNTIME_OUTPUT_DIRECTORY_DEBUG Debug - RUNTIME_OUTPUT_DIRECTORY_RELEASE Release) + set_target_properties(qasm_simulator PROPERTIES + LINKER_LANGUAGE CXX + CXX_STANDARD 14 + COMPILE_FLAGS ${AER_COMPILER_FLAGS} + LINK_FLAGS ${AER_LINKER_FLAGS} + RUNTIME_OUTPUT_DIRECTORY_DEBUG Debug + RUNTIME_OUTPUT_DIRECTORY_RELEASE Release) + endif() target_include_directories(qasm_simulator PRIVATE ${AER_SIMULATOR_CPP_SRC_DIR} PRIVATE ${AER_SIMULATOR_CPP_EXTERNAL_LIBS}) diff --git a/cmake/FindPybind11.cmake b/cmake/FindPybind11.cmake index b8be02c045..60ae0be53b 100644 --- a/cmake/FindPybind11.cmake +++ b/cmake/FindPybind11.cmake @@ -40,11 +40,7 @@ function(basic_pybind11_add_module target_name) set(exclude_from_all EXCLUDE_FROM_ALL) endif() - if(CUDA_FOUND) - cuda_add_library(${target_name} ${lib_type} ${exclude_from_all} ${ARG_UNPARSED_ARGUMENTS}) - else() - add_library(${target_name} ${lib_type} ${exclude_from_all} ${ARG_UNPARSED_ARGUMENTS}) - endif() + add_library(${target_name} ${lib_type} ${exclude_from_all} ${ARG_UNPARSED_ARGUMENTS}) # This sets various properties (python include dirs) and links to python libs target_include_directories(${target_name} PRIVATE ${PYTHON_INCLUDE_DIRS}) diff --git a/cmake/cython_utils.cmake b/cmake/cython_utils.cmake index 32370ef08c..c49c8badb8 100644 --- a/cmake/cython_utils.cmake +++ b/cmake/cython_utils.cmake @@ -26,16 +26,26 @@ set(CYTHON_USER_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}) unset(CYTHON_USER_LIB_DIRS) set(CYTHON_INSTALL_DIR "qiskit/providers/aer/backends") +include(nvcc_add_compiler_options) + function(add_cython_module module) add_cython_target(${module} ${module}.pyx CXX) # Avoid warnings in cython cpp generated code if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set_source_files_properties(${module}.cxx PROPERTIES COMPILE_FLAGS -Wno-everything) + set(MODULE_COMPILE_FLAGS "-Wno-everything") elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") - set_source_files_properties(${module}.cxx PROPERTIES COMPILE_FLAGS -w) + set(MODULE_COMPILE_FLAGS "-w") elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - set_source_files_properties(${module}.cxx PROPERTIES COMPILE_FLAGS /w) + set(MODULE_COMPILE_FLAGS "/w") + endif() + + if(CUDA_FOUND AND AER_THRUST_BACKEND STREQUAL "CUDA") + string(STRIP ${MODULE_COMPILE_FLAGS} MODULE_COMPILE_FLAGS_STRIPPED) + nvcc_add_compiler_options(${MODULE_COMPILE_FLAGS_STRIPPED} MODULE_COMPILE_FLAGS_OUT) + set_source_files_properties(${module}.cxx PROPERTIES COMPILE_FLAGS ${MODULE_COMPILE_FLAGS_OUT}) + else() + set_source_files_properties(${module}.cxx PROPERTIES COMPILE_FLAGS ${MODULE_COMPILE_FLAGS}) endif() set(options MODULE SHARED EXCLUDE_FROM_ALL NO_EXTRAS SYSTEM THIN_LTO) @@ -52,13 +62,15 @@ function(add_cython_module module) set(exclude_from_all EXCLUDE_FROM_ALL) endif() - if(CUDA_FOUND) - cuda_add_library(${module} ${lib_type} ${exclude_from_all} ${module} ${ARG_UNPARSED_ARGUMENTS}) - set_source_files_properties(${module} PROPERTIES - CUDA_SOURCE_PROPERTY_FORMAT OBJ) + if(CUDA_FOUND AND AER_THRUST_BACKEND STREQUAL "CUDA") + set_source_files_properties(${module}.cxx PROPERTIES LANGUAGE CUDA) + + string(STRIP ${AER_COMPILER_FLAGS} AER_COMPILER_FLAGS_STRIPPED) + nvcc_add_compiler_options(${AER_COMPILER_FLAGS_STRIPPED} AER_COMPILER_FLAGS_OUT) else() - add_library(${module} ${lib_type} ${exclude_from_all} ${module} ${ARG_UNPARSED_ARGUMENTS}) + set(AER_COMPILER_FLAGS_OUT ${AER_COMPILER_FLAGS}) endif() + add_library(${module} ${lib_type} ${exclude_from_all} ${module} ${ARG_UNPARSED_ARGUMENTS}) # We only need to pass the linter once, as the codebase is the same for @@ -112,7 +124,7 @@ function(add_cython_module module) # Warning: Do not merge PROPERTIES when one of the variables can be empty, it breaks # the rest of the properties so they are not properly added. set_target_properties(${module} PROPERTIES LINK_FLAGS ${AER_LINKER_FLAGS}) - set_target_properties(${module} PROPERTIES COMPILE_FLAGS ${AER_COMPILER_FLAGS}) + set_target_properties(${module} PROPERTIES COMPILE_FLAGS ${AER_COMPILER_FLAGS_OUT}) target_compile_definitions(${module} PRIVATE ${AER_COMPILER_DEFINITIONS}) python_extension_module(${module} diff --git a/cmake/nvcc_add_compiler_options.cmake b/cmake/nvcc_add_compiler_options.cmake new file mode 100644 index 0000000000..c943fe4543 --- /dev/null +++ b/cmake/nvcc_add_compiler_options.cmake @@ -0,0 +1,13 @@ +function(nvcc_add_compiler_options_list inList outVarName) + set(L "${inList}") + list(TRANSFORM L PREPEND " --compiler-options ") + string(REPLACE ";" " " TMP ${L}) + set(${outVarName} ${TMP} PARENT_SCOPE) +endfunction() + +function(nvcc_add_compiler_options inStr outVarName) + string(REPLACE " " ";" L "${inStr}") + list(TRANSFORM L PREPEND " --compiler-options ") + string(REPLACE ";" " " TMP ${L}) + set(${outVarName} ${TMP} PARENT_SCOPE) +endfunction() diff --git a/qiskit/providers/aer/backends/wrappers/CMakeLists.txt b/qiskit/providers/aer/backends/wrappers/CMakeLists.txt index 355219dd24..e3cff03581 100644 --- a/qiskit/providers/aer/backends/wrappers/CMakeLists.txt +++ b/qiskit/providers/aer/backends/wrappers/CMakeLists.txt @@ -6,26 +6,37 @@ find_package(Pybind11 REQUIRED) # dependencies we can, so some of these dependencies are linked statically into our # shared library. string(REPLACE " -static " "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64" OR CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "AMD64") - # We build SIMD file separately, because they will be reached only if the - # machine running the code has SIMD support - set(SIMD_SOURCE_FILE "../../../../../src/simulators/statevector/qv_avx2.cpp") - if(APPLE OR UNIX) - set_source_files_properties(${SIMD_SOURCE_FILE} PROPERTIES COMPILE_FLAGS "-mfma -mavx2") - elseif(MSVC) - set_source_files_properties(${SIMD_SOURCE_FILE} PROPERTIES COMPILE_FLAGS "/arch:AVX2") - endif() + # We build SIMD filed separately, because they will be reached only if the + # machine running the code has SIMD support + set(SIMD_SOURCE_FILE "../../../../../src/simulators/statevector/qv_avx2.cpp") endif() -set(AER_SIMULATOR_SOURCES "bindings.cc" - "${SIMD_SOURCE_FILE}") +set(AER_SIMULATOR_SOURCES "bindings.cc" "${SIMD_SOURCE_FILE}") +basic_pybind11_add_module(controller_wrappers "${AER_SIMULATOR_SOURCES}") -if(CUDA_FOUND) - set_source_files_properties(${AER_SIMULATOR_SOURCES} PROPERTIES - CUDA_SOURCE_PROPERTY_FORMAT OBJ) -endif() +if(AER_THRUST_BACKEND STREQUAL "CUDA") + include(nvcc_add_compiler_options) + set_source_files_properties(bindings.cc PROPERTIES LANGUAGE CUDA) + set_source_files_properties(bindings.cc PROPERTIES COMPILE_FLAGS "${CUDA_NVCC_FLAGS}") -basic_pybind11_add_module(controller_wrappers ${AER_SIMULATOR_SOURCES}) + if(DEFINED SIMD_SOURCE_FILE) + set_source_files_properties(${SIMD_SOURCE_FILE} PROPERTIES LANGUAGE CUDA) + nvcc_add_compiler_options_list("${SIMD_FLAGS_LIST}" SIMD_FLAGS_OUT) + set_source_files_properties(${SIMD_SOURCE_FILE} PROPERTIES COMPILE_FLAGS "${CUDA_NVCC_FLAGS} ${SIMD_FLAGS_OUT}") + endif() + + string(STRIP ${AER_COMPILER_FLAGS} AER_COMPILER_FLAGS_STRIPPED) + nvcc_add_compiler_options(${AER_COMPILER_FLAGS_STRIPPED} AER_COMPILER_FLAGS_OUT) + set_target_properties(controller_wrappers PROPERTIES COMPILE_FLAGS "${AER_COMPILER_FLAGS_OUT}") +else() + if(DEFINED SIMD_SOURCE_FILE) + string(REPLACE ";" " " SIMD_FLAGS "${SIMD_FLAGS_LIST}") + set_source_files_properties(${SIMD_SOURCE_FILE} PROPERTIES COMPILE_FLAGS "${SIMD_FLAGS}") + endif() + set_target_properties(controller_wrappers PROPERTIES COMPILE_FLAGS "${AER_COMPILER_FLAGS}") +endif() target_include_directories(controller_wrappers PRIVATE ${AER_SIMULATOR_CPP_SRC_DIR} PRIVATE ${AER_SIMULATOR_CPP_EXTERNAL_LIBS}) target_link_libraries(controller_wrappers ${AER_LIBRARIES}) diff --git a/src/simulators/statevector/qubitvector_thrust.hpp b/src/simulators/statevector/qubitvector_thrust.hpp index 89bf1edfd6..110b852825 100644 --- a/src/simulators/statevector/qubitvector_thrust.hpp +++ b/src/simulators/statevector/qubitvector_thrust.hpp @@ -1682,7 +1682,7 @@ void QubitVectorThrust::set_num_qubits(size_t num_qubits) tid = omp_get_thread_num(); m_nDev = 1; #ifdef AER_THRUST_CUDA - cudaGetDeviceCount(&m_nDev); + if(cudaGetDeviceCount(&m_nDev) != cudaSuccess) m_nDev = 0; #endif m_iDev = 0; From e1ee79f7ab0f0da6a9adb6023a3fcae1e2b84e46 Mon Sep 17 00:00:00 2001 From: Victor Villar Date: Mon, 16 Nov 2020 14:18:06 +0100 Subject: [PATCH 042/126] Fix tests due to bad input to assemble function (#1039) In Qiskit/qiskit-terra#5298 a bug was fixed to ensure that a singe entry list passed to `transpile()` would always return a list instead of just a circuit object. However, in the aer tests there were a couple of places that were building a list assuming transpile would return a bare circuit object. When the terra fix merged changing the return type the tests started to fail because the input to the `assemble()` function was now a list of a list of circuits instead of the intend list of circuits. This commit fixes this issue so it works with the corrected terra behavior. --- test/terra/backends/qasm_simulator/qasm_fusion.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/terra/backends/qasm_simulator/qasm_fusion.py b/test/terra/backends/qasm_simulator/qasm_fusion.py index a10f4947ce..b5d54ea4b5 100644 --- a/test/terra/backends/qasm_simulator/qasm_fusion.py +++ b/test/terra/backends/qasm_simulator/qasm_fusion.py @@ -188,7 +188,7 @@ def test_kraus_noise_fusion(self): backend=self.SIMULATOR, basis_gates=noise_model.basis_gates, optimization_level=0) - qobj = assemble([circuit], + qobj = assemble(circuit, self.SIMULATOR, shots=shots, seed_simulator=1) @@ -217,7 +217,7 @@ def test_non_kraus_noise_fusion(self): backend=self.SIMULATOR, basis_gates=noise_model.basis_gates, optimization_level=0) - qobj = assemble([circuit], + qobj = assemble(circuit, self.SIMULATOR, shots=shots, seed_simulator=1) From d4b553fabd986a589343c092a2661bf3583bc67d Mon Sep 17 00:00:00 2001 From: Padraic Calpin Date: Mon, 16 Nov 2020 17:23:17 +0100 Subject: [PATCH 043/126] Fix for Issue #306 in Extended Stabilizer Simulator (#677) Co-authored-by: Victor Villar --- .../providers/aer/backends/qasm_simulator.py | 50 +++- ...izer_norm_estimation-d17632efe8d2bb19.yaml | 39 ++++ src/controllers/qasm_controller.hpp | 12 - .../extended_stabilizer/ch_runner.hpp | 196 ++++++++++++---- .../chlib/chstabilizer.hpp | 9 +- .../extended_stabilizer/chlib/core.hpp | 103 ++++---- .../extended_stabilizer_state.hpp | 221 +++++++++++++----- src/simulators/extended_stabilizer/gates.hpp | 43 ++-- ...test_qasm_simulator_extended_stabilizer.py | 61 ++++- 9 files changed, 509 insertions(+), 225 deletions(-) create mode 100644 releasenotes/notes/extended_stabilizer_norm_estimation-d17632efe8d2bb19.yaml diff --git a/qiskit/providers/aer/backends/qasm_simulator.py b/qiskit/providers/aer/backends/qasm_simulator.py index e76802eb9a..fbe687794f 100644 --- a/qiskit/providers/aer/backends/qasm_simulator.py +++ b/qiskit/providers/aer/backends/qasm_simulator.py @@ -181,14 +181,32 @@ class QasmSimulator(AerBackend): These backend options only apply when using the ``"extended_stabilizer"`` simulation method: - * ``extended_stabilizer_measure_sampling`` (bool): Enable measure - sampling optimization on supported circuits. This prevents the - simulator from re-running the measure monte-carlo step for each - shot. Enabling measure sampling may reduce accuracy of the - measurement counts if the output distribution is strongly - peaked (Default: False). - - * ``extended_stabilizer_mixing_time`` (int): Set how long the + * ``extended_stabilizer_sampling_methid`` (string): Choose how to simulate + measurements on qubits. The performance of the simulator depends + significantly on this choice. In the following, let n be the number of + qubits in the circuit, m the number of qubits measured, and S be the + number of shots. (Default: resampled_metropolis) + + * ``"metropolis"``: Use a Monte-Carlo method to sample many output + strings from the simulator at once. To be accurate, this method + requires that all the possible output strings have a non-zero + probability. It will give inaccurate results on cases where + the circuit has many zero-probability outcomes. + This method has an overall runtime that scales as n^{2} + (S-1)n. + + * ``"resampled_metropolis"``: A variant of the metropolis method, + where the Monte-Carlo method is reinitialised for every shot. This + gives better results for circuits where some outcomes have zero + probability, but will still fail if the output distribution + is sparse. The overall runtime scales as Sn^{2}. + + * ``"norm_estimation"``: An alternative sampling method using + random state inner products to estimate outcome probabilites. This + method requires twice as much memory, and significantly longer + runtimes, but gives accurate results on circuits with sparse + output distributions. The overall runtime scales as Sn^{3}m^{3}. + + * ``extended_stabilizer_metropolis_mixing_time`` (int): Set how long the monte-carlo method runs before performing measurements. If the output distribution is strongly peaked, this can be decreased alongside setting extended_stabilizer_disable_measurement_opt @@ -199,9 +217,14 @@ class QasmSimulator(AerBackend): smaller error needs more memory and computational time (Default: 0.05). - * ``extended_stabilizer_norm_estimation_samples`` (int): Number of - samples used to compute the correct normalization for a - statevector snapshot (Default: 100). + * ``extended_stabilizer_norm_estimation_samples`` (int): The default number + of samples for the norm estimation sampler. The method will use the + default, or 4m^{2} samples where m is the number of qubits to be + measured, whichever is larger (Default: 100). + + * ``extended_stabilizer_norm_estimation_repetitions`` (int): The number + of times to repeat the norm estimation. The median of these reptitions + is used to estimate and sample output strings (Default: 3). * ``extended_stabilizer_parallel_threshold`` (int): Set the minimum size of the extended stabilizer decomposition before we enable @@ -209,6 +232,11 @@ class QasmSimulator(AerBackend): is enabled this will only use unallocated CPU cores up to max_parallel_threads (Default: 100). + * ``extended_stabilizer_probabilities_snapshot_samples`` (int): If using + the metropolis or resampled_metropolis sampling method, set the number of + samples used to estimate probabilities in a probabilities snapshot + (Default: 3000). + These backend options only apply when using the ``"matrix_product_state"`` simulation method: diff --git a/releasenotes/notes/extended_stabilizer_norm_estimation-d17632efe8d2bb19.yaml b/releasenotes/notes/extended_stabilizer_norm_estimation-d17632efe8d2bb19.yaml new file mode 100644 index 0000000000..1a8851c2dd --- /dev/null +++ b/releasenotes/notes/extended_stabilizer_norm_estimation-d17632efe8d2bb19.yaml @@ -0,0 +1,39 @@ +--- +features: + - | + Introduce a new method for performing measurements with the Extended + Stabilizer simulator, called Norm Estimation. This method can be used by passing + the following options to the ``QasmSimulator`` provider:: + + simulator = QasmSimulator( + method='extended_stabilizer, + extended_stabilizer_sampling_method="norm_estimation" + ) + + The norm estimation method is slower than the alternative `metropolis` + or `resampled_metropolis` options, but gives better performance on circuits + with sparse output distributions. See the documentation of the ``QasmSimulator`` + provider for more information. +fixes: + - | + Fixes an issue where the Extended Stabilizer simulator would give incorrect + results on quantum circuits with sparse output distributions. Refer to + `#306 ` for more information + and examples. +upgrade: + - | + The following options for the Extended Stabilizer simulator have changed. + + + ``extended_stabilizer_measure_sampling``: This option has been replaced + by the options ``extended_stabilizer_sampling_method``, which controls + how we simulate qubit measurement. + + + ``extended_stabilizer_mixing_time``: This option has been renamed as + ``extended_stabilizer_metropolis_mixing_time`` to clarify it only applies + to the `metropolis` and `resampled_metropolis` sampling methods. + + + ``extended_stabilizer_norm_estimation_samples``: This option has been renamed + to ``extended_stabilizer_norm_estimation_default_samples``. + + One additional option, ``extended_stabilizer_norm_estimation_repetitions`` has been + added, whih controls part of the behaviour of the norm estimation sampling method. diff --git a/src/controllers/qasm_controller.hpp b/src/controllers/qasm_controller.hpp index 06251d9ade..c282baf6fc 100755 --- a/src/controllers/qasm_controller.hpp +++ b/src/controllers/qasm_controller.hpp @@ -291,8 +291,6 @@ class QasmController : public Base::Controller { // TODO: initial stabilizer state - // Controller-level parameter for CH method - bool extended_stabilizer_measure_sampling_ = false; }; //========================================================================= @@ -344,10 +342,6 @@ void QasmController::set_config(const json_t& config) { } } - // Check for extended stabilizer measure sampling - JSON::get_value(extended_stabilizer_measure_sampling_, - "extended_stabilizer_measure_sampling", config); - // DEPRECATED: Add custom initial state if (JSON::get_value(initial_statevector_, "initial_statevector", config)) { // Raise error if method is set to stabilizer or ch @@ -1028,12 +1022,6 @@ bool QasmController::check_measure_sampling_opt(const Circuit& circ, return false; } - // Check if stabilizer measure sampling has been disabled - if (method == Method::extended_stabilizer && - !extended_stabilizer_measure_sampling_) { - return false; - } - // Check if non-density matrix simulation and circuit contains // a stochastic instruction before measurement // ie. initialize, reset, kraus, superop, conditional diff --git a/src/simulators/extended_stabilizer/ch_runner.hpp b/src/simulators/extended_stabilizer/ch_runner.hpp index addc8f138d..67a9ba3a1b 100644 --- a/src/simulators/extended_stabilizer/ch_runner.hpp +++ b/src/simulators/extended_stabilizer/ch_runner.hpp @@ -26,9 +26,11 @@ #define _USE_MATH_DEFINES -#include +#include +#include #include +#include #include #include @@ -53,8 +55,8 @@ thread_local std::unordered_map Z_ROTATIONS; class Runner { private: - uint_t n_qubits_; - uint_t num_states_; + uint_t n_qubits_ = 0; + uint_t num_states_ = 0; std::vector states_; std::vector coefficients_; uint_t num_threads_; @@ -118,22 +120,29 @@ class Runner void apply_ccz(uint_t control_1, uint_t control_2, uint_t target, uint_t branch, int rank); //Measure a Pauli projector on each term in the decomposition and update their coefficients // omega. + void apply_pauli(pauli_t &P); void apply_pauli_projector(const std::vector &generators); void apply_pauli_projector(const std::vector &generators, uint_t rank); //Routine for Norm Estimation, thin wrapper for the CHSimulator method that uses AER::RngEngine //to set up the estimation routine. - double norm_estimation(uint_t n_samples, AER::RngEngine &rng); - double norm_estimation(uint_t n_samples, std::vector generators, AER::RngEngine &rng); + double norm_estimation(uint_t n_samples, uint_t n_repetitions, AER::RngEngine &rng); + double norm_estimation(uint_t n_samples, uint_t n_repetitions, std::vector generators, AER::RngEngine &rng); //Metropolis Estimation for sampling from the output distribution uint_t metropolis_estimation(uint_t n_steps, AER::RngEngine &rng); std::vector metropolis_estimation(uint_t n_steps, uint_t n_shots, AER::RngEngine &rng); + // NE Sampling Routines + uint_t ne_single_sample(uint_t default_samples, uint_t repetitions, bool preserve_states, + const AER::reg_t &qubits, AER::RngEngine &rng); + + std::vector ne_probabilities(uint_t default_samples, uint_t repetitions, + const AER::reg_t &qubits, AER::RngEngine &rng); //Efficient Sampler for the output distribution of a stabilizer state uint_t stabilizer_sampler(AER::RngEngine &rng); std::vector stabilizer_sampler(uint_t n_shots, AER::RngEngine &rng); //Utilities for the state-vector snapshot. complex_t amplitude(uint_t x_measure); - void state_vector(std::vector &svector, AER::RngEngine &rng); + void state_vector(std::vector &svector, uint_t default_samples, uint_t repetitions, AER::RngEngine &rng); }; @@ -202,6 +211,16 @@ bool Runner::check_omp_threshold() // Operations on the decomposition //------------------------------------------------------------------------- +void Runner::apply_pauli(pauli_t &P) +{ + const int_t END = num_states_; + #pragma omp parallel for if (num_states_ > omp_threshold_ && num_threads_ > 1) num_threads(num_threads_) + for(int_t i=0; i &generators) { const int_t END = num_states_; @@ -416,47 +435,139 @@ void Runner::apply_ccz(uint_t control_1, uint_t control_2, uint_t target, uint_t //Measurement //------------------------------------------------------------------------- -double Runner::norm_estimation(uint_t n_samples, AER::RngEngine &rng) +double Runner::norm_estimation(uint_t n_samples, uint_t repetitions, AER::RngEngine &rng) { - std::vector adiag_1(n_samples, 0ULL); - std::vector adiag_2(n_samples, 0ULL); - std::vector< std::vector > a(n_samples, std::vector(n_qubits_, 0ULL)); + const int_t NSAMPLES = n_samples; const int_t NQUBITS = n_qubits_; - #pragma omp parallel if (num_threads_ > 1) num_threads(num_threads_) - { - #ifdef _WIN32 - #pragma omp for - #else - #pragma omp for collapse(2) - #endif - for (int_t l=0; l xi_samples(repetitions, 0.); + for(uint_t m=0; m < repetitions; m++) { - for (int_t i=0; i adiag_1(n_samples, 0ULL); + std::vector adiag_2(n_samples, 0ULL); + std::vector< std::vector > a(n_samples, std::vector(n_qubits_, 0ULL)); + #pragma omp parallel if (num_threads_ > 1) num_threads(num_threads_) { - for (int_t j=i; j generators, AER::RngEngine &rng) +double Runner::norm_estimation(uint_t n_samples, uint_t repetitions, std::vector generators, AER::RngEngine &rng) { apply_pauli_projector(generators); - return norm_estimation(n_samples, rng); + return norm_estimation(n_samples, repetitions, rng); +} + +uint_t Runner::ne_single_sample(uint_t default_samples, + uint_t repetitions, + bool preserve_states, + const AER::reg_t &qubits, + AER::RngEngine &rng) +{ + uint_t n_samples = std::llrint(4 * std::pow(qubits.size(), 2)); + if (default_samples > n_samples) + { + n_samples = default_samples; + } + double denominator = norm_estimation(n_samples, repetitions, rng); + std::vector generators; + std::vector states_cache(states_); + uint_t out_string = ZERO; + for (uint_t i=0; i Runner::ne_probabilities(uint_t default_samples, uint_t repetitions, + const AER::reg_t &qubits, AER::RngEngine &rng) +{ + uint_t n_probs = 1ULL << qubits.size(); + std::vector probs(n_probs, 0.); + std::vector states_cache(states_); + std::vector generators; + for (uint_t i=0; i> j) & 1ULL) { + generators[j].e = 2; + } + else + { + generators[j].e = 0; + } + } + double p_estimate = norm_estimation(default_samples, repetitions, generators, rng); + probs[i] = p_estimate / norm; + states_ = states_cache; + } + return probs; } uint_t Runner::metropolis_estimation(uint_t n_steps, AER::RngEngine &rng) @@ -483,7 +594,7 @@ std::vector Runner::metropolis_estimation(uint_t n_steps, uint_t n_shots void Runner::init_metropolis(AER::RngEngine &rng) { - accept_ = 0; + accept_ = false; //Random initial x_string from RngEngine uint_t max = (1ULL< &svector, AER::RngEngine &rng) +void Runner::state_vector(std::vector &svector, uint_t default_samples, uint_t repetitions, AER::RngEngine &rng) { uint_t ceil = 1ULL << n_qubits_; + uint_t n_samples = std::llrint(0.5 * std::pow(n_qubits_, 2)); + if (n_samples < default_samples) + { + n_samples = default_samples; + } if (!svector.empty()) { svector.clear(); @@ -620,7 +736,7 @@ void Runner::state_vector(std::vector &svector, AER::RngEngine &rng) double norm = 1; if(num_states_ > 1) { - norm = norm_estimation(40, rng); + norm = norm_estimation(n_samples, repetitions, rng); } for(uint_t i=0; i +#include +#include #include #include #include @@ -169,16 +170,12 @@ class StabilizerState }; -typedef std::complex cdouble; +using cdouble = std::complex; //-------------------------------// // Implementation // //-------------------------------// -//Lookup table for e^(i pi m / 4) -static const int RE_PHASE[8] = {1, 1, 0, -1, -1, -1, 0, 1}; -static const int IM_PHASE[8] = {0, 1, 1, 1, 0, -1, -1, -1}; - // Clifford simulator based on the CH-form for for n<=64 qubits StabilizerState::StabilizerState(const unsigned n_qubits): diff --git a/src/simulators/extended_stabilizer/chlib/core.hpp b/src/simulators/extended_stabilizer/chlib/core.hpp index 7ef1b3840e..45262aa5a8 100644 --- a/src/simulators/extended_stabilizer/chlib/core.hpp +++ b/src/simulators/extended_stabilizer/chlib/core.hpp @@ -15,51 +15,40 @@ #ifndef CORE_HPP #define CORE_HPP -#include -#include -#include +#include +#include +#include #include #include #include -static const int RE_PHASE[8] = {1, 1, 0, -1, -1, -1, 0, 1}; -static const int IM_PHASE[8] = {0, 1, 1, 1, 0, -1, -1, -1}; namespace CHSimulator { - + +static const std::array RE_PHASE = {1, 1, 0, -1, -1, -1, 0, 1}; +static const std::array IM_PHASE = {0, 1, 1, 1, 0, -1, -1, -1}; + using complex_t = std::complex; using uint_t = uint_fast64_t; using int_t = int_fast64_t; -// Definitions for implementing arbitrary binary vectors and matrices as arrays of 64bit integers -typedef uint_fast64_t word; -// typedef unsigned long word; -#define WORD_BITS (CHAR_BIT * sizeof(word)) -// Calculate which integer in the array we are looking at -#define WORD_INDEX(INDEX) ((INDEX) / (WORD_BITS)) -// Calculate the shift we need to read, set or clear that bit -#define WORD_SHIFT(INDEX) ((INDEX) % WORD_BITS) - -extern const word zer = 0U; -extern const word one = 1U; -extern bool (*hamming_parity)(word); -extern unsigned (*hamming_weight)(word); +extern const uint_t zer = 0U; +extern const uint_t one = 1U; +extern bool (*hamming_parity)(uint_t); +extern unsigned (*hamming_weight)(uint_t); struct scalar_t { // complex numbers of the form eps * 2^{p/2} * exp(i (pi/4)*e ) // eps=0,1 p=integer e=0,1,...,7 // if eps=0 then p and e are arbitrary - int eps; - int p; - int e; + int eps = 1; + int p = 0; + int e = 0; // constructor makes number 1 - scalar_t(): eps(1), p(0), e(0) {}; - scalar_t(const scalar_t& rhs): eps(rhs.eps), p(rhs.p), e(rhs.e) {}; - scalar_t(const std::complex coeff): - eps(1), - p(0), - e(0) + scalar_t() = default; + scalar_t(const scalar_t& rhs) = default; + scalar_t(const std::complex coeff) { double abs_val = std::abs(coeff); if(std::abs(abs_val-0.)<1e-8) @@ -124,11 +113,11 @@ struct scalar_t { scalar_t& operator*=(const scalar_t& rhs); scalar_t operator*(const scalar_t& rhs) const; - std::complex to_complex() const + std::complex to_complex() const { if (eps==0) { - return std::complex(0., 0.); + return {0., 0.}; } std::complex mag(std::pow(2, p/(double)2), 0.); std::complex phase(RE_PHASE[e], IM_PHASE[e]); @@ -147,11 +136,11 @@ struct pauli_t { // n-qubit Pauli operators: i^e * X(x) * Z(z) uint_fast64_t X; // n-bit string uint_fast64_t Z; // n-bit string - unsigned e; // takes values 0,1,2,3 + unsigned e = 0; // takes values 0,1,2,3 // constructor makes the identity Pauli operator pauli_t(); - pauli_t(const pauli_t& p): X(p.X), Z(p.Z), e(p.e) {}; + pauli_t(const pauli_t& p) = default; // multiplication of Pauli operators pauli_t& operator*=( const pauli_t& rhs ); @@ -191,59 +180,59 @@ void Print(std::vector A, unsigned n);// print a binary matrix #endif #define INTRINSIC_PARITY 1 #include - inline bool _msc_parity(word x) + inline bool _msc_parity(uint_t x) { return (POPCNT(x) & one); } - bool (*hamming_parity) (word) = &_msc_parity; - inline unsigned _msc_weight(word x) + bool (*hamming_parity) (uint_t) = &_msc_parity; + inline unsigned _msc_weight(uint_t x) { return (POPCNT(x)); } - unsigned (*hamming_weight) (word)= &_msc_weight; + unsigned (*hamming_weight) (uint_t)= &_msc_weight; #endif #ifdef __GNUC__ #define INTRINSIC_PARITY 1 - inline bool _gcc_parity(word x) + inline bool _gcc_parity(uint_t x) { return (__builtin_popcountll(x) & one); } - bool (*hamming_parity) (word) = &_gcc_parity; - inline unsigned _gcc_weight(word x) + bool (*hamming_parity) (uint_t) = &_gcc_parity; + inline unsigned _gcc_weight(uint_t x) { return (__builtin_popcountll(x)); } - unsigned (*hamming_weight) (word)= &_gcc_weight; + unsigned (*hamming_weight) (uint_t)= &_gcc_weight; #endif #ifdef _CLANG_ #if __has__builtin(__builtin_popcount) #define INTRINSIC_PARITY 1 - inline bool _clang_parity(word x) + inline bool _clang_parity(uint_t x) { return (__builtin_popcountll(x) & one); } - bool (*hamming_parity) (word) = &_clang_parity; - inline unsigned _clang_weight(word x) + bool (*hamming_parity) (uint_t) = &_clang_parity; + inline unsigned _clang_weight(uint_t x) { return (__builtin_popcountll(x)); } - unsigned (*hamming_weight) (word) = &_clang_weight; + unsigned (*hamming_weight) (uint_t) = &_clang_weight; #endif #endif #ifndef INTRINSIC_PARITY // Implementation from http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan - bool _naive_parity(word x) + bool _naive_parity(uint_t x) { - word c; // c accumulates the total bits set in x + uint_t c; // c accumulates the total bits set in x for (c = 0; x; c++) { x &= (x - 1); // clear the least significant bit set } return (c&one); } - unsigned _naive_weight(word x) + unsigned _naive_weight(uint_t x) { - word c; // c accumulates the total bits set in x + uint_t c; // c accumulates the total bits set in x for (c = 0; x; c++) { x &= (x - 1); // clear the least significant bit set @@ -251,8 +240,8 @@ void Print(std::vector A, unsigned n);// print a binary matrix return c; } - bool (*hamming_parity) (word) = &_naive_parity; - unsigned (*hamming_weight) (word) = &_naive_weight; + bool (*hamming_parity) (uint_t) = &_naive_parity; + unsigned (*hamming_weight) (uint_t) = &_naive_weight; #endif scalar_t& scalar_t::operator*=(const scalar_t& rhs) @@ -274,7 +263,7 @@ scalar_t scalar_t::operator*(const scalar_t& rhs) const return out; } -pauli_t::pauli_t(): X(zer), Z(zer), e(0) {} +pauli_t::pauli_t(): X(zer), Z(zer) {} pauli_t& pauli_t::operator*=( const pauli_t& rhs ) { @@ -401,12 +390,12 @@ scalar_t QuadraticForm::ExponentialSum() // sigma=0,1 // if Z=0 then pow2,sigma contain junk and isZero=1 int pow2_real=0; - bool sigma_real=0; - bool isZero_real=0; + bool sigma_real=false; + bool isZero_real=false; int pow2_imag=0; - bool sigma_imag=0; - bool isZero_imag=0; + bool sigma_imag=false; + bool isZero_imag=false; scalar_t amp; amp.makeOne(); @@ -475,12 +464,12 @@ scalar_t QuadraticForm::ExponentialSum() { // the form is linear in the variable i1 if (L1real) - isZero_real=1; + isZero_real=true; pow2_real++; if (L1imag) - isZero_imag=1; + isZero_imag=true; pow2_imag++; diff --git a/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp b/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp index 8df8727f98..646b4fcedb 100644 --- a/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp +++ b/src/simulators/extended_stabilizer/extended_stabilizer_state.hpp @@ -51,10 +51,14 @@ using Gates = CHSimulator::Gates; uint_t zero = 0ULL; uint_t toff_branch_max = 7ULL; +enum class SamplingMethod { + metropolis, + resampled_metropolis, + norm_estimation +}; + enum class Snapshots { - state, statevector, - probabilities, cmemory, cregister, probs @@ -68,7 +72,7 @@ class State: public Base::State State() : BaseState(StateOpSet) {} virtual ~State() = default; - virtual std::string name() const override {return "extended_stabilizer";} + std::string name() const override {return "extended_stabilizer";} //Apply a sequence of operations to the cicuit. For each operation, //we loop over the terms in the decomposition in parallel @@ -77,17 +81,17 @@ class State: public Base::State RngEngine &rng, bool final_ops = false) override; - virtual void initialize_qreg(uint_t num_qubits) override; + void initialize_qreg(uint_t num_qubits) override; - virtual void initialize_qreg(uint_t num_qubits, const chstate_t &state) override; + void initialize_qreg(uint_t num_qubits, const chstate_t &state) override; - virtual size_t required_memory_mb(uint_t num_qubits, + size_t required_memory_mb(uint_t num_qubits, const std::vector &ops) const override; - virtual void set_config(const json_t &config) override; + void set_config(const json_t &config) override; - virtual std::vector sample_measure(const reg_t& qubits, + std::vector sample_measure(const reg_t& qubits, uint_t shots, RngEngine &rng) override; @@ -125,13 +129,10 @@ class State: public Base::State // projectors Id+Z_{i} for each qubit i void apply_reset(const reg_t &qubits, AER::RngEngine &rng); - //Take a snapshot of the simulation state - //TODO: Improve the CHSimulator::to_json method. void apply_snapshot(const Operations::Op &op, ExperimentResult &result, RngEngine &rng); //Convert a decomposition to a state-vector void statevector_snapshot(const Operations::Op &op, ExperimentResult &result, RngEngine &rng); - //Compute probabilities from a stabilizer rank decomposition - //TODO: Check ordering/output format... + // //Compute probabilities from a stabilizer rank decomposition void probabilities_snapshot(const Operations::Op &op, ExperimentResult &result, RngEngine &rng); const static stringmap_t gateset_; @@ -147,6 +148,9 @@ class State: public Base::State double approximation_error_ = 0.05; uint_t norm_estimation_samples_ = 100; + + uint_t norm_estimation_repetitions_ = 3; + // How long the metropolis algorithm runs before // we consider it to be well mixed and sample form the // output distribution @@ -157,7 +161,9 @@ class State: public Base::State double snapshot_chop_threshold_ = 1e-10; - double probabilities_snapshot_samples_ = 3000.; + uint_t probabilities_snapshot_samples_ = 3000; + + SamplingMethod sampling_method_ = SamplingMethod::resampled_metropolis; // Compute the required stabilizer rank of the circuit uint_t compute_chi(const std::vector &ops) const; @@ -206,9 +212,8 @@ const stringmap_t State::gateset_({ }); const stringmap_t State::snapshotset_({ - {"state", Snapshots::state}, {"statevector", Snapshots::statevector}, - {"probabilities", Snapshots::probabilities}, + {"probabilities", Snapshots::probs}, {"memory", Snapshots::cmemory}, {"register", Snapshots::cregister} }); @@ -238,16 +243,39 @@ void State::set_config(const json_t &config) // Set the error upper bound in the stabilizer rank approximation JSON::get_value(approximation_error_, "extended_stabilizer_approximation_error", config); // Set the number of samples used in the norm estimation routine - JSON::get_value(norm_estimation_samples_, "extended_stabilizer_norm_estimation_samples", config); + JSON::get_value(norm_estimation_samples_, "extended_stabilizer_norm_estimation_default_samples", config); + // Set the desired number of repetitions of the norm estimation step. If not explicitly set, we + // compute a default basd on the approximation error + norm_estimation_repetitions_ = std::llrint(std::log2(1. / approximation_error_)); + JSON::get_value(norm_estimation_repetitions_, "extended_stabilizer_norm_estimation_repetitions", config); // Set the number of steps used in the metropolis sampler before we // consider the distribution as approximating the output - JSON::get_value(metropolis_mixing_steps_, "extended_stabilizer_mixing_time", config); + JSON::get_value(metropolis_mixing_steps_, "extended_stabilizer_metropolis_mixing_time", config); //Set the threshold of the decomposition before we use omp JSON::get_value(omp_threshold_rank_, "extended_stabilizer_parallel_threshold", config); //Set the truncation threshold for the probabilities snapshot. JSON::get_value(snapshot_chop_threshold_, "zero_threshold", config); //Set the number of samples for the probabilities snapshot - JSON::get_value(probabilities_snapshot_samples_, "probabilities_snapshot_samples", config); + JSON::get_value(probabilities_snapshot_samples_, "extended_stabilizer_probabilities_snapshot_samples", config); + //Set the measurement strategy + std::string sampling_method_str = "resampled_metropolis"; + JSON::get_value(sampling_method_str, "extended_stabilizer_sampling_method", config); + if (sampling_method_str == "metropolis") { + sampling_method_ = SamplingMethod::metropolis; + } + else if (sampling_method_str == "resampled_metropolis") + { + sampling_method_ = SamplingMethod::resampled_metropolis; + } + else if (sampling_method_str == "norm_estimation") { + sampling_method_ = SamplingMethod::norm_estimation; + } + else { + throw std::runtime_error( + std::string("Unrecognised sampling method ") + sampling_method_str + + std::string("for the extended stabilizer simulator.") + ); + } } std::pair State::decomposition_parameters(const std::vector &ops) @@ -386,8 +414,8 @@ void State::apply_ops(const std::vector &ops, ExperimentResult & } std::vector State::sample_measure(const reg_t& qubits, - uint_t shots, - RngEngine &rng) + uint_t shots, + RngEngine &rng) { std::vector output_samples; if(BaseState::qreg_.get_num_states() == 1) @@ -396,7 +424,30 @@ std::vector State::sample_measure(const reg_t& qubits, } else { - output_samples = BaseState::qreg_.metropolis_estimation(metropolis_mixing_steps_, shots, rng); + if (sampling_method_ == SamplingMethod::metropolis) + { + output_samples = BaseState::qreg_.metropolis_estimation(metropolis_mixing_steps_, shots, rng); + } + else if (sampling_method_ == SamplingMethod::resampled_metropolis) + { + output_samples.reserve(shots); + for (uint_t i=0; i all_samples; all_samples.reserve(shots); @@ -489,36 +540,61 @@ void State::apply_stabilizer_circuit(const std::vector &ops, void State::apply_measure(const reg_t &qubits, const reg_t &cmemory, const reg_t &cregister, RngEngine &rng) { - uint_t full_string; + uint_t out_string; + // Flag if the Pauli projector is applied already as part of the sampling + bool do_projector_correction = true; + // Prepare an output register for the qubits we are measurig + reg_t outcome(qubits.size(), 0ULL); if(BaseState::qreg_.get_num_states() == 1) { //For a single state, we use the efficient sampler defined in Sec IV.A ofarxiv:1808.00128 - full_string = BaseState::qreg_.stabilizer_sampler(rng); + out_string = BaseState::qreg_.stabilizer_sampler(rng); } else { - //We use the metropolis algorithm to sample an output string non-destructively - full_string = BaseState::qreg_.metropolis_estimation(metropolis_mixing_steps_, rng); + if (sampling_method_ == SamplingMethod::norm_estimation) + { + do_projector_correction = false; + //Run the norm estimation routine + out_string = BaseState::qreg_.ne_single_sample( + norm_estimation_samples_, norm_estimation_repetitions_, false, qubits, rng + ); + } + else + { + // We use the metropolis algorithm to sample an output string non-destructively + // This is a single measure step so we do the same for metropolis or resampled_metropolis + out_string = BaseState::qreg_.metropolis_estimation(metropolis_mixing_steps_, rng); + } + } + if (do_projector_correction) + { + //We prepare the Pauli projector corresponding to the measurement result + std::vectorpaulis(qubits.size(), chpauli_t()); + for (uint_t i=0; i> qubits[i]) & 1ULL) + { + //Additionally, store the output bit for this qubit + paulis[i].e = 2; + } + } + //Project the decomposition onto the measurement outcome + BaseState::qreg_.apply_pauli_projector(paulis); } - //We prepare the Pauli projector corresponding to the measurement result - std::vectorpaulis(qubits.size(), chpauli_t()); - // Prepare an output register for the qubits we are measurig - reg_t outcome(qubits.size(), 0ULL); for (uint_t i=0; i> qubits[i]) & 1ULL) + if ((out_string >> qubits[i]) & 1ULL) { //Additionally, store the output bit for this qubit - outcome[i]= 1ULL; - paulis[i].e = 2; + outcome[i] = 1ULL; } } // Convert the output string to a reg_t. and store BaseState::creg_.store_measure(outcome, cmemory, cregister); - //Project the decomposition onto the measurement outcome - BaseState::qreg_.apply_pauli_projector(paulis); } void State::apply_reset(const reg_t &qubits, AER::RngEngine &rng) @@ -642,9 +718,6 @@ void State::apply_snapshot(const Operations::Op &op, ExperimentResult &result, R } switch(it->second) { - case Snapshots::state: - BaseState::snapshot_state(op, result, "extended_stabilizer_state"); - break; case Snapshots::cmemory: BaseState::snapshot_creg_memory(op, result); break; @@ -654,7 +727,7 @@ void State::apply_snapshot(const Operations::Op &op, ExperimentResult &result, R case Snapshots::statevector: statevector_snapshot(op, result, rng); break; - case Snapshots::probabilities: + case Snapshots::probs: probabilities_snapshot(op, result, rng); break; default: @@ -667,7 +740,7 @@ void State::apply_snapshot(const Operations::Op &op, ExperimentResult &result, R void State::statevector_snapshot(const Operations::Op &op, ExperimentResult &result, RngEngine &rng) { cvector_t statevector; - BaseState::qreg_.state_vector(statevector, rng); + BaseState::qreg_.state_vector(statevector, norm_estimation_samples_, 3, rng); double sum = 0.; for(uint_t i=0; i samples; - if(BaseState::qreg_.get_num_states() == 1) - { - samples = BaseState::qreg_.stabilizer_sampler(probabilities_snapshot_samples_, rng); - } - else - { - samples = BaseState::qreg_.metropolis_estimation(metropolis_mixing_steps_, probabilities_snapshot_samples_, - rng); - } - #pragma omp parallel for if(BaseState::qreg_.check_omp_threshold() && BaseState::threads_>1) num_threads(BaseState::threads_) - for(int_t i=0; i < dim; i++) + if (BaseState::qreg_.get_num_states() == 1 || sampling_method_ != SamplingMethod::norm_estimation) { - uint_t target = 0ULL; - for(uint_t j=0; j samples; + samples.reserve(probabilities_snapshot_samples_); + if(BaseState::qreg_.get_num_states() == 1) { - if((dim >> j) & 1ULL) + samples = BaseState::qreg_.stabilizer_sampler(probabilities_snapshot_samples_, rng); + } + else + { + if (sampling_method_ == SamplingMethod::metropolis) { - target ^= (1ULL << op.qubits[j]); + samples = BaseState::qreg_.metropolis_estimation(metropolis_mixing_steps_, probabilities_snapshot_samples_, + rng); + } + else{ + for (uint_t s=0; s1) num_threads(BaseState::threads_) + for(int_t i=0; i < dim; i++) { - if((samples[j] & mask) == target) + uint_t target = 0ULL; + for(uint_t j=0; j> j) & 1ULL) + { + target ^= (1ULL << op.qubits[j]); + } + } + for(uint_t j=0; j &ops) - const + const std::vector &ops) const { size_t required_chi = compute_chi(ops); // 5 vectors of num_qubits*8byte words @@ -796,6 +886,11 @@ size_t State::required_memory_mb(uint_t num_qubits, // Plus 2*CHSimulator::pauli_t which has 2 8 byte words and one 4 byte word; double mb_per_state = 5e-5*num_qubits;// size_t required_mb = std::llrint(std::ceil(mb_per_state*required_chi)); + + if (sampling_method_ == SamplingMethod::norm_estimation) + { + required_mb *= 2; + } return required_mb; //Todo: Update this function to account for snapshots } diff --git a/src/simulators/extended_stabilizer/gates.hpp b/src/simulators/extended_stabilizer/gates.hpp index dbc9d17825..6473e66afd 100644 --- a/src/simulators/extended_stabilizer/gates.hpp +++ b/src/simulators/extended_stabilizer/gates.hpp @@ -16,7 +16,7 @@ #define _aer_chsimulator_gates_hpp #define _USE_MATH_DEFINES -#include +#include #include #include @@ -103,7 +103,7 @@ struct U1Sample : public Sample p_threshold = other.p_threshold; } - ~U1Sample() = default; + ~U1Sample() override = default; sample_branch_t sample(double r) const override; }; @@ -142,25 +142,21 @@ U1Sample::U1Sample(double lambda) angle /= 2; complex_t coeff_0 = std::cos(angle)-std::sin(angle); complex_t coeff_1 = root2*std::sin(angle); + complex_t phase_0, phase_1; + std::array gates; if(lambda < 0) { coeff_0 *= root_omega_star; coeff_1 = coeff_1 * root_omega; if(s_z_quadrant) { - branches = - { - sample_branch_t(coeff_0, Gates::sdg), - sample_branch_t(coeff_1, Gates::z) - }; + gates[0] = Gates::sdg; + gates[1] = Gates::z; } else { - branches = - { - sample_branch_t(coeff_0, Gates::id), - sample_branch_t(coeff_1, Gates::sdg) - }; + gates[0] = Gates::id; + gates[1] = Gates::sdg; } } else @@ -169,21 +165,22 @@ U1Sample::U1Sample(double lambda) coeff_1 = coeff_1 * root_omega_star; if(s_z_quadrant) { - branches = - { - sample_branch_t(coeff_0, Gates::s), - sample_branch_t(coeff_1, Gates::z) - }; + gates[0] = Gates::s; + gates[1] = Gates::z; } else { - branches = - { - sample_branch_t(coeff_0, Gates::id), - sample_branch_t(coeff_1, Gates::s) - }; + gates[0] = Gates::id; + gates[1] = Gates::s; } } + phase_0 = std::polar(1.0, std::arg(coeff_0)); + phase_1 = std::polar(1.0, std::arg(coeff_1)); + branches = + { + sample_branch_t(phase_0, gates[0]), + sample_branch_t(phase_1, gates[1]) + }; p_threshold = std::abs(coeff_0) / (std::abs(coeff_0)+std::abs(coeff_1)); } @@ -242,6 +239,4 @@ sample_branch_t U1Sample::sample(double r) const } - - #endif diff --git a/test/terra/backends/test_qasm_simulator_extended_stabilizer.py b/test/terra/backends/test_qasm_simulator_extended_stabilizer.py index d21f8e03cb..57b6b9372b 100644 --- a/test/terra/backends/test_qasm_simulator_extended_stabilizer.py +++ b/test/terra/backends/test_qasm_simulator_extended_stabilizer.py @@ -15,6 +15,7 @@ import unittest import logging +from math import sqrt from test.terra import common from test.terra.reference import ref_measure from test.terra.reference import ref_reset @@ -24,6 +25,7 @@ from test.terra.reference import ref_non_clifford from test.terra.reference import ref_algorithms +from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister from qiskit.compiler import assemble from qiskit.providers.aer import QasmSimulator @@ -35,13 +37,22 @@ class TestQasmExtendedStabilizerSimulator(common.QiskitAerTestCase): BACKEND_OPTS = { "seed_simulator": 1984, - "method": "extended_stabilizer" + "method": "extended_stabilizer", + "extended_stabilizer_sampling_method": "resampled_metropolis", } BACKEND_OPTS_SAMPLING = { "seed_simulator": 1984, "method": "extended_stabilizer", - "extended_stabilizer_measure_sampling": True + "extended_stabilizer_sampling_method": "metropolis", + } + + BACKEND_OPTS_NE = { + "seed_simulator": 1984, + "method": "extended_stabilizer", + "extended_stabilizer_sampling_method": "norm_estimation", + "extended_stabilizer_norm_estimation_default_samples": 100, + "extended_stabilizer_norm_estimation_repetitions": 3 } # --------------------------------------------------------------------- @@ -102,7 +113,7 @@ def test_measure_deterministic_without_sampling(self): self.compare_counts(result, circuits, targets, delta=0) def test_measure_nondeterministic_with_sampling(self): - """Test CHimulator measure with non-deterministic counts with sampling""" + """Test ExtendedStabilizer measure with non-deterministic counts with sampling""" shots = 4000 circuits = ref_measure.measure_circuits_nondeterministic( allow_sampling=True) @@ -114,7 +125,7 @@ def test_measure_nondeterministic_with_sampling(self): self.compare_counts(result, circuits, targets, delta=0.05 * shots) def test_measure_nondeterministic_without_sampling(self): - """Test CHimulator measure with non-deterministic counts without sampling""" + """Test ExtendedStabilizer measure with non-deterministic counts without sampling""" shots = 4000 circuits = ref_measure.measure_circuits_nondeterministic( allow_sampling=False) @@ -153,7 +164,7 @@ def test_measure_deterministic_multi_qubit_without_sampling(self): self.compare_counts(result, circuits, targets, delta=0) def test_measure_nondeterministic_multi_qubit_with_sampling(self): - """Test CHimulator reset with non-deterministic counts""" + """Test ExtendedStabilizer reset with non-deterministic counts""" shots = 4000 circuits = ref_measure.multiqubit_measure_circuits_nondeterministic( allow_sampling=True) @@ -165,7 +176,7 @@ def test_measure_nondeterministic_multi_qubit_with_sampling(self): self.compare_counts(result, circuits, targets, delta=0.05 * shots) def test_measure_nondeterministic_multi_qubit_without_sampling(self): - """Test CHimulator reset with non-deterministic counts""" + """Test ExtendedStabilizer reset with non-deterministic counts""" shots = 4000 circuits = ref_measure.multiqubit_measure_circuits_nondeterministic( allow_sampling=False) @@ -433,7 +444,7 @@ def test_t_gate_nondeterministic_default_basis_gates(self): qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_non_clifford.t_gate_counts_nondeterministic(shots) opts = self.BACKEND_OPTS.copy() - opts["extended_stabilizer_mixing_time"] = 50 + opts["extended_stabilizer_metropolis_mixing_time"] = 50 job = QasmSimulator().run(qobj, **opts) result = job.result() self.assertSuccess(result) @@ -463,7 +474,7 @@ def test_tdg_gate_nondeterministic_default_basis_gates(self): qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_non_clifford.tdg_gate_counts_nondeterministic(shots) opts = self.BACKEND_OPTS.copy() - opts["extended_stabilizer_mixing_time"] = 50 + opts["extended_stabilizer_metropolis_mixing_time"] = 50 job = QasmSimulator().run(qobj, **opts) result = job.result() self.assertSuccess(result) @@ -480,7 +491,7 @@ def test_ccx_gate_deterministic_default_basis_gates(self): qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_non_clifford.ccx_gate_counts_deterministic(shots) opts = self.BACKEND_OPTS.copy() - opts["extended_stabilizer_mixing_time"] = 100 + opts["extended_stabilizer_metropolis_mixing_time"] = 100 job = QasmSimulator().run(qobj, **opts) result = job.result() self.assertSuccess(result) @@ -494,7 +505,7 @@ def test_ccx_gate_nondeterministic_default_basis_gates(self): qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_non_clifford.ccx_gate_counts_nondeterministic(shots) opts = self.BACKEND_OPTS.copy() - opts["extended_stabilizer_mixing_time"] = 100 + opts["extended_stabilizer_metropolis_mixing_time"] = 100 job = QasmSimulator().run(qobj, **opts) result = job.result() self.assertSuccess(result) @@ -510,8 +521,8 @@ def test_grovers_default_basis_gates(self): final_measure=True, allow_sampling=True) qobj = assemble(circuits, QasmSimulator(), shots=shots) targets = ref_algorithms.grovers_counts(shots) - opts = self.BACKEND_OPTS.copy() - opts["extended_stabilizer_mixing_time"] = 100 + opts = self.BACKEND_OPTS_SAMPLING.copy() + opts["extended_stabilizer_metropolis_mixing_time"] = 100 job = QasmSimulator().run(qobj, **opts) result = job.result() self.assertSuccess(result) @@ -528,6 +539,32 @@ def test_teleport_default_basis_gates(self): self.assertSuccess(result) self.compare_counts(result, circuits, targets, delta=0.05 * shots) + def test_sparse_output_probabilities(self): + """ + Test a circuit for which the metropolis method fails. + See Issue #306 for details. + """ + shots = 100 + nqubits = 5 + qreg = QuantumRegister(nqubits) + creg = ClassicalRegister(nqubits) + circ = QuantumCircuit(qreg, creg) + circ.h(qreg[0]) + circ.t(qreg[0]) + circ.h(qreg[0]) + for i in range(nqubits-1): + circ.cx(qreg[0], qreg[i+1]) + circ.measure(qreg, creg) + target = { + '0x0': shots * (0.5 + sqrt(2)/4.), + '0x1f': shots * (0.5 - sqrt(2)/4.) + } + qobj = assemble([circ], QasmSimulator(), shots=shots) + job = QasmSimulator().run(qobj, **self.BACKEND_OPTS_NE) + result = job.result() + self.assertSuccess(result) + self.compare_counts(result, [circ], [target], delta=0.05 * shots) + if __name__ == '__main__': unittest.main() From 29a3a82c9a21d04ab81af21726db8686a853264d Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Tue, 17 Nov 2020 11:04:37 -0500 Subject: [PATCH 044/126] Update setup-build action version (#1045) This commit updates the version of the setup-msbuild action we use in the windows ci jobs. This action is used to setup the compilers in the windows environment, but the version we were using was relying on a previously deprecated and now removed feature in github actions and has now stopped working. By updating the version we should unblock CI. --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c24711f277..a78693e237 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -90,7 +90,7 @@ jobs: shell: bash if: runner.os == 'Linux' - name: Add msbuild to PATH - uses: microsoft/setup-msbuild@v1.0.1 + uses: microsoft/setup-msbuild@v1.0.2 if: runner.os == 'Windows' - name: Compile Standalone Windows run: | @@ -219,7 +219,7 @@ jobs: ${{ runner.os }}-${{ matrix.python-version}}- if: runner.os == 'Windows' - name: Add msbuild to PATH - uses: microsoft/setup-msbuild@v1.0.1 + uses: microsoft/setup-msbuild@v1.0.2 if: runner.os == 'Windows' - name: Install Deps run: python -m pip install -U -r requirements-dev.txt wheel git+https://github.com/Qiskit/qiskit-terra From 90248c0938a1ee4217259028b35463c7f90cadd6 Mon Sep 17 00:00:00 2001 From: Victor Villar Date: Wed, 18 Nov 2020 09:00:07 +0100 Subject: [PATCH 045/126] Use Terra operators instead of Qutip qobjects. (#1014) Migrate usage from Qutip Qobjects to Terra operators. Remove qutip and associated cython dependencies as they are not needed anymore. --- CMakeLists.txt | 2 - azure-pipelines.yml | 6 +- cmake/FindCython.cmake | 78 -- cmake/cython_utils.cmake | 140 ---- qiskit/providers/aer/pulse/__init__.py | 6 - .../aer/pulse/controllers/mc_controller.py | 20 +- .../aer/pulse/controllers/pulse_controller.py | 76 +- .../pulse/controllers/unitary_controller.py | 5 +- .../aer/pulse/qutip_extra_lite/__init__.py | 16 - .../pulse/qutip_extra_lite/cy/CMakeLists.txt | 10 - .../aer/pulse/qutip_extra_lite/cy/__init__.py | 0 .../qutip_extra_lite/cy/complex_math.pxi | 24 - .../pulse/qutip_extra_lite/cy/parameters.pxi | 14 - .../pulse/qutip_extra_lite/cy/pyxbuilder.py | 76 -- .../qutip_extra_lite/cy/sparse_routines.pxi | 265 ------ .../qutip_extra_lite/cy/sparse_structs.pxd | 47 -- .../qutip_extra_lite/cy/sparse_utils.pyx | 379 --------- .../pulse/qutip_extra_lite/cy/spconvert.pxd | 39 - .../pulse/qutip_extra_lite/cy/spconvert.pyx | 303 ------- .../pulse/qutip_extra_lite/cy/spmatfuncs.pxd | 49 -- .../pulse/qutip_extra_lite/cy/spmatfuncs.pyx | 100 --- .../aer/pulse/qutip_extra_lite/cy/spmath.pyx | 423 ---------- .../pulse/qutip_extra_lite/cy/utilities.py | 72 -- .../aer/pulse/qutip_extra_lite/dimensions.py | 134 --- .../aer/pulse/qutip_extra_lite/fastsparse.py | 440 ---------- .../aer/pulse/qutip_extra_lite/operators.py | 457 ----------- .../aer/pulse/qutip_extra_lite/qobj.py | 768 ------------------ .../aer/pulse/qutip_extra_lite/states.py | 113 --- .../aer/pulse/qutip_extra_lite/tensor.py | 111 --- .../pulse/system_models/hamiltonian_model.py | 2 +- .../string_model_parser/gen_operator.py | 141 ++++ ...from_string.py => operator_from_string.py} | 23 +- .../operator_generators.py} | 37 +- .../string_model_parser.py | 2 +- .../cython-dep-removed-ffc095dcc575c449.yaml | 4 + requirements-dev.txt | 1 - setup.py | 8 - src/open_pulse/numeric_integrator.cpp | 34 +- src/open_pulse/pulse_utils.cpp | 60 +- src/open_pulse/pulse_utils.hpp | 7 + src/open_pulse/pulse_utils_bindings.cpp | 16 +- src/open_pulse/python_to_cpp.hpp | 14 +- src/open_pulse/test_python_to_cpp.cpp | 11 + src/open_pulse/test_python_to_cpp.hpp | 4 + test/asv.linux.cuda.conf.json | 2 +- .../pulse/test_duffing_model_generators.py | 9 +- test/terra/pulse/test_system_models.py | 2 +- test/terra/test_python_to_cpp.py | 8 +- 48 files changed, 357 insertions(+), 4201 deletions(-) delete mode 100644 cmake/FindCython.cmake delete mode 100644 cmake/cython_utils.cmake delete mode 100644 qiskit/providers/aer/pulse/qutip_extra_lite/__init__.py delete mode 100644 qiskit/providers/aer/pulse/qutip_extra_lite/cy/CMakeLists.txt delete mode 100644 qiskit/providers/aer/pulse/qutip_extra_lite/cy/__init__.py delete mode 100644 qiskit/providers/aer/pulse/qutip_extra_lite/cy/complex_math.pxi delete mode 100644 qiskit/providers/aer/pulse/qutip_extra_lite/cy/parameters.pxi delete mode 100644 qiskit/providers/aer/pulse/qutip_extra_lite/cy/pyxbuilder.py delete mode 100644 qiskit/providers/aer/pulse/qutip_extra_lite/cy/sparse_routines.pxi delete mode 100644 qiskit/providers/aer/pulse/qutip_extra_lite/cy/sparse_structs.pxd delete mode 100644 qiskit/providers/aer/pulse/qutip_extra_lite/cy/sparse_utils.pyx delete mode 100644 qiskit/providers/aer/pulse/qutip_extra_lite/cy/spconvert.pxd delete mode 100644 qiskit/providers/aer/pulse/qutip_extra_lite/cy/spconvert.pyx delete mode 100644 qiskit/providers/aer/pulse/qutip_extra_lite/cy/spmatfuncs.pxd delete mode 100644 qiskit/providers/aer/pulse/qutip_extra_lite/cy/spmatfuncs.pyx delete mode 100644 qiskit/providers/aer/pulse/qutip_extra_lite/cy/spmath.pyx delete mode 100644 qiskit/providers/aer/pulse/qutip_extra_lite/cy/utilities.py delete mode 100644 qiskit/providers/aer/pulse/qutip_extra_lite/dimensions.py delete mode 100644 qiskit/providers/aer/pulse/qutip_extra_lite/fastsparse.py delete mode 100644 qiskit/providers/aer/pulse/qutip_extra_lite/operators.py delete mode 100644 qiskit/providers/aer/pulse/qutip_extra_lite/qobj.py delete mode 100644 qiskit/providers/aer/pulse/qutip_extra_lite/states.py delete mode 100644 qiskit/providers/aer/pulse/qutip_extra_lite/tensor.py create mode 100644 qiskit/providers/aer/pulse/system_models/string_model_parser/gen_operator.py rename qiskit/providers/aer/pulse/system_models/string_model_parser/{qobj_from_string.py => operator_from_string.py} (73%) rename qiskit/providers/aer/pulse/{qutip_extra_lite/qobj_generators.py => system_models/string_model_parser/operator_generators.py} (84%) create mode 100644 releasenotes/notes/cython-dep-removed-ffc095dcc575c449.yaml diff --git a/CMakeLists.txt b/CMakeLists.txt index 505b20c7b5..354fbf6127 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -299,10 +299,8 @@ set(AER_LIBRARIES ${THRUST_DEPENDENT_LIBS}) set(AER_COMPILER_DEFINITIONS ${AER_COMPILER_DEFINITIONS} ${CONAN_DEFINES}) -# Cython build is only enabled if building through scikit-build. if(SKBUILD) # Terra Addon build set(AER_LIBRARIES ${AER_LIBRARIES} AER_DEPENDENCY_PKG::muparserx) - add_subdirectory(qiskit/providers/aer/pulse/qutip_extra_lite/cy) add_subdirectory(qiskit/providers/aer/backends/wrappers) add_subdirectory(src/open_pulse) else() # Standalone build diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 1f1f7b4299..ce4c9870a0 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -45,7 +45,7 @@ stages: source activate qiskit-aer-$version conda update --yes -n base conda conda config --add channels conda-forge - conda install --yes --quiet --name qiskit-aer-$version python=$version numpy cmake pip setuptools pybind11 cython scipy + conda install --yes --quiet --name qiskit-aer-$version python=$version numpy cmake pip setuptools pybind11 scipy python setup.py bdist_wheel -- -G "Visual Studio 15 2017 Win64" conda create --yes --quiet python=$version --name test-$version source activate test-$version @@ -154,7 +154,7 @@ stages: source activate qiskit-aer conda update --yes -n base conda conda config --add channels conda-forge - conda install --yes --quiet --name qiskit-aer python=$(python.version) numpy cmake pip setuptools pybind11 cython scipy + conda install --yes --quiet --name qiskit-aer python=$(python.version) numpy cmake pip setuptools pybind11 scipy displayName: Create Anaconda environments - bash: | set -x @@ -195,7 +195,7 @@ stages: set -e conda create --yes --quiet --name qiskit-aer python=$(python.version) source activate qiskit-aer - conda install --yes --quiet --name qiskit-aer python=$(python.version) numpy cmake pip setuptools pybind11 cython scipy + conda install --yes --quiet --name qiskit-aer python=$(python.version) numpy cmake pip setuptools pybind11 scipy displayName: Create Anaconda environments env: CONDA_FORCE_32BIT: 1 diff --git a/cmake/FindCython.cmake b/cmake/FindCython.cmake deleted file mode 100644 index b8ae305323..0000000000 --- a/cmake/FindCython.cmake +++ /dev/null @@ -1,78 +0,0 @@ -#.rst: -# -# Find ``cython`` executable. -# -# This module will set the following variables in your project: -# -# ``CYTHON_EXECUTABLE`` -# path to the ``cython`` program -# -# ``CYTHON_VERSION`` -# version of ``cython`` -# -# ``CYTHON_FOUND`` -# true if the program was found -# -# For more information on the Cython project, see http://cython.org/. -# -# *Cython is a language that makes writing C extensions for the Python language -# as easy as Python itself.* -# -#============================================================================= -# Copyright 2011 Kitware, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#============================================================================= - -# Use the Cython executable that lives next to the Python executable -# if it is a local installation. -find_package(PythonInterp) -if(PYTHONINTERP_FOUND) - get_filename_component(_python_path ${PYTHON_EXECUTABLE} PATH) - find_program(CYTHON_EXECUTABLE - NAMES cython cython.bat cython3 - HINTS ${_python_path} - DOC "path to the cython executable") -else() - find_program(CYTHON_EXECUTABLE - NAMES cython cython.bat cython3 - DOC "path to the cython executable") -endif() - -if(CYTHON_EXECUTABLE) - set(CYTHON_version_command ${CYTHON_EXECUTABLE} --version) - - execute_process(COMMAND ${CYTHON_version_command} - OUTPUT_VARIABLE CYTHON_version_output - ERROR_VARIABLE CYTHON_version_error - RESULT_VARIABLE CYTHON_version_result - OUTPUT_STRIP_TRAILING_WHITESPACE) - - if(NOT ${CYTHON_version_result} EQUAL 0) - set(_error_msg "Command \"${CYTHON_version_command}\" failed with") - set(_error_msg "${_error_msg} output:\n${CYTHON_version_error}") - message(SEND_ERROR "${_error_msg}") - else() - if("${CYTHON_version_output}" MATCHES "^[Cc]ython version ([^,]+)") - set(CYTHON_VERSION "${CMAKE_MATCH_1}") - endif() - endif() -endif() - -include(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(Cython REQUIRED_VARS CYTHON_EXECUTABLE) - -mark_as_advanced(CYTHON_EXECUTABLE) - -include(UseCython) - diff --git a/cmake/cython_utils.cmake b/cmake/cython_utils.cmake deleted file mode 100644 index c49c8badb8..0000000000 --- a/cmake/cython_utils.cmake +++ /dev/null @@ -1,140 +0,0 @@ -find_package(PythonExtensions REQUIRED) -find_package(Cython REQUIRED) -find_package(PythonLibs REQUIRED) -set(Python_EXECUTABLE ${PYTHON_EXECUTABLE}) -find_package(Python COMPONENTS NumPy) -if(NOT Python_NumPy_FOUND) - find_package(NumPy) - set(Python_NumPy_INCLUDE_DIRS ${NumPy_INCLUDE_DIRS}) -endif() - -# Variables for input user data: -# -# CYTHON_USER_INCLUDE_DIRS: -# - For Cython modules that need to import some header file not in the paths, example: -# set(CYTHON_USER_INCLUDE_DIRS "/opt/my/include") -# CYTHON_USER_LIB_DIRS: -# - For Cython modules that need to link with external libs, example: -# set(CYTHON_USER_LIB_DIRS "/opt/my/lib") -# CYTHON_INSTALL_DIR: -# - Where to install the resulting shared libraries -# set(CYTHON_INSTALL_DIR "/opt/my/lib") - - -# Set default values -set(CYTHON_USER_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}) -unset(CYTHON_USER_LIB_DIRS) -set(CYTHON_INSTALL_DIR "qiskit/providers/aer/backends") - -include(nvcc_add_compiler_options) - -function(add_cython_module module) - add_cython_target(${module} ${module}.pyx CXX) - - # Avoid warnings in cython cpp generated code - if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(MODULE_COMPILE_FLAGS "-Wno-everything") - elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") - set(MODULE_COMPILE_FLAGS "-w") - elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - set(MODULE_COMPILE_FLAGS "/w") - endif() - - if(CUDA_FOUND AND AER_THRUST_BACKEND STREQUAL "CUDA") - string(STRIP ${MODULE_COMPILE_FLAGS} MODULE_COMPILE_FLAGS_STRIPPED) - nvcc_add_compiler_options(${MODULE_COMPILE_FLAGS_STRIPPED} MODULE_COMPILE_FLAGS_OUT) - set_source_files_properties(${module}.cxx PROPERTIES COMPILE_FLAGS ${MODULE_COMPILE_FLAGS_OUT}) - else() - set_source_files_properties(${module}.cxx PROPERTIES COMPILE_FLAGS ${MODULE_COMPILE_FLAGS}) - endif() - - set(options MODULE SHARED EXCLUDE_FROM_ALL NO_EXTRAS SYSTEM THIN_LTO) - cmake_parse_arguments(ARG "${options}" "" "" ${ARGN}) - if(ARG_MODULE AND ARG_SHARED) - message(FATAL_ERROR "Can't be both MODULE and SHARED") - elseif(ARG_SHARED) - set(lib_type SHARED) - else() - set(lib_type MODULE) - endif() - - if(ARG_EXCLUDE_FROM_ALL) - set(exclude_from_all EXCLUDE_FROM_ALL) - endif() - - if(CUDA_FOUND AND AER_THRUST_BACKEND STREQUAL "CUDA") - set_source_files_properties(${module}.cxx PROPERTIES LANGUAGE CUDA) - - string(STRIP ${AER_COMPILER_FLAGS} AER_COMPILER_FLAGS_STRIPPED) - nvcc_add_compiler_options(${AER_COMPILER_FLAGS_STRIPPED} AER_COMPILER_FLAGS_OUT) - else() - set(AER_COMPILER_FLAGS_OUT ${AER_COMPILER_FLAGS}) - endif() - add_library(${module} ${lib_type} ${exclude_from_all} ${module} ${ARG_UNPARSED_ARGUMENTS}) - - - # We only need to pass the linter once, as the codebase is the same for - # all controllers - # add_linter(target) - target_include_directories(${module} PRIVATE ${AER_SIMULATOR_CPP_SRC_DIR}) - target_include_directories(${module} PRIVATE ${AER_SIMULATOR_CPP_EXTERNAL_LIBS}) - target_include_directories(${module} PRIVATE ${PYTHON_INCLUDE_DIRS}) - target_include_directories(${module} PRIVATE ${Python_NumPy_INCLUDE_DIRS}) - target_include_directories(${module} PRIVATE ${CYTHON_USER_INCLUDE_DIRS}) - - target_link_libraries(${module} ${AER_LIBRARIES} ${CYTHON_USER_LIB_DIRS}) - - if(WIN32 OR CYGWIN) - # Link against the Python shared library on Windows - target_link_libraries(${module} ${PYTHON_LIBRARIES}) - elseif(APPLE) - # It's quite common to have multiple copies of the same Python version - # installed on one's system. E.g.: one copy from the OS and another copy - # that's statically linked into an application like Blender or Maya. - # If we link our plugin library against the OS Python here and import it - # into Blender or Maya later on, this will cause segfaults when multiple - # conflicting Python instances are active at the same time (even when they - # are of the same version). - - # Windows is not affected by this issue since it handles DLL imports - # differently. The solution for Linux and Mac OS is simple: we just don't - # link against the Python library. The resulting shared library will have - # missing symbols, but that's perfectly fine -- they will be resolved at - # import time. - # Set some general flags - if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(AER_LINKER_FLAGS "${AER_LINKER_FLAGS} -undefined dynamic_lookup") - else() - # -flat_namespace linker flag is needed otherwise dynamic symbol resolution doesn't work as expected with GCC. - # Symbols with the same name exist in different .so, so the loader just takes the first one it finds, - # which is usually the one from the first .so loaded. - # See: Two-Leve namespace symbol resolution - set(AER_LINKER_FLAGS "${AER_LINKER_FLAGS} -undefined dynamic_lookup -flat_namespace") - endif() - if(ARG_SHARED) - set_target_properties(${target_name} PROPERTIES MACOSX_RPATH ON) - endif() - endif() - - set_target_properties(${module} PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}") - set_target_properties(${module} PROPERTIES SUFFIX "${PYTHON_EXTENSION_MODULE_SUFFIX}") - set_target_properties(${module} PROPERTIES - CXX_STANDARD 14 - LINKER_LANGUAGE CXX) - # Warning: Do not merge PROPERTIES when one of the variables can be empty, it breaks - # the rest of the properties so they are not properly added. - set_target_properties(${module} PROPERTIES LINK_FLAGS ${AER_LINKER_FLAGS}) - set_target_properties(${module} PROPERTIES COMPILE_FLAGS ${AER_COMPILER_FLAGS_OUT}) - target_compile_definitions(${module} PRIVATE ${AER_COMPILER_DEFINITIONS}) - - python_extension_module(${module} - FORWARD_DECL_MODULES_VAR fdecl_module_list) - - python_modules_header(modules - FORWARD_DECL_MODULES_LIST ${fdecl_module_list}) - - include_directories(${modules_INCLUDE_DIRS}) - - # TODO Where to put the target files - install(TARGETS ${module} LIBRARY DESTINATION ${CYTHON_INSTALL_DIR}) -endfunction() diff --git a/qiskit/providers/aer/pulse/__init__.py b/qiskit/providers/aer/pulse/__init__.py index 079bdce1bb..cb588e5966 100644 --- a/qiskit/providers/aer/pulse/__init__.py +++ b/qiskit/providers/aer/pulse/__init__.py @@ -47,7 +47,6 @@ # pylint: disable=import-error import distutils.sysconfig # noqa import numpy as np -from .qutip_extra_lite.cy import pyxbuilder as pbldr from .system_models.duffing_model_generators import duffing_system_model from .system_models.pulse_system_model import PulseSystemModel @@ -56,8 +55,3 @@ CFG_VARS = distutils.sysconfig.get_config_vars() if "CFLAGS" in CFG_VARS: CFG_VARS["CFLAGS"] = CFG_VARS["CFLAGS"].replace("-Wstrict-prototypes", "") - -# Setup pyximport -# pylint: disable=no-member -pbldr.install(setup_args={'include_dirs': [np.get_include()]}) -del pbldr diff --git a/qiskit/providers/aer/pulse/controllers/mc_controller.py b/qiskit/providers/aer/pulse/controllers/mc_controller.py index 658bb2c17c..4157f53c0b 100644 --- a/qiskit/providers/aer/pulse/controllers/mc_controller.py +++ b/qiskit/providers/aer/pulse/controllers/mc_controller.py @@ -24,7 +24,7 @@ from qiskit.tools.parallel import parallel_map, CPU_COUNT from .pulse_sim_options import PulseSimOptions from .pulse_de_solver import setup_de_solver -from .pulse_utils import (cy_expect_psi_csr, occ_probabilities, write_shots_memory, spmv_csr) +from .pulse_utils import (occ_probabilities, write_shots_memory, spmv, cy_expect_psi) dznrm2 = get_blas_funcs("znrm2", dtype=np.float64) @@ -46,10 +46,10 @@ def run_monte_carlo_experiments(pulse_sim_desc, pulse_de_model, solver_options=N solver_options = PulseSimOptions() if solver_options is None else solver_options - if not pulse_sim_desc.initial_state.isket: + if not pulse_sim_desc.initial_state.data.ndim != 1: raise Exception("Initial state must be a state vector.") - y0 = pulse_sim_desc.initial_state.full().ravel() + y0 = pulse_sim_desc.initial_state.data.ravel() # set num_cpus to the value given in settings if none in Options if not solver_options.num_cpus: @@ -153,6 +153,7 @@ def monte_carlo_evolution(seed, if not ODE.successful(): raise Exception("Integration step failed!") norm2_psi = dznrm2(ODE.y) ** 2 + if norm2_psi <= rand_vals[0]: # collapse has occured: # find collapse time to within specified tolerance @@ -192,21 +193,13 @@ def monte_carlo_evolution(seed, collapse_times.append(ODE.t) # all constant collapse operators. for i in range(n_dp.shape[0]): - n_dp[i] = cy_expect_psi_csr(pulse_de_model.n_ops_data[i], - pulse_de_model.n_ops_ind[i], - pulse_de_model.n_ops_ptr[i], - ODE.y, True) - + n_dp[i] = cy_expect_psi(pulse_de_model.n_ops_data[i], ODE.y, True) # determine which operator does collapse and store it _p = np.cumsum(n_dp / np.sum(n_dp)) j = cinds[_p >= rand_vals[1]][0] collapse_operators.append(j) - state = spmv_csr(pulse_de_model.c_ops_data[j], - pulse_de_model.c_ops_ind[j], - pulse_de_model.c_ops_ptr[j], - ODE.y) - + state = spmv(pulse_de_model.c_ops_data[j], ODE.y) state /= dznrm2(state) ODE.y = state rand_vals = rng.rand(2) @@ -214,6 +207,7 @@ def monte_carlo_evolution(seed, # after while loop (Do measurement or conditional) # ------------------------------------------------ out_psi = ODE.y / dznrm2(ODE.y) + for aind in range(acq_idx, num_acq): if exp['acquire'][aind][0] == stop_time: current_acq = exp['acquire'][aind] diff --git a/qiskit/providers/aer/pulse/controllers/pulse_controller.py b/qiskit/providers/aer/pulse/controllers/pulse_controller.py index 207b0b6a27..8e964cc5bc 100644 --- a/qiskit/providers/aer/pulse/controllers/pulse_controller.py +++ b/qiskit/providers/aer/pulse/controllers/pulse_controller.py @@ -19,10 +19,10 @@ from warnings import warn import numpy as np +from qiskit.quantum_info.operators.operator import Operator from ..system_models.string_model_parser.string_model_parser import NoiseParser -from ..qutip_extra_lite import qobj_generators as qobj_gen +from ..system_models.string_model_parser import operator_generators as op_gen from .digest_pulse_qobj import digest_pulse_qobj -from ..qutip_extra_lite.qobj import Qobj from .pulse_sim_options import PulseSimOptions from .unitary_controller import run_unitary_experiments from .mc_controller import run_monte_carlo_experiments @@ -74,11 +74,11 @@ def pulse_controller(qobj): dim_qub = ham_model._subsystem_dims dim_osc = {} # convert estates into a Qutip qobj - estates = [qobj_gen.state(state) for state in ham_model._estates.T[:]] + estates = [op_gen.state(state) for state in ham_model._estates.T[:]] # initial state set here if hasattr(config, 'initial_state'): - pulse_sim_desc.initial_state = Qobj(config.initial_state) + pulse_sim_desc.initial_state = op_gen.state(config.initial_state) else: pulse_sim_desc.initial_state = estates[0] @@ -189,12 +189,12 @@ def pulse_controller(qobj): if not pulse_sim_desc.measurement_ops[qubit_list.index(jj)]: q_level_meas = pulse_sim_desc.q_level_meas pulse_sim_desc.measurement_ops[qubit_list.index(jj)] = \ - qobj_gen.qubit_occ_oper_dressed(jj, - estates, - h_osc=dim_osc, - h_qub=dim_qub, - level=q_level_meas - ) + op_gen.qubit_occ_oper_dressed(jj, + estates, + h_osc=dim_osc, + h_qub=dim_qub, + level=q_level_meas + ) if not exp['can_sample']: pulse_sim_desc.can_sample = False @@ -352,16 +352,10 @@ def __init__(self): self.num_h_terms = None self.c_num = None self.c_ops_data = None - self.c_ops_ind = None - self.c_ops_ptr = None self.n_ops_data = None - self.n_ops_ind = None - self.n_ops_ptr = None self.h_diag_elems = None self.h_ops_data = None - self.h_ops_ind = None - self.h_ops_ptr = None self._rhs_dict = None @@ -377,45 +371,33 @@ def _config_internal_data(self): H = [hpart[0] for hpart in self.system] self.num_h_terms = num_h_terms - # take care of collapse operators, if any - self.c_num = 0 - if self.noise: - self.c_num = len(self.noise) - self.num_h_terms += 1 - self.c_ops_data = [] - self.c_ops_ind = [] - self.c_ops_ptr = [] self.n_ops_data = [] - self.n_ops_ind = [] - self.n_ops_ptr = [] self.h_diag_elems = self.h_diag # if there are any collapse operators - H_noise = 0 - for kk in range(self.c_num): - c_op = self.noise[kk] - n_op = c_op.dag() * c_op - # collapse ops - self.c_ops_data.append(c_op.data.data) - self.c_ops_ind.append(c_op.data.indices) - self.c_ops_ptr.append(c_op.data.indptr) - # norm ops - self.n_ops_data.append(n_op.data.data) - self.n_ops_ind.append(n_op.data.indices) - self.n_ops_ptr.append(n_op.data.indptr) - # Norm ops added to time-independent part of - # Hamiltonian to decrease norm - H_noise -= 0.5j * n_op - - if H_noise: + self.c_num = 0 + + if self.noise: + self.c_num = len(self.noise) + self.num_h_terms += 1 + H_noise = Operator(np.zeros(self.noise[0].data.shape)) + for kk in range(self.c_num): + c_op = self.noise[kk] + n_op = c_op.adjoint() @ c_op + # collapse ops + self.c_ops_data.append(c_op.data) + # norm ops + self.n_ops_data.append(n_op.data) + # Norm ops added to time-independent part of + # Hamiltonian to decrease norm + H_noise = Operator(H_noise.data - 0.5j * n_op.data) + H = H + [H_noise] # construct data sets - self.h_ops_data = [-1.0j * hpart.data.data for hpart in H] - self.h_ops_ind = [hpart.data.indices for hpart in H] - self.h_ops_ptr = [hpart.data.indptr for hpart in H] + self.h_ops_data = [-1.0j * hpart.data for hpart in H] self._rhs_dict = {'freqs': list(self.freqs.values()), 'pulse_array': self.pulse_array, @@ -424,8 +406,6 @@ def _config_internal_data(self): 'vars_names': self.vars_names, 'num_h_terms': self.num_h_terms, 'h_ops_data': self.h_ops_data, - 'h_ops_ind': self.h_ops_ind, - 'h_ops_ptr': self.h_ops_ptr, 'h_diag_elems': self.h_diag_elems} def init_rhs(self, exp): diff --git a/qiskit/providers/aer/pulse/controllers/unitary_controller.py b/qiskit/providers/aer/pulse/controllers/unitary_controller.py index f76957158e..0397e12f25 100644 --- a/qiskit/providers/aer/pulse/controllers/unitary_controller.py +++ b/qiskit/providers/aer/pulse/controllers/unitary_controller.py @@ -24,7 +24,6 @@ from .pulse_sim_options import PulseSimOptions from .pulse_de_solver import setup_de_solver -# Imports from qutip_extra_lite from .pulse_utils import occ_probabilities, write_shots_memory dznrm2 = get_blas_funcs("znrm2", dtype=np.float64) @@ -83,10 +82,10 @@ def run_unitary_experiments(pulse_sim_desc, pulse_de_model, solver_options=None) solver_options = PulseSimOptions() if solver_options is None else solver_options - if not pulse_sim_desc.initial_state.isket: + if not pulse_sim_desc.initial_state.data.ndim != 1: raise Exception("Initial state must be a state vector.") - y0 = pulse_sim_desc.initial_state.full().ravel() + y0 = pulse_sim_desc.initial_state.data.ravel() # set num_cpus to the value given in settings if none in Options if not solver_options.num_cpus: diff --git a/qiskit/providers/aer/pulse/qutip_extra_lite/__init__.py b/qiskit/providers/aer/pulse/qutip_extra_lite/__init__.py deleted file mode 100644 index 1b3f375cbe..0000000000 --- a/qiskit/providers/aer/pulse/qutip_extra_lite/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# -*- coding: utf-8 -*- - -# This code is part of Qiskit. -# -# (C) Copyright IBM 2018, 2019, 2020. -# -# 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. - -"""Temporary folder containing trimmed down qutip objects and functions -""" diff --git a/qiskit/providers/aer/pulse/qutip_extra_lite/cy/CMakeLists.txt b/qiskit/providers/aer/pulse/qutip_extra_lite/cy/CMakeLists.txt deleted file mode 100644 index a5529c2acf..0000000000 --- a/qiskit/providers/aer/pulse/qutip_extra_lite/cy/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -include(Linter) -include(cython_utils) -# We need to remove the -static flag, because Python Extension system only supports -# dynamic linked libraries, but we want to build a shared libraries with the least -# dependencies we can, so some of these dependencies are linked statically into our -# shared library. -string(REPLACE " -static " "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") - -set(CYTHON_INSTALL_DIR "qiskit/providers/aer/pulse/qutip_extra_lite/cy") -add_cython_module(spmath) diff --git a/qiskit/providers/aer/pulse/qutip_extra_lite/cy/__init__.py b/qiskit/providers/aer/pulse/qutip_extra_lite/cy/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/qiskit/providers/aer/pulse/qutip_extra_lite/cy/complex_math.pxi b/qiskit/providers/aer/pulse/qutip_extra_lite/cy/complex_math.pxi deleted file mode 100644 index 43f0fd1793..0000000000 --- a/qiskit/providers/aer/pulse/qutip_extra_lite/cy/complex_math.pxi +++ /dev/null @@ -1,24 +0,0 @@ -cdef extern from "" namespace "std" nogil: - double abs(double complex x) - double complex acos(double complex x) - double complex acosh(double complex x) - double arg(double complex x) - double complex asin(double complex x) - double complex asinh(double complex x) - double complex atan(double complex x) - double complex atanh(double complex x) - double complex conj(double complex x) - double complex cos(double complex x) - double complex cosh(double complex x) - double complex exp(double complex x) - double imag(double complex x) - double complex log(double complex x) - double complex log10(double complex x) - double norm(double complex x) - double complex proj(double complex x) - double real(double complex x) - double complex sin(double complex x) - double complex sinh(double complex x) - double complex sqrt(double complex x) - double complex tan(double complex x) - double complex tanh(double complex x) diff --git a/qiskit/providers/aer/pulse/qutip_extra_lite/cy/parameters.pxi b/qiskit/providers/aer/pulse/qutip_extra_lite/cy/parameters.pxi deleted file mode 100644 index 66705ba064..0000000000 --- a/qiskit/providers/aer/pulse/qutip_extra_lite/cy/parameters.pxi +++ /dev/null @@ -1,14 +0,0 @@ -import numpy as np -cimport numpy as cnp - -DTYPE = np.float64 -ctypedef cnp.float64_t DTYPE_t - -ITYPE = np.int32 -ctypedef cnp.int32_t ITYPE_t - -CTYPE = np.complex128 -ctypedef cnp.complex128_t CTYPE_t - -CTYPE = np.int64 -ctypedef cnp.int64_t LTYPE_t diff --git a/qiskit/providers/aer/pulse/qutip_extra_lite/cy/pyxbuilder.py b/qiskit/providers/aer/pulse/qutip_extra_lite/cy/pyxbuilder.py deleted file mode 100644 index b7f9792bba..0000000000 --- a/qiskit/providers/aer/pulse/qutip_extra_lite/cy/pyxbuilder.py +++ /dev/null @@ -1,76 +0,0 @@ -# -*- coding: utf-8 -*- - -# 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. - -# This file is part of QuTiP: Quantum Toolbox in Python. -# -# Copyright (c) 2011 and later, The QuTiP Project -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# 3. Neither the name of the QuTiP: Quantum Toolbox in Python nor the names -# of its contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -############################################################################### -"""Utility for making the build options for compiling the Hamiltonian""" -import sys -import os -import pyximport -from pyximport import install - -__all__ = ["install"] - -OLD_EXT = pyximport.pyximport.get_distutils_extension - - -def new_get_distutils_extension(modname, pyxfilename, language_level=None): - """Get the distutils extension""" - extension_mod, setup_args = OLD_EXT(modname, pyxfilename, language_level) - extension_mod.language = 'c++' - # If on Win and Python version >= 3.5 and not in MSYS2 (i.e. Visual studio compile) - if sys.platform == 'win32' and \ - (int(str(sys.version_info[0]) + str(sys.version_info[1])) >= 35) \ - and os.environ.get('MSYSTEM') is None: - - extension_mod.extra_compile_args = ['/w', '/O1'] - else: - extension_mod.extra_compile_args = ['-w', '-O1'] - if sys.platform == 'darwin': - extension_mod.extra_compile_args.append('-mmacosx-version-min=10.9') - extension_mod.extra_link_args = ['-mmacosx-version-min=10.9'] - return extension_mod, setup_args - - -pyximport.pyximport.get_distutils_extension = new_get_distutils_extension diff --git a/qiskit/providers/aer/pulse/qutip_extra_lite/cy/sparse_routines.pxi b/qiskit/providers/aer/pulse/qutip_extra_lite/cy/sparse_routines.pxi deleted file mode 100644 index 2c2cec8786..0000000000 --- a/qiskit/providers/aer/pulse/qutip_extra_lite/cy/sparse_routines.pxi +++ /dev/null @@ -1,265 +0,0 @@ -#!python -#cython: language_level=3 -# This file is part of QuTiP: Quantum Toolbox in Python. -# -# Copyright (c) 2011 and later, The QuTiP Project. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# 3. Neither the name of the QuTiP: Quantum Toolbox in Python nor the names -# of its contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -############################################################################### -import numpy as np -from scipy.sparse import coo_matrix -from ..fastsparse import fast_csr_matrix -cimport numpy as np -cimport cython -from libcpp.algorithm cimport sort -from libcpp.vector cimport vector -from .sparse_structs cimport CSR_Matrix -np.import_array() -from libc.string cimport memset - -cdef extern from "numpy/arrayobject.h" nogil: - void PyArray_ENABLEFLAGS(np.ndarray arr, int flags) - void PyDataMem_FREE(void * ptr) - void PyDataMem_RENEW(void * ptr, size_t size) - void PyDataMem_NEW(size_t size) - - -#Struct used for CSR indices sorting -cdef struct _data_ind_pair: - double complex data - int ind - -ctypedef _data_ind_pair data_ind_pair -ctypedef int (*cfptr)(data_ind_pair, data_ind_pair) - - -cdef void raise_error_CSR(int E, CSR_Matrix * C = NULL): - if not C.numpy_lock and C != NULL: - free_CSR(C) - if E == -1: - raise MemoryError('Could not allocate memory.') - elif E == -2: - raise Exception('Error manipulating CSR_Matrix structure.') - elif E == -3: - raise Exception('CSR_Matrix is not initialized.') - elif E == -4: - raise Exception('NumPy already has lock on data.') - elif E == -5: - raise Exception('Cannot expand data structures past max_length.') - elif E == -6: - raise Exception('CSR_Matrix cannot be expanded.') - elif E == -7: - raise Exception('Data length cannot be larger than max_length') - else: - raise Exception('Error in Cython code.') - -cdef inline int int_min(int a, int b) nogil: - return b if b < a else a - -cdef inline int int_max(int a, int b) nogil: - return a if a > b else b - - -@cython.boundscheck(False) -@cython.wraparound(False) -cdef void init_CSR(CSR_Matrix * mat, int nnz, int nrows, int ncols = 0, - int max_length = 0, int init_zeros = 1): - """ - Initialize CSR_Matrix struct. Matrix is assumed to be square with - shape nrows x nrows. Manually set mat.ncols otherwise - - Parameters - ---------- - mat : CSR_Matrix * - Pointer to struct. - nnz : int - Length of data and indices arrays. Also number of nonzero elements - nrows : int - Number of rows in matrix. Also gives length - of indptr array (nrows+1). - ncols : int (default = 0) - Number of cols in matrix. Default is ncols = nrows. - max_length : int (default = 0) - Maximum length of data and indices arrays. Used for resizing. - Default value of zero indicates no resizing. - """ - if max_length == 0: - max_length = nnz - if nnz > max_length: - raise_error_CSR(-7, mat) - if init_zeros: - mat.data = PyDataMem_NEW(nnz * sizeof(double complex)) - memset(&mat.data[0],0,nnz * sizeof(double complex)) - else: - mat.data = PyDataMem_NEW(nnz * sizeof(double complex)) - if mat.data == NULL: - raise_error_CSR(-1, mat) - if init_zeros: - mat.indices = PyDataMem_NEW(nnz * sizeof(int)) - mat.indptr = PyDataMem_NEW((nrows+1) * sizeof(int)) - memset(&mat.indices[0],0,nnz * sizeof(int)) - memset(&mat.indptr[0],0,(nrows+1) * sizeof(int)) - else: - mat.indices = PyDataMem_NEW(nnz * sizeof(int)) - mat.indptr = PyDataMem_NEW((nrows+1) * sizeof(int)) - mat.nnz = nnz - mat.nrows = nrows - if ncols == 0: - mat.ncols = nrows - else: - mat.ncols = ncols - mat.is_set = 1 - mat.max_length = max_length - mat.numpy_lock = 0 - - -@cython.boundscheck(False) -@cython.wraparound(False) -cdef void copy_CSR(CSR_Matrix * out, CSR_Matrix * mat): - """ - Copy a CSR_Matrix. - """ - cdef size_t kk - if not mat.is_set: - raise_error_CSR(-3) - elif out.is_set: - raise_error_CSR(-2) - init_CSR(out, mat.nnz, mat.nrows, mat.nrows, mat.max_length) - # We cannot use memcpy here since there are issues with - # doing so on Win with the GCC compiler - for kk in range(mat.nnz): - out.data[kk] = mat.data[kk] - out.indices[kk] = mat.indices[kk] - for kk in range(mat.nrows+1): - out.indptr[kk] = mat.indptr[kk] - -@cython.boundscheck(False) -@cython.wraparound(False) -cdef void free_CSR(CSR_Matrix * mat): - """ - Manually free CSR_Matrix data structures if - data is not locked by NumPy. - """ - if not mat.numpy_lock and mat.is_set: - if mat.data != NULL: - PyDataMem_FREE(mat.data) - if mat.indices != NULL: - PyDataMem_FREE(mat.indices) - if mat.indptr != NULL: - PyDataMem_FREE(mat.indptr) - mat.is_set = 0 - else: - raise_error_CSR(-2) - -@cython.boundscheck(False) -@cython.wraparound(False) -cdef void shorten_CSR(CSR_Matrix * mat, int N): - """ - Shortends the length of CSR data and indices arrays. - """ - if (not mat.numpy_lock) and mat.is_set: - mat.data = PyDataMem_RENEW(mat.data, N * sizeof(double complex)) - mat.indices = PyDataMem_RENEW(mat.indices, N * sizeof(int)) - mat.nnz = N - else: - if mat.numpy_lock: - raise_error_CSR(-4, mat) - elif not mat.is_set: - raise_error_CSR(-3, mat) - - -@cython.boundscheck(False) -@cython.wraparound(False) -cdef object CSR_to_scipy(CSR_Matrix * mat): - """ - Converts a CSR_Matrix struct to a SciPy csr_matrix class object. - The NumPy arrays are generated from the pointers, and the lifetime - of the pointer memory is tied to that of the NumPy array - (i.e. automatic garbage cleanup.) - - Parameters - ---------- - mat : CSR_Matrix * - Pointer to CSR_Matrix. - """ - cdef np.npy_intp dat_len, ptr_len - cdef np.ndarray[complex, ndim=1] _data - cdef np.ndarray[int, ndim=1] _ind, _ptr - if (not mat.numpy_lock) and mat.is_set: - dat_len = mat.nnz - ptr_len = mat.nrows+1 - _data = np.PyArray_SimpleNewFromData(1, &dat_len, np.NPY_COMPLEX128, mat.data) - PyArray_ENABLEFLAGS(_data, np.NPY_OWNDATA) - - _ind = np.PyArray_SimpleNewFromData(1, &dat_len, np.NPY_INT32, mat.indices) - PyArray_ENABLEFLAGS(_ind, np.NPY_OWNDATA) - - _ptr = np.PyArray_SimpleNewFromData(1, &ptr_len, np.NPY_INT32, mat.indptr) - PyArray_ENABLEFLAGS(_ptr, np.NPY_OWNDATA) - mat.numpy_lock = 1 - return fast_csr_matrix((_data, _ind, _ptr), shape=(mat.nrows,mat.ncols)) - else: - if mat.numpy_lock: - raise_error_CSR(-4) - elif not mat.is_set: - raise_error_CSR(-3) - - -@cython.boundscheck(False) -@cython.wraparound(False) -cdef int ind_sort(data_ind_pair x, data_ind_pair y): - return x.ind < y.ind - - -@cython.boundscheck(False) -@cython.wraparound(False) -cdef void sort_indices(CSR_Matrix * mat): - """ - Sorts the indices of a CSR_Matrix inplace. - """ - cdef size_t ii, jj - cdef vector[data_ind_pair] pairs - cdef cfptr cfptr_ = &ind_sort - cdef int row_start, row_end, length - - for ii in range(mat.nrows): - row_start = mat.indptr[ii] - row_end = mat.indptr[ii+1] - length = row_end - row_start - pairs.resize(length) - - for jj in range(length): - pairs[jj].data = mat.data[row_start+jj] - pairs[jj].ind = mat.indices[row_start+jj] - - sort(pairs.begin(),pairs.end(),cfptr_) - - for jj in range(length): - mat.data[row_start+jj] = pairs[jj].data - mat.indices[row_start+jj] = pairs[jj].ind \ No newline at end of file diff --git a/qiskit/providers/aer/pulse/qutip_extra_lite/cy/sparse_structs.pxd b/qiskit/providers/aer/pulse/qutip_extra_lite/cy/sparse_structs.pxd deleted file mode 100644 index 48e96cbca5..0000000000 --- a/qiskit/providers/aer/pulse/qutip_extra_lite/cy/sparse_structs.pxd +++ /dev/null @@ -1,47 +0,0 @@ -#!python -#cython: language_level=3 -# This file is part of QuTiP: Quantum Toolbox in Python. -# -# Copyright (c) 2011 and later, The QuTiP Project. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# 3. Neither the name of the QuTiP: Quantum Toolbox in Python nor the names -# of its contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -############################################################################### - -cdef struct _csr_mat: - double complex * data - int * indices - int * indptr - int nnz - int nrows - int ncols - int is_set - int max_length - int numpy_lock - -ctypedef _csr_mat CSR_Matrix \ No newline at end of file diff --git a/qiskit/providers/aer/pulse/qutip_extra_lite/cy/sparse_utils.pyx b/qiskit/providers/aer/pulse/qutip_extra_lite/cy/sparse_utils.pyx deleted file mode 100644 index 57bcf6109d..0000000000 --- a/qiskit/providers/aer/pulse/qutip_extra_lite/cy/sparse_utils.pyx +++ /dev/null @@ -1,379 +0,0 @@ -#!python -#cython: language_level=3 -# This file is part of QuTiP: Quantum Toolbox in Python. -# -# Copyright (c) 2011 and later, Paul D. Nation and Robert J. Johansson. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# 3. Neither the name of the QuTiP: Quantum Toolbox in Python nor the names -# of its contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -############################################################################### -import numpy as np -from ..fastsparse import fast_csr_matrix -cimport numpy as cnp -from libc.math cimport abs, fabs, sqrt -from libcpp cimport bool -cimport cython -cnp.import_array() -from libc.string cimport memset - -cdef extern from "numpy/arrayobject.h" nogil: - void PyArray_ENABLEFLAGS(cnp.ndarray arr, int flags) - void PyDataMem_FREE(void * ptr) - void PyDataMem_RENEW(void * ptr, size_t size) - void PyDataMem_NEW(size_t size) - - -cdef extern from "" namespace "std" nogil: - double abs(double complex x) - double real(double complex x) - double imag(double complex x) - -cdef extern from "" namespace "std" nogil: - double cabs "abs" (double complex x) - -cdef inline int int_max(int x, int y): - return x ^ ((x ^ y) & -(x < y)) - -include "parameters.pxi" - -@cython.boundscheck(False) -@cython.wraparound(False) -def _sparse_bandwidth( - int[::1] idx, - int[::1] ptr, - int nrows): - """ - Calculates the max (mb), lower(lb), and upper(ub) bandwidths of a - csr_matrix. - """ - cdef int ldist - cdef int lb = -nrows - cdef int ub = -nrows - cdef int mb = 0 - cdef size_t ii, jj - - for ii in range(nrows): - for jj in range(ptr[ii], ptr[ii + 1]): - ldist = ii - idx[jj] - lb = int_max(lb, ldist) - ub = int_max(ub, -ldist) - mb = int_max(mb, ub + lb + 1) - - return mb, lb, ub - - -@cython.boundscheck(False) -@cython.wraparound(False) -def _sparse_profile(int[::1] idx, - int[::1] ptr, - int nrows): - cdef int ii, jj, temp, ldist=0 - cdef LTYPE_t pro = 0 - for ii in range(nrows): - temp = 0 - for jj in range(ptr[ii], ptr[ii + 1]): - ldist = idx[jj] - ii - temp = int_max(temp, ldist) - pro += temp - return pro - - -@cython.boundscheck(False) -@cython.wraparound(False) -def _sparse_permute( - cnp.ndarray[cython.numeric, ndim=1] data, - int[::1] idx, - int[::1] ptr, - int nrows, - int ncols, - cnp.ndarray[ITYPE_t, ndim=1] rperm, - cnp.ndarray[ITYPE_t, ndim=1] cperm, - int flag): - """ - Permutes the rows and columns of a sparse CSR or CSC matrix according to - the permutation arrays rperm and cperm, respectively. - Here, the permutation arrays specify the new order of the rows and columns. - i.e. [0,1,2,3,4] -> [3,0,4,1,2]. - """ - cdef int ii, jj, kk, k0, nnz - cdef cnp.ndarray[cython.numeric] new_data = np.zeros_like(data) - cdef cnp.ndarray[ITYPE_t] new_idx = np.zeros_like(idx) - cdef cnp.ndarray[ITYPE_t] new_ptr = np.zeros_like(ptr) - cdef cnp.ndarray[ITYPE_t] perm_r - cdef cnp.ndarray[ITYPE_t] perm_c - cdef cnp.ndarray[ITYPE_t] inds - - if flag == 0: # CSR matrix - if rperm.shape[0] != 0: - inds = np.argsort(rperm).astype(ITYPE) - perm_r = np.arange(rperm.shape[0], dtype=ITYPE)[inds] - - for jj in range(nrows): - ii = perm_r[jj] - new_ptr[ii + 1] = ptr[jj + 1] - ptr[jj] - - for jj in range(nrows): - new_ptr[jj + 1] = new_ptr[jj+1] + new_ptr[jj] - - for jj in range(nrows): - k0 = new_ptr[perm_r[jj]] - for kk in range(ptr[jj], ptr[jj + 1]): - new_idx[k0] = idx[kk] - new_data[k0] = data[kk] - k0 = k0 + 1 - - if cperm.shape[0] != 0: - inds = np.argsort(cperm).astype(ITYPE) - perm_c = np.arange(cperm.shape[0], dtype=ITYPE)[inds] - nnz = new_ptr[new_ptr.shape[0] - 1] - for jj in range(nnz): - new_idx[jj] = perm_c[new_idx[jj]] - - elif flag == 1: # CSC matrix - if cperm.shape[0] != 0: - inds = np.argsort(cperm).astype(ITYPE) - perm_c = np.arange(cperm.shape[0], dtype=ITYPE)[inds] - - for jj in range(ncols): - ii = perm_c[jj] - new_ptr[ii + 1] = ptr[jj + 1] - ptr[jj] - - for jj in range(ncols): - new_ptr[jj + 1] = new_ptr[jj + 1] + new_ptr[jj] - - for jj in range(ncols): - k0 = new_ptr[perm_c[jj]] - for kk in range(ptr[jj], ptr[jj + 1]): - new_idx[k0] = idx[kk] - new_data[k0] = data[kk] - k0 = k0 + 1 - - if rperm.shape[0] != 0: - inds = np.argsort(rperm).astype(ITYPE) - perm_r = np.arange(rperm.shape[0], dtype=ITYPE)[inds] - nnz = new_ptr[new_ptr.shape[0] - 1] - for jj in range(nnz): - new_idx[jj] = perm_r[new_idx[jj]] - - return new_data, new_idx, new_ptr - - -@cython.boundscheck(False) -@cython.wraparound(False) -def _sparse_reverse_permute( - cnp.ndarray[cython.numeric, ndim=1] data, - int[::1] idx, - int[::1] ptr, - int nrows, - int ncols, - cnp.ndarray[ITYPE_t, ndim=1] rperm, - cnp.ndarray[ITYPE_t, ndim=1] cperm, - int flag): - """ - Reverse permutes the rows and columns of a sparse CSR or CSC matrix - according to the original permutation arrays rperm and cperm, respectively. - """ - cdef int ii, jj, kk, k0, nnz - cdef cnp.ndarray[cython.numeric, ndim=1] new_data = np.zeros_like(data) - cdef cnp.ndarray[ITYPE_t, ndim=1] new_idx = np.zeros_like(idx) - cdef cnp.ndarray[ITYPE_t, ndim=1] new_ptr = np.zeros_like(ptr) - - if flag == 0: # CSR matrix - if rperm.shape[0] != 0: - for jj in range(nrows): - ii = rperm[jj] - new_ptr[ii + 1] = ptr[jj + 1] - ptr[jj] - - for jj in range(nrows): - new_ptr[jj + 1] = new_ptr[jj + 1] + new_ptr[jj] - - for jj in range(nrows): - k0 = new_ptr[rperm[jj]] - for kk in range(ptr[jj], ptr[jj + 1]): - new_idx[k0] = idx[kk] - new_data[k0] = data[kk] - k0 = k0 + 1 - - if cperm.shape[0] > 0: - nnz = new_ptr[new_ptr.shape[0] - 1] - for jj in range(nnz): - new_idx[jj] = cperm[new_idx[jj]] - - if flag == 1: # CSC matrix - if cperm.shape[0] != 0: - for jj in range(ncols): - ii = cperm[jj] - new_ptr[ii + 1] = ptr[jj + 1] - ptr[jj] - - for jj in range(ncols): - new_ptr[jj + 1] = new_ptr[jj + 1] + new_ptr[jj] - - for jj in range(ncols): - k0 = new_ptr[cperm[jj]] - for kk in range(ptr[jj], ptr[jj + 1]): - new_idx[k0] = idx[kk] - new_data[k0] = data[kk] - k0 = k0 + 1 - - if cperm.shape[0] != 0: - nnz = new_ptr[new_ptr.shape[0] - 1] - for jj in range(nnz): - new_idx[jj] = rperm[new_idx[jj]] - - return new_data, new_idx, new_ptr - - -@cython.boundscheck(False) -@cython.wraparound(False) -def _isdiag(int[::1] idx, - int[::1] ptr, - int nrows): - - cdef int row, num_elems - for row in range(nrows): - num_elems = ptr[row+1] - ptr[row] - if num_elems > 1: - return 0 - elif num_elems == 1: - if idx[ptr[row]] != row: - return 0 - return 1 - - -@cython.boundscheck(False) -@cython.wraparound(False) -cpdef cnp.ndarray[complex, ndim=1, mode='c'] _csr_get_diag(complex[::1] data, - int[::1] idx, int[::1] ptr, int k=0): - - cdef size_t row, jj - cdef int num_rows = ptr.shape[0]-1 - cdef int abs_k = abs(k) - cdef int start, stop - cdef cnp.ndarray[complex, ndim=1, mode='c'] out = np.zeros(num_rows-abs_k, dtype=complex) - - if k >= 0: - start = 0 - stop = num_rows-abs_k - else: #k < 0 - start = abs_k - stop = num_rows - - for row in range(start, stop): - for jj in range(ptr[row], ptr[row+1]): - if idx[jj]-k == row: - out[row-start] = data[jj] - break - return out - - -@cython.boundscheck(False) -@cython.wraparound(False) -@cython.cdivision(True) -def unit_row_norm(complex[::1] data, int[::1] ptr, int nrows): - cdef size_t row, ii - cdef double total - for row in range(nrows): - total = 0 - for ii in range(ptr[row], ptr[row+1]): - total += real(data[ii]) * real(data[ii]) + imag(data[ii]) * imag(data[ii]) - total = sqrt(total) - for ii in range(ptr[row], ptr[row+1]): - data[ii] /= total - - - -@cython.boundscheck(False) -@cython.wraparound(False) -cpdef double zcsr_one_norm(complex[::1] data, int[::1] ind, int[::1] ptr, - int nrows, int ncols): - - cdef int k - cdef size_t ii, jj - cdef double * col_sum = PyDataMem_NEW(ncols * sizeof(double)) - cdef double max_col = 0 - - memset(&col_sum[0],0,ncols * sizeof(double)) - for ii in range(nrows): - for jj in range(ptr[ii], ptr[ii+1]): - k = ind[jj] - col_sum[k] += cabs(data[jj]) - for ii in range(ncols): - if col_sum[ii] > max_col: - max_col = col_sum[ii] - PyDataMem_FREE(col_sum) - return max_col - - -@cython.boundscheck(False) -@cython.wraparound(False) -cpdef double zcsr_inf_norm(complex[::1] data, int[::1] ind, int[::1] ptr, - int nrows, int ncols): - - cdef int k - cdef size_t ii, jj - cdef double * row_sum = PyDataMem_NEW(nrows * sizeof(double)) - cdef double max_row = 0 - - memset(&row_sum[0],0,nrows * sizeof(double)) - for ii in range(nrows): - for jj in range(ptr[ii], ptr[ii+1]): - row_sum[ii] += cabs(data[jj]) - for ii in range(nrows): - if row_sum[ii] > max_row: - max_row = row_sum[ii] - PyDataMem_FREE(row_sum) - return max_row - - -@cython.boundscheck(False) -@cython.wraparound(False) -cpdef bool cy_tidyup(complex[::1] data, double atol, unsigned int nnz): - """ - Performs an in-place tidyup of CSR matrix data - """ - cdef size_t kk - cdef double re, im - cdef bool re_flag, im_flag, out_flag = 0 - for kk in range(nnz): - re_flag = 0 - im_flag = 0 - re = real(data[kk]) - im = imag(data[kk]) - if fabs(re) < atol: - re = 0 - re_flag = 1 - if fabs(im) < atol: - im = 0 - im_flag = 1 - - if re_flag or im_flag: - data[kk] = re + 1j*im - - if re_flag and im_flag: - out_flag = 1 - return out_flag diff --git a/qiskit/providers/aer/pulse/qutip_extra_lite/cy/spconvert.pxd b/qiskit/providers/aer/pulse/qutip_extra_lite/cy/spconvert.pxd deleted file mode 100644 index ea64bed657..0000000000 --- a/qiskit/providers/aer/pulse/qutip_extra_lite/cy/spconvert.pxd +++ /dev/null @@ -1,39 +0,0 @@ -#!python -#cython: language_level=3 -# This file is part of QuTiP: Quantum Toolbox in Python. -# -# Copyright (c) 2011 and later, The QuTiP Project. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# 3. Neither the name of the QuTiP: Quantum Toolbox in Python nor the names -# of its contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -############################################################################### - -from .sparse_structs cimport CSR_Matrix - -cdef void fdense2D_to_CSR(complex[::1, :] mat, CSR_Matrix * out, - unsigned int nrows, unsigned int ncols) diff --git a/qiskit/providers/aer/pulse/qutip_extra_lite/cy/spconvert.pyx b/qiskit/providers/aer/pulse/qutip_extra_lite/cy/spconvert.pyx deleted file mode 100644 index 147df97c29..0000000000 --- a/qiskit/providers/aer/pulse/qutip_extra_lite/cy/spconvert.pyx +++ /dev/null @@ -1,303 +0,0 @@ -#!python -#cython: language_level=3 -# This file is part of QuTiP: Quantum Toolbox in Python. -# -# Copyright (c) 2011 and later, The QuTiP Project. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# 3. Neither the name of the QuTiP: Quantum Toolbox in Python nor the names -# of its contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -############################################################################### -import numpy as np -from ..fastsparse import fast_csr_matrix -cimport numpy as cnp -cimport cython -from libc.stdlib cimport div, malloc, free - -cdef extern from "stdlib.h": - ctypedef struct div_t: - int quot - int rem - -include "sparse_routines.pxi" - -@cython.boundscheck(False) -@cython.wraparound(False) -def arr_coo2fast(complex[::1] data, int[::1] rows, int[::1] cols, int nrows, int ncols): - """ - Converts a set of ndarrays (data, rows, cols) that specify a COO sparse matrix - to CSR format. - """ - cdef int nnz = data.shape[0] - cdef COO_Matrix mat - mat.data = &data[0] - mat.rows = &rows[0] - mat.cols = &cols[0] - mat.nrows = nrows - mat.ncols = ncols - mat.nnz = nnz - mat.is_set = 1 - mat.max_length = nnz - - cdef CSR_Matrix out - COO_to_CSR(&out, &mat) - return CSR_to_scipy(&out) - - -@cython.boundscheck(False) -@cython.wraparound(False) -def dense2D_to_fastcsr_cmode(complex[:, ::1] mat, int nrows, int ncols): - """ - Converts a dense c-mode complex ndarray to a sparse CSR matrix. - - Parameters - ---------- - mat : ndarray - Input complex ndarray - nrows : int - Number of rows in matrix. - ncols : int - Number of cols in matrix. - - Returns - ------- - out : fast_csr_matrix - Output matrix in CSR format. - """ - cdef int nnz = 0 - cdef size_t ii, jj - cdef np.ndarray[complex, ndim=1, mode='c'] data = np.zeros(nrows*ncols, dtype=complex) - cdef np.ndarray[int, ndim=1, mode='c'] ind = np.zeros(nrows*ncols, dtype=np.int32) - cdef np.ndarray[int, ndim=1, mode='c'] ptr = np.zeros(nrows+1, dtype=np.int32) - - for ii in range(nrows): - for jj in range(ncols): - if mat[ii,jj] != 0: - ind[nnz] = jj - data[nnz] = mat[ii,jj] - nnz += 1 - ptr[ii+1] = nnz - - if nnz < (nrows*ncols): - return fast_csr_matrix((data[:nnz], ind[:nnz], ptr), shape=(nrows,ncols)) - else: - return fast_csr_matrix((data, ind, ptr), shape=(nrows,ncols)) - - -@cython.boundscheck(False) -@cython.wraparound(False) -def dense1D_to_fastcsr_ket(complex[::1] vec): - """ - Converts a dense c-mode complex ndarray to a sparse CSR matrix. - - Parameters - ---------- - mat : ndarray - Input complex ndarray - - Returns - ------- - out : fast_csr_matrix - Output matrix in CSR format. - """ - cdef int nnz = 0 - cdef size_t ii, nrows = vec.shape[0] - cdef np.ndarray[complex, ndim=1, mode='c'] data = np.zeros(nrows, dtype=complex) - cdef np.ndarray[int, ndim=1, mode='c'] ind = np.zeros(nrows, dtype=np.int32) - cdef np.ndarray[int, ndim=1, mode='c'] ptr = np.zeros(nrows+1, dtype=np.int32) - - for ii in range(nrows): - if vec[ii] != 0: - data[nnz] = vec[ii] - nnz += 1 - ptr[ii+1] = nnz - - if nnz < (nrows): - return fast_csr_matrix((data[:nnz], ind[:nnz], ptr), shape=(nrows,1)) - else: - return fast_csr_matrix((data, ind, ptr), shape=(nrows,1)) - - -@cython.boundscheck(False) -@cython.wraparound(False) -cdef void fdense2D_to_CSR(complex[::1, :] mat, CSR_Matrix * out, - unsigned int nrows, unsigned int ncols): - """ - Converts a dense complex ndarray to a CSR matrix struct. - - Parameters - ---------- - mat : ndarray - Input complex ndarray - nrows : int - Number of rows in matrix. - ncols : int - Number of cols in matrix. - - Returns - ------- - out : CSR_Matrix - Output matrix as CSR struct. - """ - cdef int nnz = 0 - cdef size_t ii, jj - init_CSR(out, nrows*ncols, nrows, ncols, nrows*ncols) - - for ii in range(nrows): - for jj in range(ncols): - if mat[ii,jj] != 0: - out.indices[nnz] = jj - out.data[nnz] = mat[ii,jj] - nnz += 1 - out.indptr[ii+1] = nnz - - if nnz < (nrows*ncols): - shorten_CSR(out, nnz) - - -@cython.boundscheck(False) -@cython.wraparound(False) -def dense2D_to_fastcsr_fmode(complex[::1, :] mat, int nrows, int ncols): - """ - Converts a dense fortran-mode complex ndarray to a sparse CSR matrix. - - Parameters - ---------- - mat : ndarray - Input complex ndarray - nrows : int - Number of rows in matrix. - ncols : int - Number of cols in matrix. - - Returns - ------- - out : fast_csr_matrix - Output matrix in CSR format. - """ - cdef int nnz = 0 - cdef size_t ii, jj - cdef np.ndarray[complex, ndim=1, mode='c'] data = np.zeros(nrows*ncols, dtype=complex) - cdef np.ndarray[int, ndim=1, mode='c'] ind = np.zeros(nrows*ncols, dtype=np.int32) - cdef np.ndarray[int, ndim=1, mode='c'] ptr = np.zeros(nrows+1, dtype=np.int32) - - for ii in range(nrows): - for jj in range(ncols): - if mat[ii,jj] != 0: - ind[nnz] = jj - data[nnz] = mat[ii,jj] - nnz += 1 - ptr[ii+1] = nnz - - if nnz < (nrows*ncols): - return fast_csr_matrix((data[:nnz], ind[:nnz], ptr), shape=(nrows,ncols)) - else: - return fast_csr_matrix((data, ind, ptr), shape=(nrows,ncols)) - - - -@cython.boundscheck(False) -@cython.wraparound(False) -def zcsr_reshape(object A not None, int new_rows, int new_cols): - """ - Reshapes a complex CSR matrix. - - Parameters - ---------- - A : fast_csr_matrix - Input CSR matrix. - new_rows : int - Number of rows in reshaped matrix. - new_cols : int - Number of cols in reshaped matrix. - - Returns - ------- - out : fast_csr_matrix - Reshaped CSR matrix. - - Notes - ----- - This routine does not need to make a temp. copy of the matrix. - """ - cdef CSR_Matrix inmat = CSR_from_scipy(A) - cdef COO_Matrix mat - CSR_to_COO(&mat, &inmat) - cdef CSR_Matrix out - cdef div_t new_inds - cdef size_t kk - - if (mat.nrows * mat.ncols) != (new_rows * new_cols): - raise Exception('Total size of array must be unchanged.') - - for kk in range(mat.nnz): - new_inds = div(mat.ncols*mat.rows[kk]+mat.cols[kk], new_cols) - mat.rows[kk] = new_inds.quot - mat.cols[kk] = new_inds.rem - - mat.nrows = new_rows - mat.ncols = new_cols - - COO_to_CSR_inplace(&out, &mat) - sort_indices(&out) - return CSR_to_scipy(&out) - - -@cython.boundscheck(False) -@cython.wraparound(False) -@cython.cdivision(True) -def cy_index_permute(int [::1] idx_arr, - int [::1] dims, - int [::1] order): - - cdef int ndims = dims.shape[0] - cdef int ii, n, dim, idx, orderr - - #the fastest way to allocate memory for a temporary array - cdef int * multi_idx = malloc(sizeof(int) * ndims) - - try: - for ii from 0 <= ii < idx_arr.shape[0]: - idx = idx_arr[ii] - - #First, decompose long index into multi-index - for n from ndims > n >= 0: - dim = dims[n] - multi_idx[n] = idx % dim - idx = idx // dim - - #Finally, assemble new long index from reordered multi-index - dim = 1 - idx = 0 - for n from ndims > n >= 0: - orderr = order[n] - idx += multi_idx[orderr] * dim - dim *= dims[orderr] - - idx_arr[ii] = idx - finally: - free(multi_idx) diff --git a/qiskit/providers/aer/pulse/qutip_extra_lite/cy/spmatfuncs.pxd b/qiskit/providers/aer/pulse/qutip_extra_lite/cy/spmatfuncs.pxd deleted file mode 100644 index 8d31956057..0000000000 --- a/qiskit/providers/aer/pulse/qutip_extra_lite/cy/spmatfuncs.pxd +++ /dev/null @@ -1,49 +0,0 @@ -#!python -#cython: language_level=3 -# This file is part of QuTiP: Quantum Toolbox in Python. -# -# Copyright (c) 2011 and later, Paul D. Nation and Robert J. Johansson. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# 3. Neither the name of the QuTiP: Quantum Toolbox in Python nor the names -# of its contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -############################################################################### - -cimport numpy as cnp -cimport cython -from libcpp cimport bool - -include "parameters.pxi" - -cpdef cnp.ndarray[CTYPE_t, ndim=1, mode="c"] spmv_csr(complex[::1] data, - int[::1] ind, int[::1] ptr, complex[::1] vec) - -cpdef cy_expect_psi_csr(complex[::1] data, - int[::1] ind, - int[::1] ptr, - complex[::1] vec, - bool isherm) \ No newline at end of file diff --git a/qiskit/providers/aer/pulse/qutip_extra_lite/cy/spmatfuncs.pyx b/qiskit/providers/aer/pulse/qutip_extra_lite/cy/spmatfuncs.pyx deleted file mode 100644 index f3c6d60f81..0000000000 --- a/qiskit/providers/aer/pulse/qutip_extra_lite/cy/spmatfuncs.pyx +++ /dev/null @@ -1,100 +0,0 @@ -#!python -#cython: language_level=3 -# This file is part of QuTiP: Quantum Toolbox in Python. -# -# Copyright (c) 2011 and later, Paul D. Nation and Robert J. Johansson. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# 3. Neither the name of the QuTiP: Quantum Toolbox in Python nor the names -# of its contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -############################################################################### -import numpy as np -cimport numpy as cnp -cimport cython -cimport libc.math -from libcpp cimport bool - -cdef extern from "src/zspmv.hpp" nogil: - void zspmvpy(double complex *data, int *ind, int *ptr, double complex *vec, - double complex a, double complex *out, int nrows) - -include "complex_math.pxi" - -@cython.boundscheck(False) -@cython.wraparound(False) -cpdef cnp.ndarray[complex, ndim=1, mode="c"] spmv_csr(complex[::1] data, - int[::1] ind, int[::1] ptr, complex[::1] vec): - """ - Sparse matrix, dense vector multiplication. - Here the vector is assumed to have one-dimension. - Matrix must be in CSR format and have complex entries. - - Parameters - ---------- - data : array - Data for sparse matrix. - idx : array - Indices for sparse matrix data. - ptr : array - Pointers for sparse matrix data. - vec : array - Dense vector for multiplication. Must be one-dimensional. - - Returns - ------- - out : array - Returns dense array. - - """ - cdef unsigned int num_rows = ptr.shape[0] - 1 - cdef cnp.ndarray[complex, ndim=1, mode="c"] out = np.zeros((num_rows), dtype=np.complex) - zspmvpy(&data[0], &ind[0], &ptr[0], &vec[0], 1.0, &out[0], num_rows) - return out - -@cython.boundscheck(False) -@cython.wraparound(False) -cpdef cy_expect_psi_csr(complex[::1] data, - int[::1] ind, - int[::1] ptr, - complex[::1] vec, - bool isherm): - - cdef size_t row, jj - cdef int nrows = vec.shape[0] - cdef complex expt = 0, temp, cval - - for row in range(nrows): - cval = conj(vec[row]) - temp = 0 - for jj in range(ptr[row], ptr[row+1]): - temp += data[jj]*vec[ind[jj]] - expt += cval*temp - - if isherm : - return real(expt) - else: - return expt \ No newline at end of file diff --git a/qiskit/providers/aer/pulse/qutip_extra_lite/cy/spmath.pyx b/qiskit/providers/aer/pulse/qutip_extra_lite/cy/spmath.pyx deleted file mode 100644 index 30938cea30..0000000000 --- a/qiskit/providers/aer/pulse/qutip_extra_lite/cy/spmath.pyx +++ /dev/null @@ -1,423 +0,0 @@ -#!python -#cython: language_level=3 -# This file is part of QuTiP: Quantum Toolbox in Python. -# -# Copyright (c) 2011 and later, The QuTiP Project. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# 3. Neither the name of the QuTiP: Quantum Toolbox in Python nor the names -# of its contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -############################################################################### -import numpy as np -cimport numpy as cnp -cimport cython -from libcpp cimport bool -from libc.string cimport memset - -cdef extern from "" namespace "std" nogil: - double complex conj(double complex x) - double real(double complex) - double imag(double complex) - double abs(double complex) - -include "sparse_routines.pxi" - -@cython.boundscheck(False) -@cython.wraparound(False) -def zcsr_mult(object A, object B, int sorted = 1): - - cdef complex [::1] dataA = A.data - cdef int[::1] indsA = A.indices - cdef int[::1] indptrA = A.indptr - cdef int Annz = A.nnz - - cdef complex [::1] dataB = B.data - cdef int[::1] indsB = B.indices - cdef int[::1] indptrB = B.indptr - cdef int Bnnz = B.nnz - - cdef int nrows = A.shape[0] - cdef int ncols = B.shape[1] - - #Both matrices are zero mats - if Annz == 0 or Bnnz == 0: - return fast_csr_matrix(shape=(nrows,ncols)) - - cdef int nnz - cdef CSR_Matrix out - - nnz = _zcsr_mult_pass1(&dataA[0], &indsA[0], &indptrA[0], - &dataB[0], &indsB[0], &indptrB[0], - nrows, ncols) - - if nnz == 0: - return fast_csr_matrix(shape=(nrows,ncols)) - - init_CSR(&out, nnz, nrows, ncols) - _zcsr_mult_pass2(&dataA[0], &indsA[0], &indptrA[0], - &dataB[0], &indsB[0], &indptrB[0], - &out, - nrows, ncols) - - #Shorten data and indices if needed - if out.nnz > out.indptr[out.nrows]: - shorten_CSR(&out, out.indptr[out.nrows]) - - if sorted: - sort_indices(&out) - return CSR_to_scipy(&out) - - -@cython.boundscheck(False) -@cython.wraparound(False) -cdef int _zcsr_mult_pass1(double complex * Adata, int * Aind, int * Aptr, - double complex * Bdata, int * Bind, int * Bptr, - int nrows, int ncols) nogil: - - cdef int j, k, nnz = 0 - cdef size_t ii,jj,kk - #Setup mask array - cdef int * mask = PyDataMem_NEW(ncols*sizeof(int)) - for ii in range(ncols): - mask[ii] = -1 - #Pass 1 - for ii in range(nrows): - for jj in range(Aptr[ii], Aptr[ii+1]): - j = Aind[jj] - for kk in range(Bptr[j], Bptr[j+1]): - k = Bind[kk] - if mask[k] != ii: - mask[k] = ii - nnz += 1 - PyDataMem_FREE(mask) - return nnz - - -@cython.boundscheck(False) -@cython.wraparound(False) -cdef void _zcsr_mult_pass2(double complex * Adata, int * Aind, int * Aptr, - double complex * Bdata, int * Bind, int * Bptr, - CSR_Matrix * C, - int nrows, int ncols) nogil: - - cdef int head, length, temp, j, k, nnz = 0 - cdef size_t ii,jj,kk - cdef double complex val - cdef double complex * sums = PyDataMem_NEW(ncols * sizeof(double complex)) - cdef int * nxt = PyDataMem_NEW(ncols*sizeof(int)) - - memset(&sums[0],0,ncols * sizeof(double complex)) - for ii in range(ncols): - nxt[ii] = -1 - - C.indptr[0] = 0 - for ii in range(nrows): - head = -2 - length = 0 - for jj in range(Aptr[ii], Aptr[ii+1]): - j = Aind[jj] - val = Adata[jj] - for kk in range(Bptr[j], Bptr[j+1]): - k = Bind[kk] - sums[k] += val*Bdata[kk] - if nxt[k] == -1: - nxt[k] = head - head = k - length += 1 - - for jj in range(length): - if sums[head] != 0: - C.indices[nnz] = head - C.data[nnz] = sums[head] - nnz += 1 - temp = head - head = nxt[head] - nxt[temp] = -1 - sums[temp] = 0 - - C.indptr[ii+1] = nnz - - #Free temp arrays - PyDataMem_FREE(sums) - PyDataMem_FREE(nxt) - - -@cython.boundscheck(False) -@cython.wraparound(False) -def zcsr_kron(object A, object B): - """ - Computes the kronecker product between two complex - sparse matrices in CSR format. - """ - cdef complex[::1] dataA = A.data - cdef int[::1] indsA = A.indices - cdef int[::1] indptrA = A.indptr - cdef int rowsA = A.shape[0] - cdef int colsA = A.shape[1] - - cdef complex[::1] dataB = B.data - cdef int[::1] indsB = B.indices - cdef int[::1] indptrB = B.indptr - cdef int rowsB = B.shape[0] - cdef int colsB = B.shape[1] - - cdef int out_nnz = _safe_multiply(dataA.shape[0], dataB.shape[0]) - cdef int rows_out = rowsA * rowsB - cdef int cols_out = colsA * colsB - - cdef CSR_Matrix out - init_CSR(&out, out_nnz, rows_out, cols_out) - - _zcsr_kron_core(&dataA[0], &indsA[0], &indptrA[0], - &dataB[0], &indsB[0], &indptrB[0], - &out, - rowsA, rowsB, colsB) - return CSR_to_scipy(&out) - - -@cython.boundscheck(False) -@cython.wraparound(False) -cdef void _zcsr_kron_core(double complex * dataA, int * indsA, int * indptrA, - double complex * dataB, int * indsB, int * indptrB, - CSR_Matrix * out, - int rowsA, int rowsB, int colsB) nogil: - cdef size_t ii, jj, ptrA, ptr - cdef int row = 0 - cdef int ptr_start, ptr_end - cdef int row_startA, row_endA, row_startB, row_endB, distA, distB, ptrB - - for ii in range(rowsA): - row_startA = indptrA[ii] - row_endA = indptrA[ii+1] - distA = row_endA - row_startA - - for jj in range(rowsB): - row_startB = indptrB[jj] - row_endB = indptrB[jj+1] - distB = row_endB - row_startB - - ptr_start = out.indptr[row] - ptr_end = ptr_start + distB - - out.indptr[row+1] = out.indptr[row] + distA * distB - row += 1 - - for ptrA in range(row_startA, row_endA): - ptrB = row_startB - for ptr in range(ptr_start, ptr_end): - out.indices[ptr] = indsA[ptrA] * colsB + indsB[ptrB] - out.data[ptr] = dataA[ptrA] * dataB[ptrB] - ptrB += 1 - - ptr_start += distB - ptr_end += distB - - -@cython.boundscheck(False) -@cython.wraparound(False) -def zcsr_transpose(object A): - """ - Transpose of a sparse matrix in CSR format. - """ - cdef complex[::1] data = A.data - cdef int[::1] ind = A.indices - cdef int[::1] ptr = A.indptr - cdef int nrows = A.shape[0] - cdef int ncols = A.shape[1] - - cdef CSR_Matrix out - init_CSR(&out, data.shape[0], ncols, nrows) - - _zcsr_trans_core(&data[0], &ind[0], &ptr[0], - &out, nrows, ncols) - return CSR_to_scipy(&out) - - -@cython.boundscheck(False) -@cython.wraparound(False) -cdef void _zcsr_trans_core(double complex * data, int * ind, int * ptr, - CSR_Matrix * out, - int nrows, int ncols) nogil: - - cdef int k, nxt - cdef size_t ii, jj - - for ii in range(nrows): - for jj in range(ptr[ii], ptr[ii+1]): - k = ind[jj] + 1 - out.indptr[k] += 1 - - for ii in range(ncols): - out.indptr[ii+1] += out.indptr[ii] - - for ii in range(nrows): - for jj in range(ptr[ii], ptr[ii+1]): - k = ind[jj] - nxt = out.indptr[k] - out.data[nxt] = data[jj] - out.indices[nxt] = ii - out.indptr[k] = nxt + 1 - - for ii in range(ncols,0,-1): - out.indptr[ii] = out.indptr[ii-1] - - out.indptr[0] = 0 - - - -@cython.boundscheck(False) -@cython.wraparound(False) -def zcsr_adjoint(object A): - """ - Adjoint of a sparse matrix in CSR format. - """ - cdef complex[::1] data = A.data - cdef int[::1] ind = A.indices - cdef int[::1] ptr = A.indptr - cdef int nrows = A.shape[0] - cdef int ncols = A.shape[1] - - cdef CSR_Matrix out - init_CSR(&out, data.shape[0], ncols, nrows) - - _zcsr_adjoint_core(&data[0], &ind[0], &ptr[0], - &out, nrows, ncols) - return CSR_to_scipy(&out) - - -@cython.boundscheck(False) -@cython.wraparound(False) -cdef void _zcsr_adjoint_core(double complex * data, int * ind, int * ptr, - CSR_Matrix * out, - int nrows, int ncols) nogil: - - cdef int k, nxt - cdef size_t ii, jj - - for ii in range(nrows): - for jj in range(ptr[ii], ptr[ii+1]): - k = ind[jj] + 1 - out.indptr[k] += 1 - - for ii in range(ncols): - out.indptr[ii+1] += out.indptr[ii] - - for ii in range(nrows): - for jj in range(ptr[ii], ptr[ii+1]): - k = ind[jj] - nxt = out.indptr[k] - out.data[nxt] = conj(data[jj]) - out.indices[nxt] = ii - out.indptr[k] = nxt + 1 - - for ii in range(ncols,0,-1): - out.indptr[ii] = out.indptr[ii-1] - - out.indptr[0] = 0 - - -@cython.boundscheck(False) -@cython.wraparound(False) -def zcsr_isherm(object A not None, double tol = 1e-12): - """ - Determines if a given input sparse CSR matrix is Hermitian - to within a specified floating-point tolerance. - - Parameters - ---------- - A : csr_matrix - Input sparse matrix. - tol : float (default is atol from settings) - Desired tolerance value. - - Returns - ------- - isherm : int - One if matrix is Hermitian, zero otherwise. - - Notes - ----- - This implimentation is esentially an adjoint calulation - where the data and indices are not stored, but checked - elementwise to see if they match those of the input matrix. - Thus we do not need to build the actual adjoint. Here we - only need a temp array of output indptr. - """ - cdef complex[::1] data = A.data - cdef int[::1] ind = A.indices - cdef int[::1] ptr = A.indptr - cdef int nrows = A.shape[0] - cdef int ncols = A.shape[1] - - cdef int k, nxt, isherm = 1 - cdef size_t ii, jj - cdef complex tmp, tmp2 - - if nrows != ncols: - return 0 - - cdef int * out_ptr = PyDataMem_NEW( (ncols+1) * sizeof(int)) - - memset(&out_ptr[0],0,(ncols+1) * sizeof(int)) - - for ii in range(nrows): - for jj in range(ptr[ii], ptr[ii+1]): - k = ind[jj] + 1 - out_ptr[k] += 1 - - for ii in range(nrows): - out_ptr[ii+1] += out_ptr[ii] - - for ii in range(nrows): - for jj in range(ptr[ii], ptr[ii+1]): - k = ind[jj] - nxt = out_ptr[k] - out_ptr[k] += 1 - #structure test - if ind[nxt] != ii: - isherm = 0 - break - tmp = conj(data[jj]) - tmp2 = data[nxt] - #data test - if abs(tmp-tmp2) > tol: - isherm = 0 - break - else: - continue - break - - PyDataMem_FREE(out_ptr) - return isherm - -@cython.overflowcheck(True) -cdef _safe_multiply(int A, int B): - """ - Computes A*B and checks for overflow. - """ - cdef int C = A*B - return C \ No newline at end of file diff --git a/qiskit/providers/aer/pulse/qutip_extra_lite/cy/utilities.py b/qiskit/providers/aer/pulse/qutip_extra_lite/cy/utilities.py deleted file mode 100644 index 1c9cd5ffdf..0000000000 --- a/qiskit/providers/aer/pulse/qutip_extra_lite/cy/utilities.py +++ /dev/null @@ -1,72 +0,0 @@ -# -*- coding: utf-8 -*- - -# 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. - -# This file is part of QuTiP: Quantum Toolbox in Python. -# -# Copyright (c) 2011 and later, Paul D. Nation and Robert J. Johansson. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# 3. Neither the name of the QuTiP: Quantum Toolbox in Python nor the names -# of its contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -############################################################################### -# pylint: disable=invalid-name, no-name-in-module, import-error -"""Cython utilities""" -import os - - -def _cython_build_cleanup(tdname, build_dir=None): - """Cleanup cython build files - """ - if build_dir is None: - build_dir = os.path.join(os.path.expanduser('~'), '.pyxbld') - - # Remove tdname.pyx - pyx_file = tdname + ".pyx" - try: - os.remove(pyx_file) - except OSError: - pass - - # Remove temp build files - for dirpath, _, files in os.walk(build_dir): - for file in files: - if file.startswith(tdname): - try: - os.remove(os.path.join(dirpath, file)) - except OSError: - pass diff --git a/qiskit/providers/aer/pulse/qutip_extra_lite/dimensions.py b/qiskit/providers/aer/pulse/qutip_extra_lite/dimensions.py deleted file mode 100644 index 4a6d70c14a..0000000000 --- a/qiskit/providers/aer/pulse/qutip_extra_lite/dimensions.py +++ /dev/null @@ -1,134 +0,0 @@ -# -*- coding: utf-8 -*- - -# This code is part of Qiskit. -# -# (C) Copyright IBM 2018, 2019, 2020. -# -# 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. - -# This file is part of QuTiP: Quantum Toolbox in Python. -# -# Copyright (c) 2011 and later, Paul D. Nation and Robert J. Johansson. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# 3. Neither the name of the QuTiP: Quantum Toolbox in Python nor the names -# of its contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -############################################################################### -# pylint: disable=invalid-name -""" -Internal use module for manipulating dims specifications. -""" - -__all__ = [] -# Everything should be explicitly imported, not made available -# by default. - -import numpy as np - - -def flatten(the_list): - """Flattens a list of lists to the first level. - - Given a list containing a mix of scalars and lists, - flattens down to a list of the scalars within the original - list. - - Args: - the_list (list): Input list - - Returns: - list: Flattened list. - - """ - if not isinstance(the_list, list): - return [the_list] - else: - return sum(map(flatten, the_list), []) - - -def is_scalar(dims): - """ - Returns True if a dims specification is effectively - a scalar (has dimension 1). - """ - return np.prod(flatten(dims)) == 1 - - -def is_vector(dims): - """Is a vector""" - return ( - isinstance(dims, list) and - isinstance(dims[0], (int, np.integer)) - ) - - -def is_vectorized_oper(dims): - """Is a vectorized operator.""" - return ( - isinstance(dims, list) and - isinstance(dims[0], list) - ) - - -# pylint: disable=too-many-return-statements -def type_from_dims(dims, enforce_square=True): - """Get the type of operator from dims structure""" - bra_like, ket_like = map(is_scalar, dims) - - if bra_like: - if is_vector(dims[1]): - return 'bra' - elif is_vectorized_oper(dims[1]): - return 'operator-bra' - - if ket_like: - if is_vector(dims[0]): - return 'ket' - elif is_vectorized_oper(dims[0]): - return 'operator-ket' - - elif is_vector(dims[0]) and (dims[0] == dims[1] or not enforce_square): - return 'oper' - - elif ( - is_vectorized_oper(dims[0]) and - ( - ( - dims[0] == dims[1] and - dims[0][0] == dims[1][0] - ) or not enforce_square - ) - ): - return 'super' - - return 'other' diff --git a/qiskit/providers/aer/pulse/qutip_extra_lite/fastsparse.py b/qiskit/providers/aer/pulse/qutip_extra_lite/fastsparse.py deleted file mode 100644 index e822c1ce7e..0000000000 --- a/qiskit/providers/aer/pulse/qutip_extra_lite/fastsparse.py +++ /dev/null @@ -1,440 +0,0 @@ -# -*- coding: utf-8 -*- - -# This code is part of Qiskit. -# -# (C) Copyright IBM 2018, 2019, 2020. -# -# 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. - -# This file is part of QuTiP: Quantum Toolbox in Python. -# -# Copyright (c) 2011 and later, The QuTiP Project. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# 3. Neither the name of the QuTiP: Quantum Toolbox in Python nor the names -# of its contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -############################################################################### -# pylint: disable=invalid-name - -""" -Module for fast versions of SciPy sparse CSR matrices -""" - -import operator -from warnings import warn -import numpy as np -from scipy.sparse import (_sparsetools, isspmatrix, csr_matrix, dia_matrix) -from scipy.sparse.sputils import (upcast, isdense, isscalarlike, get_index_dtype) -from scipy.sparse.base import SparseEfficiencyWarning - - -class fast_csr_matrix(csr_matrix): - """ - A subclass of scipy.sparse.csr_matrix that skips the data format - checks that are run everytime a new csr_matrix is created. - """ - # pylint: disable=super-init-not-called - def __init__(self, args=None, shape=None, dtype=None, copy=False): - if args is None: # Build zero matrix - if shape is None: - raise Exception('Shape must be given when building zero matrix.') - self.data = np.array([], dtype=complex) - self.indices = np.array([], dtype=np.int32) - self.indptr = np.zeros(shape[0] + 1, dtype=np.int32) - self._shape = tuple(int(s) for s in shape) - - else: - if args[0].shape[0] and args[0].dtype != complex: - raise TypeError('fast_csr_matrix allows only complex data.') - if args[1].shape[0] and args[1].dtype != np.int32: - raise TypeError('fast_csr_matrix allows only int32 indices.') - if args[2].shape[0] and args[1].dtype != np.int32: - raise TypeError('fast_csr_matrix allows only int32 indptr.') - self.data = np.array(args[0], dtype=complex, copy=copy) - self.indices = np.array(args[1], dtype=np.int32, copy=copy) - self.indptr = np.array(args[2], dtype=np.int32, copy=copy) - if shape is None: - self._shape = tuple([len(self.indptr) - 1] * 2) - else: - self._shape = tuple(int(s) for s in shape) - self.dtype = complex - self.maxprint = 50 - self.format = 'csr' - - def _binopt(self, other, op): - """ - Do the binary operation fn to two sparse matrices using - fast_csr_matrix only when other is also a fast_csr_matrix. - """ - # e.g. csr_plus_csr, csr_minus_csr, etc. - if not isinstance(other, fast_csr_matrix): - other = csr_matrix(other) - # e.g. csr_plus_csr, csr_minus_csr, etc. - fn = getattr(_sparsetools, self.format + op + self.format) - - maxnnz = self.nnz + other.nnz - idx_dtype = get_index_dtype((self.indptr, self.indices, - other.indptr, other.indices), - maxval=maxnnz) - indptr = np.empty(self.indptr.shape, dtype=idx_dtype) - indices = np.empty(maxnnz, dtype=idx_dtype) - - bool_ops = ['_ne_', '_lt_', '_gt_', '_le_', '_ge_'] - if op in bool_ops: - data = np.empty(maxnnz, dtype=np.bool_) - else: - data = np.empty(maxnnz, dtype=upcast(self.dtype, other.dtype)) - - fn(self.shape[0], self.shape[1], - np.asarray(self.indptr, dtype=idx_dtype), - np.asarray(self.indices, dtype=idx_dtype), - self.data, - np.asarray(other.indptr, dtype=idx_dtype), - np.asarray(other.indices, dtype=idx_dtype), - other.data, - indptr, indices, data) - - actual_nnz = indptr[-1] - indices = indices[:actual_nnz] - data = data[:actual_nnz] - if actual_nnz < maxnnz // 2: - # too much waste, trim arrays - indices = indices.copy() - data = data.copy() - if isinstance(other, fast_csr_matrix) and (op not in bool_ops): - A = fast_csr_matrix((data, indices, indptr), dtype=data.dtype, shape=self.shape) - else: - A = csr_matrix((data, indices, indptr), dtype=data.dtype, shape=self.shape) - return A - - # pylint: disable=too-many-return-statements - def multiply(self, other): - """Point-wise multiplication by another matrix, vector, or - scalar. - """ - # Scalar multiplication. - if isscalarlike(other): - return self._mul_scalar(other) - # Sparse matrix or vector. - if isspmatrix(other): - if self.shape == other.shape: - if not isinstance(other, fast_csr_matrix): - other = csr_matrix(other) - return self._binopt(other, '_elmul_') - # Single element. - elif other.shape == (1, 1): - return self._mul_scalar(other.toarray()[0, 0]) - elif self.shape == (1, 1): - return other._mul_scalar(self.toarray()[0, 0]) - # A row times a column. - elif self.shape[1] == other.shape[0] and self.shape[1] == 1: - return self._mul_sparse_matrix(other.tocsc()) - elif self.shape[0] == other.shape[1] and self.shape[0] == 1: - return other._mul_sparse_matrix(self.tocsc()) - # Row vector times matrix. other is a row. - elif other.shape[0] == 1 and self.shape[1] == other.shape[1]: - other = dia_matrix((other.toarray().ravel(), [0]), - shape=(other.shape[1], other.shape[1])) - return self._mul_sparse_matrix(other) - # self is a row. - elif self.shape[0] == 1 and self.shape[1] == other.shape[1]: - copy = dia_matrix((self.toarray().ravel(), [0]), - shape=(self.shape[1], self.shape[1])) - return other._mul_sparse_matrix(copy) - # Column vector times matrix. other is a column. - elif other.shape[1] == 1 and self.shape[0] == other.shape[0]: - other = dia_matrix((other.toarray().ravel(), [0]), - shape=(other.shape[0], other.shape[0])) - return other._mul_sparse_matrix(self) - # self is a column. - elif self.shape[1] == 1 and self.shape[0] == other.shape[0]: - copy = dia_matrix((self.toarray().ravel(), [0]), - shape=(self.shape[0], self.shape[0])) - return copy._mul_sparse_matrix(other) - else: - raise ValueError("inconsistent shapes") - # Dense matrix. - if isdense(other): - if self.shape == other.shape: - ret = self.tocoo() - ret.data = np.multiply(ret.data, other[ret.row, ret.col] - ).view(np.ndarray).ravel() - return ret - # Single element. - elif other.size == 1: - return self._mul_scalar(other.flat[0]) - # Anything else. - return np.multiply(self.todense(), other) - - def _mul_sparse_matrix(self, other): - """ - Do the sparse matrix mult returning fast_csr_matrix only - when other is also fast_csr_matrix. - """ - M, _ = self.shape - _, N = other.shape - - major_axis = self._swap((M, N))[0] - if isinstance(other, fast_csr_matrix): - A = zcsr_mult(self, other, sorted=1) - return A - - other = csr_matrix(other) # convert to this format - idx_dtype = get_index_dtype((self.indptr, self.indices, - other.indptr, other.indices), - maxval=M * N) - indptr = np.empty(major_axis + 1, dtype=idx_dtype) - - fn = getattr(_sparsetools, self.format + '_matmat_pass1') - fn(M, N, - np.asarray(self.indptr, dtype=idx_dtype), - np.asarray(self.indices, dtype=idx_dtype), - np.asarray(other.indptr, dtype=idx_dtype), - np.asarray(other.indices, dtype=idx_dtype), - indptr) - - nnz = indptr[-1] - idx_dtype = get_index_dtype((self.indptr, self.indices, - other.indptr, other.indices), - maxval=nnz) - indptr = np.asarray(indptr, dtype=idx_dtype) - indices = np.empty(nnz, dtype=idx_dtype) - data = np.empty(nnz, dtype=upcast(self.dtype, other.dtype)) - - fn = getattr(_sparsetools, self.format + '_matmat_pass2') - fn(M, N, np.asarray(self.indptr, dtype=idx_dtype), - np.asarray(self.indices, dtype=idx_dtype), - self.data, - np.asarray(other.indptr, dtype=idx_dtype), - np.asarray(other.indices, dtype=idx_dtype), - other.data, - indptr, indices, data) - A = csr_matrix((data, indices, indptr), shape=(M, N)) - return A - - def _scalar_binopt(self, other, op): - """Scalar version of self._binopt, for cases in which no new nonzeros - are added. Produces a new spmatrix in canonical form. - """ - self.sum_duplicates() - res = self._with_data(op(self.data, other), copy=True) - res.eliminate_zeros() - return res - - # pylint: disable=too-many-return-statements - def __eq__(self, other): - # Scalar other. - if isscalarlike(other): - if np.isnan(other): - return csr_matrix(self.shape, dtype=np.bool_) - - if other == 0: - warn("Comparing a sparse matrix with 0 using == is inefficient" - ", try using != instead.", SparseEfficiencyWarning) - all_true = _all_true(self.shape) - inv = self._scalar_binopt(other, operator.ne) - return all_true - inv - else: - return self._scalar_binopt(other, operator.eq) - # Dense other. - elif isdense(other): - return self.todense() == other - # Sparse other. - elif isspmatrix(other): - warn("Comparing sparse matrices using == is inefficient, try using" - " != instead.", SparseEfficiencyWarning) - # TODO sparse broadcasting - if self.shape != other.shape: - return False - elif self.format != other.format: - other = other.asformat(self.format) - res = self._binopt(other, '_ne_') - all_true = _all_true(self.shape) - return all_true - res - else: - return False - - # pylint: disable=too-many-return-statements - def __ne__(self, other): - # Scalar other. - if isscalarlike(other): - if np.isnan(other): - warn("Comparing a sparse matrix with nan using != is inefficient", - SparseEfficiencyWarning) - all_true = _all_true(self.shape) - return all_true - elif other != 0: - warn("Comparing a sparse matrix with a nonzero scalar using !=" - " is inefficient, try using == instead.", SparseEfficiencyWarning) - all_true = _all_true(self.shape) - inv = self._scalar_binopt(other, operator.eq) - return all_true - inv - else: - return self._scalar_binopt(other, operator.ne) - # Dense other. - elif isdense(other): - return self.todense() != other - # Sparse other. - elif isspmatrix(other): - # TODO sparse broadcasting - if self.shape != other.shape: - return True - elif self.format != other.format: - other = other.asformat(self.format) - return self._binopt(other, '_ne_') - else: - return True - - def _inequality(self, other, op, op_name, bad_scalar_msg): - # Scalar other. - if isscalarlike(other): - if other == 0 and op_name in ('_le_', '_ge_'): - raise NotImplementedError(" >= and <= don't work with 0.") - - if op(0, other): - warn(bad_scalar_msg, SparseEfficiencyWarning) - other_arr = np.empty(self.shape, dtype=np.result_type(other)) - other_arr.fill(other) - other_arr = csr_matrix(other_arr) - return self._binopt(other_arr, op_name) - else: - return self._scalar_binopt(other, op) - # Dense other. - elif isdense(other): - return op(self.todense(), other) - # Sparse other. - elif isspmatrix(other): - # TODO sparse broadcasting - if self.shape != other.shape: - raise ValueError("inconsistent shapes") - if self.format != other.format: - other = other.asformat(self.format) - if op_name not in ('_ge_', '_le_'): - return self._binopt(other, op_name) - - warn("Comparing sparse matrices using >= and <= is inefficient, " - "using <, >, or !=, instead.", SparseEfficiencyWarning) - all_true = _all_true(self.shape) - res = self._binopt(other, '_gt_' if op_name == '_le_' else '_lt_') - return all_true - res - else: - raise ValueError("Operands could not be compared.") - - def _with_data(self, data, copy=True): - """Returns a matrix with the same sparsity structure as self, - but with different data. By default the structure arrays - (i.e. .indptr and .indices) are copied. - """ - # We need this just in case something like abs(data) gets called - # does nothing if data.dtype is complex. - data = np.asarray(data, dtype=complex) - if copy: - return fast_csr_matrix((data, self.indices.copy(), self.indptr.copy()), - shape=self.shape, dtype=data.dtype) - else: - return fast_csr_matrix((data, self.indices, self.indptr), - shape=self.shape, dtype=data.dtype) - - # pylint: disable=arguments-differ - def transpose(self): - """ - Returns the transpose of the matrix, keeping - it in fast_csr format. - """ - return zcsr_transpose(self) - - def trans(self): - """ - Same as transpose - """ - return zcsr_transpose(self) - - def getH(self): - """ - Returns the conjugate-transpose of the matrix, keeping - it in fast_csr format. - """ - return zcsr_adjoint(self) - - def adjoint(self): - """ - Same as getH - """ - return zcsr_adjoint(self) - - -def csr2fast(A, copy=False): - """Converts a SciPy CSR matrix - to the internal fast version. - - Args: - A (csr_matrx): Input csr_matrix. - copy (bool): Make a copy of the data arrays. - - Returns: - fast_csr: The equivilent fast CSR matrix. - """ - if (not isinstance(A, fast_csr_matrix)) or copy: - # Do not need to do any type checking here - # since fast_csr_matrix does that. - return fast_csr_matrix((A.data, A.indices, A.indptr), - shape=A.shape, copy=copy) - else: - return A - - -def fast_identity(N): - """Generates a sparse identity matrix in - fast_csr format. - """ - data = np.ones(N, dtype=complex) - ind = np.arange(N, dtype=np.int32) - ptr = np.arange(N + 1, dtype=np.int32) - ptr[-1] = N - return fast_csr_matrix((data, ind, ptr), shape=(N, N)) - - -# Convenience functions -# -------------------- -def _all_true(shape): - A = csr_matrix((np.ones(np.prod(shape), dtype=np.bool_), - np.tile(np.arange(shape[1], dtype=np.int32), shape[0]), - np.arange(0, np.prod(shape) + 1, shape[1], dtype=np.int32)), - shape=shape) - return A - - -# Need to do some trailing imports here -# ------------------------------------- -# pylint: disable=no-name-in-module, wrong-import-position, import-error -from .cy.spmath import (zcsr_transpose, zcsr_adjoint, zcsr_mult) diff --git a/qiskit/providers/aer/pulse/qutip_extra_lite/operators.py b/qiskit/providers/aer/pulse/qutip_extra_lite/operators.py deleted file mode 100644 index 7793882422..0000000000 --- a/qiskit/providers/aer/pulse/qutip_extra_lite/operators.py +++ /dev/null @@ -1,457 +0,0 @@ -# -*- coding: utf-8 -*- - -# This code is part of Qiskit. -# -# (C) Copyright IBM 2018, 2019, 2020. -# -# 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. - - -# This file is part of QuTiP: Quantum Toolbox in Python. -# -# Copyright (c) 2011 and later, Paul D. Nation and Robert J. Johansson. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# 3. Neither the name of the QuTiP: Quantum Toolbox in Python nor the names -# of its contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -############################################################################### -# pylint: disable=invalid-name - -""" -This module contains functions for generating Qobj representation of a variety -of commonly occuring quantum operators. -""" - -import numpy as np -from .fastsparse import fast_csr_matrix, fast_identity -from .qobj import Qobj - - -# Spin operators -def jmat(j, *args): - """Higher-order spin operators: - - Args: - j (float): Spin of operator - - args (str): Which operator to return 'x','y','z','+','-'. - If no args given, then output is ['x','y','z'] - - Returns: - Qobj: Requested spin operator(s). - - Raises: - TypeError: Invalid input. - """ - if (np.fix(2 * j) != 2 * j) or (j < 0): - raise TypeError('j must be a non-negative integer or half-integer') - - if not args: - return jmat(j, 'x'), jmat(j, 'y'), jmat(j, 'z') - - if args[0] == '+': - A = _jplus(j) - elif args[0] == '-': - A = _jplus(j).getH() - elif args[0] == 'x': - A = 0.5 * (_jplus(j) + _jplus(j).getH()) - elif args[0] == 'y': - A = -0.5 * 1j * (_jplus(j) - _jplus(j).getH()) - elif args[0] == 'z': - A = _jz(j) - else: - raise TypeError('Invalid type') - - return Qobj(A) - - -def _jplus(j): - """ - Internal functions for generating the data representing the J-plus - operator. - """ - m = np.arange(j, -j - 1, -1, dtype=complex) - data = (np.sqrt(j * (j + 1.0) - (m + 1.0) * m))[1:] - N = m.shape[0] - ind = np.arange(1, N, dtype=np.int32) - ptr = np.array(list(range(N - 1)) + [N - 1] * 2, dtype=np.int32) - ptr[-1] = N - 1 - return fast_csr_matrix((data, ind, ptr), shape=(N, N)) - - -def _jz(j): - """ - Internal functions for generating the data representing the J-z operator. - """ - N = int(2 * j + 1) - data = np.array([j - k for k in range(N) if (j - k) != 0], dtype=complex) - # Even shaped matrix - if N % 2 == 0: - ind = np.arange(N, dtype=np.int32) - ptr = np.arange(N + 1, dtype=np.int32) - ptr[-1] = N - # Odd shaped matrix - else: - j = int(j) - ind = np.array(list(range(j)) + list(range(j + 1, N)), dtype=np.int32) - ptr = np.array(list(range(j + 1)) + list(range(j, N)), dtype=np.int32) - ptr[-1] = N - 1 - return fast_csr_matrix((data, ind, ptr), shape=(N, N)) - - -# -# Spin j operators: -# -def spin_Jx(j): - """Spin-j x operator - - Parameters - ---------- - j : float - Spin of operator - - Returns - ------- - op : Qobj - ``qobj`` representation of the operator. - - """ - return jmat(j, 'x') - - -def spin_Jy(j): - """Spin-j y operator - - Args: - j (float): Spin of operator - - Returns: - Qobj: representation of the operator. - - """ - return jmat(j, 'y') - - -def spin_Jz(j): - """Spin-j z operator - - Args: - j (float): Spin of operator - - Returns: - Qobj: representation of the operator. - - """ - return jmat(j, 'z') - - -def spin_Jm(j): - """Spin-j annihilation operator - - Parameters: - j (float): Spin of operator - - Returns: - Qobj: representation of the operator. - - """ - return jmat(j, '-') - - -def spin_Jp(j): - """Spin-j creation operator - - Args: - j (float): Spin of operator - - Returns: - Qobj: representation of the operator. - - """ - return jmat(j, '+') - - -def spin_J_set(j): - """Set of spin-j operators (x, y, z) - - Args: - j (float): Spin of operators - - Returns: - list: list of ``qobj`` representating of the spin operator. - - """ - return jmat(j) - - -# -# Pauli spin 1/2 operators: -# -def sigmap(): - """Creation operator for Pauli spins. - - Examples - -------- - >>> sigmap() - Quantum object: dims = [[2], [2]], \ -shape = [2, 2], type = oper, isHerm = False - Qobj data = - [[ 0. 1.] - [ 0. 0.]] - - """ - return jmat(1 / 2., '+') - - -def sigmam(): - """Annihilation operator for Pauli spins. - - Examples - -------- - >>> sigmam() - Quantum object: dims = [[2], [2]], \ -shape = [2, 2], type = oper, isHerm = False - Qobj data = - [[ 0. 0.] - [ 1. 0.]] - - """ - return jmat(1 / 2., '-') - - -def sigmax(): - """Pauli spin 1/2 sigma-x operator - - Examples - -------- - >>> sigmax() - Quantum object: dims = [[2], [2]], \ -shape = [2, 2], type = oper, isHerm = False - Qobj data = - [[ 0. 1.] - [ 1. 0.]] - - """ - return 2.0 * jmat(1.0 / 2, 'x') - - -def sigmay(): - """Pauli spin 1/2 sigma-y operator. - - Examples - -------- - >>> sigmay() - Quantum object: dims = [[2], [2]], \ -shape = [2, 2], type = oper, isHerm = True - Qobj data = - [[ 0.+0.j 0.-1.j] - [ 0.+1.j 0.+0.j]] - - """ - return 2.0 * jmat(1.0 / 2, 'y') - - -def sigmaz(): - """Pauli spin 1/2 sigma-z operator. - - Examples - -------- - >>> sigmaz() - Quantum object: dims = [[2], [2]], \ -shape = [2, 2], type = oper, isHerm = True - Qobj data = - [[ 1. 0.] - [ 0. -1.]] - - """ - return 2.0 * jmat(1.0 / 2, 'z') - - -# -# DESTROY returns annihilation operator for N dimensional Hilbert space -# out = destroy(N), N is integer value & N>0 -# -def destroy(N, offset=0): - """Destruction (lowering) operator. - - Args: - N (int): Dimension of Hilbert space. - - offset (int): (default 0) The lowest number state that is included - in the finite number state representation of the operator. - - Returns: - Qobj: Qobj for lowering operator. - - Raises: - ValueError: Invalid input. - - """ - if not isinstance(N, (int, np.integer)): # raise error if N not integer - raise ValueError("Hilbert space dimension must be integer value") - data = np.sqrt(np.arange(offset + 1, N + offset, dtype=complex)) - ind = np.arange(1, N, dtype=np.int32) - ptr = np.arange(N + 1, dtype=np.int32) - ptr[-1] = N - 1 - return Qobj(fast_csr_matrix((data, ind, ptr), shape=(N, N)), isherm=False) - - -# -# create returns creation operator for N dimensional Hilbert space -# out = create(N), N is integer value & N>0 -# -def create(N, offset=0): - """Creation (raising) operator. - - Args: - N (int): Dimension of Hilbert space. - - offset (int): (default 0) The lowest number state that is included - in the finite number state representation of the operator. - - Returns: - Qobj: Qobj for raising operator. - - Raises: - ValueError: Invalid inputs. - - """ - if not isinstance(N, (int, np.integer)): # raise error if N not integer - raise ValueError("Hilbert space dimension must be integer value") - qo = destroy(N, offset=offset) # create operator using destroy function - return qo.dag() - - -# -# QEYE returns identity operator for an N dimensional space -# a = qeye(N), N is integer & N>0 -# -def qeye(N): - """ - Identity operator - - Args: - N (int): Dimension of Hilbert space. If provided as a list of ints, - then the dimension is the product over this list, but the - ``dims`` property of the new Qobj are set to this list. - - Returns: - Qobj: Identity operator Qobj. - - Raises: - ValueError: Invalid input. - """ - N = int(N) - if N < 0: - raise ValueError("N must be integer N>=0") - return Qobj(fast_identity(N), isherm=True, isunitary=True) - - -def identity(N): - """Identity operator. Alternative name to :func:`qeye`. - - Parameters - ---------- - N : int or list of ints - Dimension of Hilbert space. If provided as a list of ints, - then the dimension is the product over this list, but the - ``dims`` property of the new Qobj are set to this list. - - Returns - ------- - oper : qobj - Identity operator Qobj. - """ - return qeye(N) - - -def position(N, offset=0): - """ - Position operator x=1/sqrt(2)*(a+a.dag()) - - Args: - N (int): Number of Fock states in Hilbert space. - - offset (int): (default 0) The lowest number state that is included - in the finite number state representation of the operator. - Returns: - Qobj: Position operator as Qobj. - """ - a = destroy(N, offset=offset) - return 1.0 / np.sqrt(2.0) * (a + a.dag()) - - -def momentum(N, offset=0): - """ - Momentum operator p=-1j/sqrt(2)*(a-a.dag()) - - Args: - N (int): Number of Fock states in Hilbert space. - - offset (int): (default 0) The lowest number state that is - included in the finite number state - representation of the operator. - Returns: - Qobj: Momentum operator as Qobj. - """ - a = destroy(N, offset=offset) - return -1j / np.sqrt(2.0) * (a - a.dag()) - - -# number operator, important! -def num(N, offset=0): - """Quantum object for number operator. - - Args: - N (int): The dimension of the Hilbert space. - - offset(int): (default 0) The lowest number state that is included - in the finite number state representation of the operator. - - Returns: - Qobj: Qobj for number operator. - - """ - if offset == 0: - data = np.arange(1, N, dtype=complex) - ind = np.arange(1, N, dtype=np.int32) - ptr = np.array([0] + list(range(0, N)), dtype=np.int32) - ptr[-1] = N - 1 - else: - data = np.arange(offset, offset + N, dtype=complex) - ind = np.arange(N, dtype=np.int32) - ptr = np.arange(N + 1, dtype=np.int32) - ptr[-1] = N - - return Qobj(fast_csr_matrix((data, ind, ptr), - shape=(N, N)), isherm=True) diff --git a/qiskit/providers/aer/pulse/qutip_extra_lite/qobj.py b/qiskit/providers/aer/pulse/qutip_extra_lite/qobj.py deleted file mode 100644 index b330852f0c..0000000000 --- a/qiskit/providers/aer/pulse/qutip_extra_lite/qobj.py +++ /dev/null @@ -1,768 +0,0 @@ -# -*- coding: utf-8 -*- - -# This code is part of Qiskit. -# -# (C) Copyright IBM 2018, 2019, 2020. -# -# 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. - -# This file is part of QuTiP: Quantum Toolbox in Python. -# -# Copyright (c) 2011 and later, Paul D. Nation and Robert J. Johansson. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# 3. Neither the name of the QuTiP: Quantum Toolbox in Python nor the names -# of its contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -############################################################################### -# pylint: disable=invalid-name, redefined-outer-name, no-name-in-module -# pylint: disable=import-error, unused-import - -"""The Quantum Object (Qobj) class, for representing quantum states and -operators, and related functions. -""" - -__all__ = ['Qobj'] - -import warnings -import builtins - -# import math functions from numpy.math: required for td string evaluation -import numpy as np -import scipy.sparse as sp -import scipy.linalg as la -from qiskit.providers.aer.version import __version__ - -from .dimensions import type_from_dims - -# used in existing functions that break if removed -from .cy.spmath import (zcsr_adjoint, zcsr_isherm) -from .fastsparse import fast_csr_matrix, fast_identity - -# general absolute tolerance -atol = 1e-12 - - -class Qobj(): - """A class for representing quantum objects, such as quantum operators - and states. - - The Qobj class is the QuTiP representation of quantum operators and state - vectors. This class also implements math operations +,-,* between Qobj - instances (and / by a C-number), as well as a collection of common - operator/state operations. The Qobj constructor optionally takes a - dimension ``list`` and/or shape ``list`` as arguments. - - Attributes - ---------- - data : array_like - Sparse matrix characterizing the quantum object. - dims : list - List of dimensions keeping track of the tensor structure. - shape : list - Shape of the underlying `data` array. - type : str - Type of quantum object: 'bra', 'ket', 'oper', 'operator-ket', - 'operator-bra', or 'super'. - superrep : str - Representation used if `type` is 'super'. One of 'super' - (Liouville form) or 'choi' (Choi matrix with tr = dimension). - isherm : bool - Indicates if quantum object represents Hermitian operator. - isunitary : bool - Indictaes if quantum object represents unitary operator. - iscp : bool - Indicates if the quantum object represents a map, and if that map is - completely positive (CP). - ishp : bool - Indicates if the quantum object represents a map, and if that map is - hermicity preserving (HP). - istp : bool - Indicates if the quantum object represents a map, and if that map is - trace preserving (TP). - iscptp : bool - Indicates if the quantum object represents a map that is completely - positive and trace preserving (CPTP). - isket : bool - Indicates if the quantum object represents a ket. - isbra : bool - Indicates if the quantum object represents a bra. - isoper : bool - Indicates if the quantum object represents an operator. - issuper : bool - Indicates if the quantum object represents a superoperator. - isoperket : bool - Indicates if the quantum object represents an operator in column vector - form. - isoperbra : bool - Indicates if the quantum object represents an operator in row vector - form. - - Methods - ------- - copy() - Create copy of Qobj - conj() - Conjugate of quantum object. - cosm() - Cosine of quantum object. - dag() - Adjoint (dagger) of quantum object. - dnorm() - Diamond norm of quantum operator. - dual_chan() - Dual channel of quantum object representing a CP map. - eigenenergies(sparse=False, sort='low', eigvals=0, tol=0, maxiter=100000) - Returns eigenenergies (eigenvalues) of a quantum object. - eigenstates(sparse=False, sort='low', eigvals=0, tol=0, maxiter=100000) - Returns eigenenergies and eigenstates of quantum object. - expm() - Matrix exponential of quantum object. - full(order='C') - Returns dense array of quantum object `data` attribute. - groundstate(sparse=False, tol=0, maxiter=100000) - Returns eigenvalue and eigenket for the groundstate of a quantum - object. - matrix_element(bra, ket) - Returns the matrix element of operator between `bra` and `ket` vectors. - norm(norm='tr', sparse=False, tol=0, maxiter=100000) - Returns norm of a ket or an operator. - proj() - Computes the projector for a ket or bra vector. - sinm() - Sine of quantum object. - sqrtm() - Matrix square root of quantum object. - tidyup(atol=1e-12) - Removes small elements from quantum object. - tr() - Trace of quantum object. - trans() - Transpose of quantum object. - transform(inpt, inverse=False) - Performs a basis transformation defined by `inpt` matrix. - trunc_neg(method='clip') - Removes negative eigenvalues and returns a new Qobj that is - a valid density operator. - unit(norm='tr', sparse=False, tol=0, maxiter=100000) - Returns normalized quantum object. - - """ - __array_priority__ = 100 # sets Qobj priority above numpy arrays - - # pylint: disable=dangerous-default-value, redefined-builtin - def __init__(self, inpt=None, dims=[[], []], shape=[], - type=None, isherm=None, copy=True, - fast=False, superrep=None, isunitary=None): - """ - Qobj constructor. - - Args: - inpt (ndarray): Input array or matrix data. - dims (list): List of Qobj dims. - shape (list): shape of underlying data. - type (str): Is object a ket, bra, oper, super. - isherm (bool): Is object Hermitian. - copy (bool): Copy input data. - fast (str or bool): Fast object instantiation. - superrep (str): Type of super representaiton. - isunitary (bool): Is object unitary. - - Raises: - Exception: Something bad happened. - """ - - self._isherm = isherm - self._type = type - self.superrep = superrep - self._isunitary = isunitary - - if fast == 'mc': - # fast Qobj construction for use in mcsolve with ket output - self._data = inpt - self.dims = dims - self._isherm = False - return - - if fast == 'mc-dm': - # fast Qobj construction for use in mcsolve with dm output - self._data = inpt - self.dims = dims - self._isherm = True - return - - if isinstance(inpt, Qobj): - # if input is already Qobj then return identical copy - - self._data = fast_csr_matrix((inpt.data.data, inpt.data.indices, - inpt.data.indptr), - shape=inpt.shape, copy=copy) - - if not np.any(dims): - # Dimensions of quantum object used for keeping track of tensor - # components - self.dims = inpt.dims - else: - self.dims = dims - - self.superrep = inpt.superrep - self._isunitary = inpt._isunitary - - elif inpt is None: - # initialize an empty Qobj with correct dimensions and shape - - if any(dims): - N, M = np.prod(dims[0]), np.prod(dims[1]) - self.dims = dims - - elif shape: - N, M = shape - self.dims = [[N], [M]] - - else: - N, M = 1, 1 - self.dims = [[N], [M]] - - self._data = fast_csr_matrix(shape=(N, M)) - - elif isinstance(inpt, (list, tuple)): - # case where input is a list - data = np.array(inpt) - if len(data.shape) == 1: - # if list has only one dimension (i.e [5,4]) - data = data.transpose() - - _tmp = sp.csr_matrix(data, dtype=complex) - self._data = fast_csr_matrix((_tmp.data, _tmp.indices, _tmp.indptr), - shape=_tmp.shape) - if not np.any(dims): - self.dims = [[int(data.shape[0])], [int(data.shape[1])]] - else: - self.dims = dims - - elif isinstance(inpt, np.ndarray) or sp.issparse(inpt): - # case where input is array or sparse - if inpt.ndim == 1: - inpt = inpt[:, np.newaxis] - - do_copy = copy - if not isinstance(inpt, fast_csr_matrix): - _tmp = sp.csr_matrix(inpt, dtype=complex, copy=do_copy) - _tmp.sort_indices() # Make sure indices are sorted. - do_copy = 0 - else: - _tmp = inpt - self._data = fast_csr_matrix((_tmp.data, _tmp.indices, _tmp.indptr), - shape=_tmp.shape, copy=do_copy) - - if not np.any(dims): - self.dims = [[int(inpt.shape[0])], [int(inpt.shape[1])]] - else: - self.dims = dims - - elif isinstance(inpt, (int, float, complex, - np.integer, np.floating, np.complexfloating)): - # if input is int, float, or complex then convert to array - _tmp = sp.csr_matrix([[inpt]], dtype=complex) - self._data = fast_csr_matrix((_tmp.data, _tmp.indices, _tmp.indptr), - shape=_tmp.shape) - if not np.any(dims): - self.dims = [[1], [1]] - else: - self.dims = dims - - else: - warnings.warn("Initializing Qobj from unsupported type: %s" % - builtins.type(inpt)) - inpt = np.array([[0]]) - _tmp = sp.csr_matrix(inpt, dtype=complex, copy=copy) - self._data = fast_csr_matrix((_tmp.data, _tmp.indices, _tmp.indptr), - shape=_tmp.shape) - self.dims = [[int(inpt.shape[0])], [int(inpt.shape[1])]] - - if type == 'super': - # Type is not super, i.e. dims not explicitly passed, but oper shape - if dims == [[], []] and self.shape[0] == self.shape[1]: - sub_shape = np.sqrt(self.shape[0]) - # check if root of shape is int - if (sub_shape % 1) != 0: - raise Exception('Invalid shape for a super operator.') - - sub_shape = int(sub_shape) - self.dims = [[[sub_shape], [sub_shape]]] * 2 - - if superrep: - self.superrep = superrep - else: - if self.type == 'super' and self.superrep is None: - self.superrep = 'super' - - # clear type cache - self._type = None - - def copy(self): - """Create identical copy""" - return Qobj(inpt=self) - - def get_data(self): - """Gets underlying data.""" - return self._data - - # Here we perfrom a check of the csr matrix type during setting of Q.data - def set_data(self, data): - """Data setter - """ - if not isinstance(data, fast_csr_matrix): - raise TypeError('Qobj data must be in fast_csr format.') - - self._data = data - data = property(get_data, set_data) - - def __add__(self, other): - """ - ADDITION with Qobj on LEFT [ ex. Qobj+4 ] - """ - self._isunitary = None - - if not isinstance(other, Qobj): - if isinstance(other, (int, float, complex, np.integer, - np.floating, np.complexfloating, np.ndarray, - list, tuple)) or sp.issparse(other): - other = Qobj(other) - else: - return NotImplemented - - if np.prod(other.shape) == 1 and np.prod(self.shape) != 1: - # case for scalar quantum object - dat = other.data[0, 0] - if dat == 0: - return self - - out = Qobj() - - if self.type in ['oper', 'super']: - out.data = self.data + dat * fast_identity( - self.shape[0]) - else: - out.data = self.data - out.data.data = out.data.data + dat - - out.dims = self.dims - - if isinstance(dat, (int, float)): - out._isherm = self._isherm - else: - # We use _isherm here to prevent recalculating on self and - # other, relying on that bool(None) == False. - out._isherm = (True if self._isherm and other._isherm - else out.isherm) - - out.superrep = self.superrep - - return out - - elif np.prod(self.shape) == 1 and np.prod(other.shape) != 1: - # case for scalar quantum object - dat = self.data[0, 0] - if dat == 0: - return other - - out = Qobj() - if other.type in ['oper', 'super']: - out.data = dat * fast_identity(other.shape[0]) + other.data - else: - out.data = other.data - out.data.data = out.data.data + dat - out.dims = other.dims - - if isinstance(dat, complex): - out._isherm = out.isherm - else: - out._isherm = self._isherm - - out.superrep = self.superrep - - return out - - elif self.dims != other.dims: - raise TypeError('Incompatible quantum object dimensions') - - elif self.shape != other.shape: - raise TypeError('Matrix shapes do not match') - - else: # case for matching quantum objects - out = Qobj() - out.data = self.data + other.data - out.dims = self.dims - - if self.type in ['ket', 'bra', 'operator-ket', 'operator-bra']: - out._isherm = False - elif self._isherm is None or other._isherm is None: - out._isherm = out.isherm - elif not self._isherm and not other._isherm: - out._isherm = out.isherm - else: - out._isherm = self._isherm and other._isherm - - if self.superrep and other.superrep: - if self.superrep != other.superrep: - msg = ("Adding superoperators with different " + - "representations") - warnings.warn(msg) - - out.superrep = self.superrep - - return out - - def __radd__(self, other): - """ - ADDITION with Qobj on RIGHT [ ex. 4+Qobj ] - """ - return self + other - - def __sub__(self, other): - """ - SUBTRACTION with Qobj on LEFT [ ex. Qobj-4 ] - """ - return self + (-other) - - def __rsub__(self, other): - """ - SUBTRACTION with Qobj on RIGHT [ ex. 4-Qobj ] - """ - return (-self) + other - - # used - # pylint: disable=too-many-return-statements - def __mul__(self, other): - """ - MULTIPLICATION with Qobj on LEFT [ ex. Qobj*4 ] - """ - self._isunitary = None - - if isinstance(other, Qobj): - if self.dims[1] == other.dims[0]: - out = Qobj() - out.data = self.data * other.data - dims = [self.dims[0], other.dims[1]] - out.dims = dims - out.dims = dims - - out._isherm = None - - if self.superrep and other.superrep: - if self.superrep != other.superrep: - msg = ("Multiplying superoperators with different " + - "representations") - warnings.warn(msg) - - out.superrep = self.superrep - - return out - - elif np.prod(self.shape) == 1: - out = Qobj(other) - out.data *= self.data[0, 0] - out.superrep = other.superrep - return out - - elif np.prod(other.shape) == 1: - out = Qobj(self) - out.data *= other.data[0, 0] - out.superrep = self.superrep - return out - - else: - raise TypeError("Incompatible Qobj shapes") - - elif isinstance(other, np.ndarray): - if other.dtype == 'object': - return np.array([self * item for item in other], - dtype=object) - else: - return self.data * other - - elif isinstance(other, list): - # if other is a list, do element-wise multiplication - return np.array([self * item for item in other], - dtype=object) - - elif isinstance(other, (int, float, complex, - np.integer, np.floating, np.complexfloating)): - out = Qobj() - out.data = self.data * other - out.dims = self.dims - out.superrep = self.superrep - if isinstance(other, complex): - out._isherm = out.isherm - else: - out._isherm = self._isherm - - return out - - else: - return NotImplemented - - # keep for now - def __rmul__(self, other): - """ - MULTIPLICATION with Qobj on RIGHT [ ex. 4*Qobj ] - """ - if isinstance(other, np.ndarray): - if other.dtype == 'object': - return np.array([item * self for item in other], - dtype=object) - else: - return other * self.data - - elif isinstance(other, list): - # if other is a list, do element-wise multiplication - return np.array([item * self for item in other], - dtype=object) - - elif isinstance(other, (int, float, complex, - np.integer, np.floating, - np.complexfloating)): - out = Qobj() - out.data = other * self.data - out.dims = self.dims - out.superrep = self.superrep - if isinstance(other, complex): - out._isherm = out.isherm - else: - out._isherm = self._isherm - - return out - - else: - raise TypeError("Incompatible object for multiplication") - - # keep for now - def __truediv__(self, other): - return self.__div__(other) - - # keep for now - def __div__(self, other): - """ - DIVISION (by numbers only) - """ - if isinstance(other, Qobj): # if both are quantum objects - raise TypeError("Incompatible Qobj shapes " + - "[division with Qobj not implemented]") - - if isinstance(other, (int, float, complex, - np.integer, np.floating, np.complexfloating)): - out = Qobj() - out.data = self.data / other - out.dims = self.dims - if isinstance(other, complex): - out._isherm = out.isherm - else: - out._isherm = self._isherm - - out.superrep = self.superrep - - return out - - else: - raise TypeError("Incompatible object for division") - - # keep for now - def __neg__(self): - """ - NEGATION operation. - """ - out = Qobj() - out.data = -self.data - out.dims = self.dims - out.superrep = self.superrep - out._isherm = self._isherm - out._isunitary = self._isunitary - return out - - # needed by qobj_generators - def __getitem__(self, ind): - """ - GET qobj elements. - """ - out = self.data[ind] - if sp.issparse(out): - return np.asarray(out.todense()) - else: - return out - - # keep for now - def __eq__(self, other): - """ - EQUALITY operator. - """ - return bool(isinstance(other, Qobj) and - self.dims == other.dims and - not np.any(np.abs((self.data - other.data).data) > atol)) - - # keep for now - def __ne__(self, other): - """ - INEQUALITY operator. - """ - return not self == other - - # not needed functionally but is useful to keep for now - def __str__(self): - s = "" - t = self.type - shape = self.shape - if self.type in ['oper', 'super']: - s += ("Quantum object: " + - "dims = " + str(self.dims) + - ", shape = " + str(shape) + - ", type = " + t + - ", isherm = " + str(self.isherm) + - ( - ", superrep = {0.superrep}".format(self) - if t == "super" and self.superrep != "super" - else "" - ) + "\n") - else: - s += ("Quantum object: " + - "dims = " + str(self.dims) + - ", shape = " + str(shape) + - ", type = " + t + "\n") - s += "Qobj data =\n" - - if shape[0] > 10000 or shape[1] > 10000: - # if the system is huge, don't attempt to convert to a - # dense matrix and then to string, because it is pointless - # and is likely going to produce memory errors. Instead print the - # sparse data string representation - s += str(self.data) - - elif all(np.imag(self.data.data) == 0): - s += str(np.real(self.full())) - - else: - s += str(self.full()) - - return s - - # used by states - def dag(self): - """Adjoint operator of quantum object. - """ - out = Qobj() - out.data = zcsr_adjoint(self.data) - out.dims = [self.dims[1], self.dims[0]] - out._isherm = self._isherm - out.superrep = self.superrep - return out - - # breaks if removed - used in hamiltonian_model - def full(self, order='C', squeeze=False): - """Dense array from quantum object. - - Parameters - ---------- - order : str {'C', 'F'} - Return array in C (default) or Fortran ordering. - squeeze : bool {False, True} - Squeeze output array. - - Returns - ------- - data : array - Array of complex data from quantum objects `data` attribute. - """ - if squeeze: - return self.data.toarray(order=order).squeeze() - else: - return self.data.toarray(order=order) - - # breaks if removed - only ever actually used in tests for duffing_model_generators - # pylint: disable=unused-argument - def __array__(self, *arg, **kwarg): - """Numpy array from Qobj - For compatibility with np.array - """ - return self.full() - - # breaks if removed due to tensor - @property - def isherm(self): - """Is operator Hermitian. - - Returns: - bool: Operator is Hermitian or not. - """ - - if self._isherm is not None: - # used previously computed value - return self._isherm - - self._isherm = bool(zcsr_isherm(self.data)) - - return self._isherm - - # breaks if removed due to tensor - @isherm.setter - def isherm(self, isherm): - self._isherm = isherm - - @property - def type(self): - """Type of Qobj - """ - if not self._type: - self._type = type_from_dims(self.dims) - - return self._type - - @property - def shape(self): - """Shape of Qobj - """ - if self.data.shape == (1, 1): - return tuple([np.prod(self.dims[0]), np.prod(self.dims[1])]) - else: - return tuple(self.data.shape) - - # breaks if removed - called in pulse_controller - # when initial state being set - @property - def isket(self): - """Is ket vector""" - return self.type == 'ket' - - # breaks if removed - called in tensor - @property - def issuper(self): - """Is super operator""" - return self.type == 'super' diff --git a/qiskit/providers/aer/pulse/qutip_extra_lite/states.py b/qiskit/providers/aer/pulse/qutip_extra_lite/states.py deleted file mode 100644 index 2caaf2f561..0000000000 --- a/qiskit/providers/aer/pulse/qutip_extra_lite/states.py +++ /dev/null @@ -1,113 +0,0 @@ -# -*- coding: utf-8 -*- - -# This code is part of Qiskit. -# -# (C) Copyright IBM 2018, 2019, 2020. -# -# 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. - -# This file is part of QuTiP: Quantum Toolbox in Python. -# -# Copyright (c) 2011 and later, Paul D. Nation and Robert J. Johansson. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# 3. Neither the name of the QuTiP: Quantum Toolbox in Python nor the names -# of its contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -############################################################################### -# pylint: disable=invalid-name - -"""States -""" - -import numpy as np -from .qobj import Qobj -from .fastsparse import fast_csr_matrix - - -# used by qobj_generators -def fock_dm(N, n=0, offset=0): - """Density matrix representation of a Fock state - - Constructed via outer product of :func:`qutip.states.fock`. - - Args: - N (int): Number of Fock states in Hilbert space. - - n (int): Desired number state, defaults to 0 if omitted. - - offset (int): Energy level offset. - - Returns: - Qobj: Density matrix representation of Fock state. - - """ - psi = basis(N, n, offset=offset) - - return psi * psi.dag() - - -def basis(N, n=0, offset=0): - """Generates the vector representation of a Fock state. - - Args: - N (int): Number of Fock states in Hilbert space. - - n (int): Integer corresponding to desired number - state, defaults to 0 if omitted. - - offset (int): The lowest number state that is included - in the finite number state representation - of the state. - - Returns: - Qobj: Qobj representing the requested number state ``|n>``. - - Raises: - ValueError: Invalid input value. - - """ - if (not isinstance(N, (int, np.integer))) or N < 0: - raise ValueError("N must be integer N >= 0") - - if (not isinstance(n, (int, np.integer))) or n < offset: - raise ValueError("n must be integer n >= 0") - - if n - offset > (N - 1): # check if n is within bounds - raise ValueError("basis vector index need to be in n <= N-1") - - data = np.array([1], dtype=complex) - ind = np.array([0], dtype=np.int32) - ptr = np.array([0] * ((n - offset) + 1) + [1] * (N - (n - offset)), - dtype=np.int32) - - return Qobj(fast_csr_matrix((data, ind, ptr), shape=(N, 1)), isherm=False) diff --git a/qiskit/providers/aer/pulse/qutip_extra_lite/tensor.py b/qiskit/providers/aer/pulse/qutip_extra_lite/tensor.py deleted file mode 100644 index 11863c2e1e..0000000000 --- a/qiskit/providers/aer/pulse/qutip_extra_lite/tensor.py +++ /dev/null @@ -1,111 +0,0 @@ -# -*- coding: utf-8 -*- - -# This code is part of Qiskit. -# -# (C) Copyright IBM 2018, 2019, 2020. -# -# 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. - -# This file is part of QuTiP: Quantum Toolbox in Python. -# -# Copyright (c) 2011 and later, Paul D. Nation and Robert J. Johansson. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# 3. Neither the name of the QuTiP: Quantum Toolbox in Python nor the names -# of its contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -############################################################################### -""" -Module for the creation of composite quantum objects via the tensor product. -""" - -import numpy as np -# pylint: disable=no-name-in-module, import-error -from .cy.spmath import zcsr_kron -from .qobj import Qobj - - -def tensor(*args): - """Calculates the tensor product of input operators. - - Args: - args (array_like): List or array of quantum objects for tensor product. - - Returns: - qobj.Qobj: A composite quantum object. - - Raises: - TypeError: Requires at least one input argument. - """ - if not args: - raise TypeError("Requires at least one input argument") - - if len(args) == 1 and isinstance(args[0], (list, np.ndarray)): - # this is the case when tensor is called on the form: - # tensor([q1, q2, q3, ...]) - qlist = args[0] - - elif len(args) == 1 and isinstance(args[0], Qobj): - # tensor is called with a single Qobj as an argument, do nothing - return args[0] - - else: - # this is the case when tensor is called on the form: - # tensor(q1, q2, q3, ...) - qlist = args - - if not all([isinstance(q, Qobj) for q in qlist]): - # raise error if one of the inputs is not a quantum object - raise TypeError("One of inputs is not a quantum object") - - out = Qobj() - if qlist[0].issuper: - out.superrep = qlist[0].superrep - if not all([q.superrep == out.superrep for q in qlist]): - raise TypeError("In tensor products of superroperators, all must" + - "have the same representation") - - out.isherm = True - for n, q in enumerate(qlist): - if n == 0: - out.data = q.data - out.dims = q.dims - else: - out.data = zcsr_kron(out.data, q.data) - out.dims = [out.dims[0] + q.dims[0], out.dims[1] + q.dims[1]] - - out.isherm = out.isherm and q.isherm - - if not out.isherm: - out._isherm = None - - return out diff --git a/qiskit/providers/aer/pulse/system_models/hamiltonian_model.py b/qiskit/providers/aer/pulse/system_models/hamiltonian_model.py index 35fe8fdd1e..a4b6c90f1d 100644 --- a/qiskit/providers/aer/pulse/system_models/hamiltonian_model.py +++ b/qiskit/providers/aer/pulse/system_models/hamiltonian_model.py @@ -217,7 +217,7 @@ def _compute_drift_data(self): ham_full = np.zeros((full_dim, full_dim), dtype=complex) for ham_part in self._system: - ham_full += ham_part[0].full() * eval(ham_part[1]) + ham_full += ham_part[0].data * eval(ham_part[1]) # Remap eigenvalues and eigenstates evals, estates = la.eigh(ham_full) diff --git a/qiskit/providers/aer/pulse/system_models/string_model_parser/gen_operator.py b/qiskit/providers/aer/pulse/system_models/string_model_parser/gen_operator.py new file mode 100644 index 0000000000..b18fad0b7c --- /dev/null +++ b/qiskit/providers/aer/pulse/system_models/string_model_parser/gen_operator.py @@ -0,0 +1,141 @@ +# -*- coding: utf-8 -*- + +# This code is part of Qiskit. +# +# (C) Copyright IBM 2018, 2019, 2020. +# +# 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. + +""" +Functions to construct terra operators +""" + +import numpy as np + +from qiskit.quantum_info.operators.operator import Operator + + +def _create_destroy(dim, creation=True): + a_x, b_x = (1, 0) if creation else (0, 1) + data_op = np.zeros((dim, dim)) + for i in range(dim - 1): + data_op[i + a_x, i + b_x] = np.sqrt(i + 1) + return Operator(data_op) + + +def create(dim): + """Creation operator. + Args: + dim (int): Dimension of Hilbert space. + Returns: + Operator: Operator representation of creation operator. + """ + return _create_destroy(dim, creation=True) + + +def destroy(dim): + """Destruction operator. + Args: + dim (int): Dimension of Hilbert space. + Returns: + Operator: Operator representation of destruction operator. + """ + return _create_destroy(dim, creation=False) + + +def num(dim): + """Operator representation for number operator. + Args: + dim (int): The dimension of the Hilbert space. + Returns: + Operator: Operator representation for number operator. + """ + return Operator(np.diag(np.arange(dim))) + + +def sigmax(): + """Operator representation for Pauli spin 1/2 sigma-x operator. + Returns: + Operator: Operator representation for sigma x. + """ + return Operator.from_label('X') + + +def sigmay(): + """Operator representation for Pauli spin 1/2 sigma-y operator. + Returns: + Operator: Operator representation for sigma y. + """ + return Operator.from_label('Y') + + +def sigmaz(): + """Operator representation for Pauli spin 1/2 sigma-z operator. + Returns: + Operator: Operator representation for sigma z. + """ + return Operator.from_label('Z') + + +def identity(dim): + """Identity operator. + Args: + dim (int): Dimension of Hilbert space. + Returns: + Operator: Operator representation of identity operator. + """ + return Operator(np.identity(dim, dtype=np.complex128)) + + +def basis(dim, n=0): + """Vector representation of a Fock state. + Args: + dim (int): Number of Fock states in Hilbert space. + n (int): Integer corresponding to desired number state, default value is 0. + Returns: + Operator: Opertor representing the requested number state ``|n>``. + """ + data_op = np.zeros((dim, 1)) + data_op[n] = 1 + return Operator(data_op) + + +def tensor(op_list): + """Tensor product of input operators. + Args: + op_list (array_like): List or array of Operators objects for tensor product. + Returns: + Operator: Operator representation of tensor product. + """ + ret = op_list[0] + for op in op_list[1:]: + ret = ret.tensor(op) + return ret + + +def state(state_vector): + """Operator representation of state vector. + Args: + state_vector (array_like): array representing the state-vector. + Returns: + Operator: State vector operator representation. + """ + return Operator(state_vector.reshape(1, state_vector.shape[0])) + + +def fock_dm(dim, n=0): + """Density matrix representation of a Fock state + Args: + dim (int): Number of Fock states in Hilbert space. + n (int): Desired number state, defaults to 0 if omitted. + Returns: + Operator: Density matrix Operator representation of Fock state. + """ + psi = basis(dim, n) + return psi * psi.adjoint() diff --git a/qiskit/providers/aer/pulse/system_models/string_model_parser/qobj_from_string.py b/qiskit/providers/aer/pulse/system_models/string_model_parser/operator_from_string.py similarity index 73% rename from qiskit/providers/aer/pulse/system_models/string_model_parser/qobj_from_string.py rename to qiskit/providers/aer/pulse/system_models/string_model_parser/operator_from_string.py index 96ade9ebf7..dc485f9d22 100644 --- a/qiskit/providers/aer/pulse/system_models/string_model_parser/qobj_from_string.py +++ b/qiskit/providers/aer/pulse/system_models/string_model_parser/operator_from_string.py @@ -15,7 +15,7 @@ """Module for creating quantum operators.""" -from ...qutip_extra_lite import qobj_generators +from . import operator_generators as op_gen def gen_oper(opname, index, h_osc, h_qub, states=None): @@ -41,23 +41,24 @@ def gen_oper(opname, index, h_osc, h_qub, states=None): if opname in ['X', 'Y', 'Z'] and dim > 2: if opname == 'X': - opr_tmp = qobj_generators.get_oper('A', dim) + qobj_generators.get_oper('C', dim) + opr_tmp = (op_gen.get_oper('A', dim) + + op_gen.get_oper('C', dim)) elif opname == 'Y': - opr_tmp = (-1j * qobj_generators.get_oper('A', dim) + - 1j * qobj_generators.get_oper('C', dim)) + opr_tmp = (-1j * op_gen.get_oper('A', dim) + + 1j * op_gen.get_oper('C', dim)) else: - opr_tmp = (qobj_generators.get_oper('I', dim) - - 2 * qobj_generators.get_oper('N', dim)) + opr_tmp = (op_gen.get_oper('I', dim) - + 2 * op_gen.get_oper('N', dim)) else: is_qubit = False dim = h_osc.get(index, 5) if opname == 'P': - opr_tmp = qobj_generators.get_oper(opname, dim, states) + opr_tmp = op_gen.get_oper(opname, dim, states) else: if opr_tmp is None: - opr_tmp = qobj_generators.get_oper(opname, dim) + opr_tmp = op_gen.get_oper(opname, dim) # reverse sort by index rev_h_osc = sorted(h_osc.items(), key=lambda x: x[0])[::-1] @@ -69,11 +70,11 @@ def gen_oper(opname, index, h_osc, h_qub, states=None): if ii == index and not is_qubit: opers.append(opr_tmp) else: - opers.append(qobj_generators.qeye(dd)) + opers.append(op_gen.qeye(dd)) for ii, dd in rev_h_qub: if ii == index and is_qubit: opers.append(opr_tmp) else: - opers.append(qobj_generators.qeye(dd)) + opers.append(op_gen.qeye(dd)) - return qobj_generators.tensor(opers) + return op_gen.tensor(opers) diff --git a/qiskit/providers/aer/pulse/qutip_extra_lite/qobj_generators.py b/qiskit/providers/aer/pulse/system_models/string_model_parser/operator_generators.py similarity index 84% rename from qiskit/providers/aer/pulse/qutip_extra_lite/qobj_generators.py rename to qiskit/providers/aer/pulse/system_models/string_model_parser/operator_generators.py index 8f8aeaa95e..dfb8d4b9a7 100644 --- a/qiskit/providers/aer/pulse/qutip_extra_lite/qobj_generators.py +++ b/qiskit/providers/aer/pulse/system_models/string_model_parser/operator_generators.py @@ -16,17 +16,14 @@ """Operators to use in simulator""" import numpy as np -from . import operators as ops -from . import states as st -from . import tensor as ten -from .qobj import Qobj +from . import gen_operator def sigmax(dim=2): """Qiskit wrapper of sigma-X operator. """ if dim == 2: - return ops.sigmax() + return gen_operator.sigmax() else: raise Exception('Invalid level specification of the qubit subspace') @@ -35,7 +32,7 @@ def sigmay(dim=2): """Qiskit wrapper of sigma-Y operator. """ if dim == 2: - return ops.sigmay() + return gen_operator.sigmay() else: raise Exception('Invalid level specification of the qubit subspace') @@ -44,7 +41,7 @@ def sigmaz(dim=2): """Qiskit wrapper of sigma-Z operator. """ if dim == 2: - return ops.sigmaz() + return gen_operator.sigmaz() else: raise Exception('Invalid level specification of the qubit subspace') @@ -52,37 +49,37 @@ def sigmaz(dim=2): def sigmap(dim=2): """Qiskit wrapper of sigma-plus operator. """ - return ops.create(dim) + return gen_operator.create(dim) def sigmam(dim=2): """Qiskit wrapper of sigma-minus operator. """ - return ops.destroy(dim) + return gen_operator.destroy(dim) def create(dim): """Qiskit wrapper of creation operator. """ - return ops.create(dim) + return gen_operator.create(dim) def destroy(dim): """Qiskit wrapper of annihilation operator. """ - return ops.destroy(dim) + return gen_operator.destroy(dim) def num(dim): """Qiskit wrapper of number operator. """ - return ops.num(dim) + return gen_operator.num(dim) def qeye(dim): """Qiskit wrapper of identity operator. """ - return ops.qeye(dim) + return gen_operator.identity(dim) def project(dim, states): @@ -90,7 +87,7 @@ def project(dim, states): """ ket, bra = states if ket in range(dim) and bra in range(dim): - return st.basis(dim, ket) * st.basis(dim, bra).dag() + return gen_operator.basis(dim, ket) * gen_operator.basis(dim, bra).adjoint() else: raise Exception('States are specified on the outside of Hilbert space %s' % states) @@ -98,25 +95,25 @@ def project(dim, states): def tensor(list_qobj): """ Qiskit wrapper of tensor product """ - return ten.tensor(list_qobj) + return gen_operator.tensor(list_qobj) def basis(level, pos): """ Qiskit wrapper of basis """ - return st.basis(level, pos) + return gen_operator.basis(level, pos) def state(state_vec): """ Qiskit wrapper of qobj """ - return Qobj(state_vec) + return gen_operator.state(state_vec) def fock_dm(level, eigv): """ Qiskit wrapper of fock_dm """ - return st.fock_dm(level, eigv) + return gen_operator.fock_dm(level, eigv) def qubit_occ_oper_dressed(target_qubit, estates, h_osc, h_qub, level=0): @@ -153,8 +150,8 @@ def qubit_occ_oper_dressed(target_qubit, estates, h_osc, h_qub, level=0): out_state = tensor(states) for ii, estate in enumerate(estates): - if out_state[ii] == 1: - proj_op += estate * estate.dag() + if out_state.data.flatten()[ii] == 1: + proj_op += estate @ estate.adjoint() return proj_op diff --git a/qiskit/providers/aer/pulse/system_models/string_model_parser/string_model_parser.py b/qiskit/providers/aer/pulse/system_models/string_model_parser/string_model_parser.py index e6fc47ddf6..698792f8e4 100644 --- a/qiskit/providers/aer/pulse/system_models/string_model_parser/string_model_parser.py +++ b/qiskit/providers/aer/pulse/system_models/string_model_parser/string_model_parser.py @@ -20,7 +20,7 @@ from collections import namedtuple, OrderedDict import numpy as np from .apply_str_func_to_qobj import apply_func -from .qobj_from_string import gen_oper +from .operator_from_string import gen_oper Token = namedtuple('Token', ('type', 'name')) diff --git a/releasenotes/notes/cython-dep-removed-ffc095dcc575c449.yaml b/releasenotes/notes/cython-dep-removed-ffc095dcc575c449.yaml new file mode 100644 index 0000000000..7f51030ec2 --- /dev/null +++ b/releasenotes/notes/cython-dep-removed-ffc095dcc575c449.yaml @@ -0,0 +1,4 @@ +--- +upgrade: + - | + Code that dependes on Aer has been removed, so Cython is no longer a dependency. diff --git a/requirements-dev.txt b/requirements-dev.txt index 201ca40425..152516ba5c 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -2,7 +2,6 @@ stestr>=2.5.0 cmake!=3.17.1,!=3.17.0 conan>=1.22.2 scikit-build -cython asv cvxpy>=1.0.0 pylint diff --git a/setup.py b/setup.py index cf88f2b5e9..188d94fe49 100644 --- a/setup.py +++ b/setup.py @@ -15,13 +15,6 @@ PACKAGE_NAME = os.getenv('QISKIT_AER_PACKAGE_NAME', 'qiskit-aer') _DISABLE_CONAN = distutils.util.strtobool(os.getenv("DISABLE_CONAN", "OFF").lower()) -try: - from Cython.Build import cythonize -except ImportError: - import subprocess - subprocess.call([sys.executable, '-m', 'pip', 'install', 'Cython>=0.27.1']) - from Cython.Build import cythonize - if not _DISABLE_CONAN: try: from conans import client @@ -51,7 +44,6 @@ common_requirements = [ 'numpy>=1.16.3', 'scipy>=1.0', - 'cython>=0.27.1', 'pybind11>=2.4' # This isn't really an install requirement, # Pybind11 is required to be pre-installed for # CMake to successfully find header files. diff --git a/src/open_pulse/numeric_integrator.cpp b/src/open_pulse/numeric_integrator.cpp index 9892e2f96a..89271dce74 100644 --- a/src/open_pulse/numeric_integrator.cpp +++ b/src/open_pulse/numeric_integrator.cpp @@ -134,9 +134,25 @@ struct RhsData { vars = get_vec_from_dict_item(py_global_data, "vars"); vars_names = get_vec_from_dict_item(py_global_data, "vars_names"); num_h_terms = get_value_from_dict_item(py_global_data, "num_h_terms"); - datas = get_vec_from_dict_item>(py_global_data, "h_ops_data"); - idxs = get_vec_from_dict_item>(py_global_data, "h_ops_ind"); - ptrs = get_vec_from_dict_item>(py_global_data, "h_ops_ptr"); + auto tmp_datas = get_vec_from_dict_item>(py_global_data, "h_ops_data"); + for (const auto& data: tmp_datas){ + auto datas_back = datas.emplace(datas.end()); + auto idxs_back = idxs.emplace(idxs.end()); + auto ptrs_back = ptrs.emplace(ptrs.end()); + ptrs_back->push_back(0); + auto first_j = 0; + auto last_j = 0; + for (auto i = 0; i < data.shape[0]; i++) { + for (auto j = 0; j < data.shape[1]; j++) { + if (std::abs(data(i, j)) > 1e-15) { + datas_back->push_back(data(i,j)); + idxs_back->push_back(j); + last_j++; + } + } + ptrs_back->push_back(last_j); + } + } energy = get_value_from_dict_item>(py_global_data, "h_diag_elems"); } @@ -150,10 +166,12 @@ struct RhsData { std::vector vars; std::vector vars_names; long num_h_terms; - std::vector> datas; - std::vector> idxs; - std::vector> ptrs; + std::vector> datas; + std::vector> idxs; + std::vector> ptrs; NpArray energy; + + std::vector osc_terms_no_t; }; py::array_t inner_ode_rhs(double t, @@ -205,8 +223,7 @@ py::array_t inner_ode_rhs(double t, auto row_end = rhs_data.ptrs[h_idx][i + 1]; for (auto j = row_start; j < row_end; ++j) { auto tmp_idx = rhs_data.idxs[h_idx][j]; - auto osc_term = - std::exp( + auto osc_term = std::exp( complex_t(0., 1.) * (rhs_data.energy[i] - rhs_data.energy[tmp_idx]) * t ); complex_t coef = (i < tmp_idx ? std::conj(td) : td); @@ -216,7 +233,6 @@ py::array_t inner_ode_rhs(double t, } } } /* End of systems */ - for (auto i = 0; i < num_rows; ++i) { out[i] += complex_t(0., 1.) * rhs_data.energy[i] * vec[i]; } diff --git a/src/open_pulse/pulse_utils.cpp b/src/open_pulse/pulse_utils.cpp index a8be0b45ed..d6d4b7cc7b 100644 --- a/src/open_pulse/pulse_utils.cpp +++ b/src/open_pulse/pulse_utils.cpp @@ -24,6 +24,26 @@ complex_t internal_expect_psi_csr(const py::array_t& data, return expt; } +complex_t internal_expect_psi(const py::array_t& data, + const py::array_t& vec) { + auto data_raw = data.unchecked<2>(); + auto vec_raw = vec.unchecked<1>(); + + auto nrows = data.shape(0); + auto ncols = data.shape(1); + complex_t temp, expt = 0; + + for (decltype(nrows) i = 0; i < nrows; i++) { + temp = 0; + auto vec_conj = std::conj(vec_raw[i]); + for (auto j = 0; j < ncols; j++) { + temp += data_raw(i, j) * vec_raw[j]; + } + expt += vec_conj * temp; + } + return expt; +} + py::object expect_psi_csr(py::array_t data, py::array_t ind, @@ -38,6 +58,16 @@ py::object expect_psi_csr(py::array_t data, } +py::object expect_psi(py::array_t data, + py::array_t vec, + bool isherm){ + complex_t expt = internal_expect_psi(data, vec); + if(isherm){ + return py::cast(std::real(expt)); + } + return py::cast(expt); +} + py::array_t occ_probabilities(py::array_t qubits, py::array_t state, py::list meas_ops){ @@ -46,12 +76,9 @@ py::array_t occ_probabilities(py::array_t qubits, auto probs_raw = probs.mutable_unchecked<1>(); for(decltype(meas_size) i=0; i < meas_size; i++){ auto data = meas_ops[i].attr("data").attr("data").cast>(); - auto ind = meas_ops[i].attr("data").attr("indices").cast>(); - auto ptr = meas_ops[i].attr("data").attr("indptr").cast>(); - - probs_raw[i] = std::real(internal_expect_psi_csr(data, ind, ptr, state)); + probs_raw[i] = std::real(internal_expect_psi(data, state)); } - + return probs; } @@ -120,3 +147,26 @@ py::array_t spmv_csr(py::array_t data, return out; } + +py::array_t spmv(py::array_t data, + py::array_t vec) +{ + auto data_raw = get_raw_data(data); + auto vec_raw = get_raw_data(vec); + + auto num_columns = data.shape(0); + auto num_rows = data.shape(1); + + py::array_t out(num_rows); + auto out_raw = get_raw_data(out); + memset(&out_raw[0], 0, num_rows * sizeof(complex_t)); + for (auto row=0; row < num_rows; row++) + { + for (auto jj=0; jj data, py::array_t vec, bool isherm); +py::object expect_psi(py::array_t data, + py::array_t vec, + bool isherm); + //============================================================================ // Computes the occupation probabilities of the specifed qubits for // the given state. @@ -90,4 +94,7 @@ py::array_t spmv_csr(py::array_t data, py::array_t ptr, py::array_t vec); +py::array_t spmv(py::array_t data, + py::array_t vec); + #endif //PULSE_UTILS_H diff --git a/src/open_pulse/pulse_utils_bindings.cpp b/src/open_pulse/pulse_utils_bindings.cpp index d7968fe6d0..b417cd8727 100644 --- a/src/open_pulse/pulse_utils_bindings.cpp +++ b/src/open_pulse/pulse_utils_bindings.cpp @@ -25,18 +25,30 @@ RhsFunctor get_ode_rhs_functor(py::object the_global_data, py::object the_exp, return RhsFunctor(the_global_data, the_exp, the_system, the_channels, the_reg); } + +class OccProbabilitiesFunctor { +public: + OccProbabilitiesFunctor() = default; + py::array_t operator()(py::array_t qubits, + py::array_t state, + py::list meas_ops) { return occ_probabilities(qubits, state, meas_ops); } +}; + PYBIND11_MODULE(pulse_utils, m) { m.doc() = "Utility functions for pulse simulator"; // optional module docstring m.def("td_ode_rhs_static", &td_ode_rhs, "Compute rhs for ODE"); m.def("cy_expect_psi_csr", &expect_psi_csr, "Expected value for a operator"); + m.def("cy_expect_psi", &expect_psi, "Expected value for a operator"); m.def("occ_probabilities", &occ_probabilities, "Computes the occupation probabilities of the specifed qubits for the given state"); m.def("write_shots_memory", &write_shots_memory, "Converts probabilities back into shots"); m.def("oplist_to_array", &oplist_to_array, "Insert list of complex numbers into numpy complex array"); m.def("spmv_csr", &spmv_csr, "Sparse matrix, dense vector multiplication."); + m.def("spmv", &spmv, "Matrix vector multiplication."); - py::class_(m, "OdeRhsFunctor") - .def("__call__", &RhsFunctor::operator()); + py::class_ ode_rhs_func(m, "OdeRhsFunctor"); + ode_rhs_func.def("__call__", &RhsFunctor::operator()); + ode_rhs_func.def("__reduce__", [ode_rhs_func](const RhsFunctor& self) { return py::make_tuple(ode_rhs_func, py::tuple());}); m.def("get_ode_rhs_functor", &get_ode_rhs_functor, "Get ode_rhs functor to allow caching of parameters"); } diff --git a/src/open_pulse/python_to_cpp.hpp b/src/open_pulse/python_to_cpp.hpp index 2af00e1766..555de09f71 100644 --- a/src/open_pulse/python_to_cpp.hpp +++ b/src/open_pulse/python_to_cpp.hpp @@ -313,9 +313,12 @@ class NpArray { public: NpArray(){} NpArray(PyArrayObject * array){ + if(PyArray_NDIM(array) > 2){ + throw std::runtime_error("NpArray can only wrap 1D or 2D arrays."); + } _populate_data(array); _populate_shape(array); - size = array->dimensions[0]; + size = PyArray_NDIM(array) == 2 ? array->dimensions[0] * array->dimensions[1] : array->dimensions[0]; } const VecType * data = nullptr; @@ -332,7 +335,11 @@ class NpArray { const VecType& operator[](size_t index) const { return data[index]; } - + + const VecType& operator()(size_t i, size_t j) const { + return data[i*shape[1] + j]; + } + bool operator==(const NpArray& other) const { if(other.size != size || other.shape.size() != shape.size()) @@ -365,6 +372,9 @@ class NpArray { for(auto i = 0; i < num_dims; ++i){ shape.emplace_back(p_dims[i]); } + if(shape.size() == 1){ + shape.emplace_back(0); + } } void _populate_data(PyArrayObject * array){ diff --git a/src/open_pulse/test_python_to_cpp.cpp b/src/open_pulse/test_python_to_cpp.cpp index b0fbdcf35d..e240abfde0 100644 --- a/src/open_pulse/test_python_to_cpp.cpp +++ b/src/open_pulse/test_python_to_cpp.cpp @@ -46,6 +46,17 @@ bool cpp_test_np_array_of_doubles(PyArrayObject * val){ return true; } +bool cpp_test_np_2D_array_of_doubles(PyArrayObject * val){ + // val = np.array([[0., 1., 2., 3.],[10.,20.,30.,40]]) + auto vec = get_value>(val); + if(vec(0, 0) != 0. || vec(0, 1) != 1. || vec(0, 2) != 2. || vec(0, 3) != 3. || + vec(1, 0) != 10. || vec(1, 1) != 20. || vec(1, 2) != 30. || vec(1, 3) != 40. ) + return false; + + return true; +} + + bool cpp_test_evaluate_hamiltonians(PyObject * val){ // TODO: Add tests! return false; diff --git a/src/open_pulse/test_python_to_cpp.hpp b/src/open_pulse/test_python_to_cpp.hpp index 2b7f9fd3bd..3e3817f330 100644 --- a/src/open_pulse/test_python_to_cpp.hpp +++ b/src/open_pulse/test_python_to_cpp.hpp @@ -32,9 +32,11 @@ bool cpp_test_py_list_of_lists_to_cpp_vector_of_vectors(PyObject * val); bool cpp_test_py_dict_string_numeric_to_cpp_map_string_numeric(PyObject * val); bool cpp_test_py_dict_string_list_of_list_of_doubles_to_cpp_map_string_vec_of_vecs_of_doubles(PyObject * val); bool cpp_test_np_array_of_doubles(PyArrayObject * val); +bool cpp_test_np_2D_array_of_doubles(PyArrayObject * val); bool cpp_test_evaluate_hamiltonians(PyObject * val); bool cpp_test_py_ordered_map(PyObject * val); + PYBIND11_MODULE(test_python_to_cpp, m) { m.doc() = "pybind11 test_python_to_cpp"; // optional module docstring @@ -47,6 +49,8 @@ PYBIND11_MODULE(test_python_to_cpp, m) { [](py::dict dict) { return cpp_test_py_dict_string_list_of_list_of_doubles_to_cpp_map_string_vec_of_vecs_of_doubles(dict.ptr()); } , ""); m.def("test_np_array_of_doubles", [](py::array_t array_doubles) { return cpp_test_np_array_of_doubles(reinterpret_cast(array_doubles.ptr())); } , ""); + m.def("test_np_2D_array_of_doubles", + [](py::array_t array_doubles) { return cpp_test_np_2D_array_of_doubles(reinterpret_cast(array_doubles.ptr())); } , ""); m.def("test_evaluate_hamiltonians", [](py::list list) { return cpp_test_evaluate_hamiltonians(list.ptr()); } , ""); m.def("test_py_ordered_map", [](py::dict dict) { return cpp_test_py_ordered_map(dict.ptr()); } , ""); } diff --git a/test/asv.linux.cuda.conf.json b/test/asv.linux.cuda.conf.json index 5fde993fe7..bc0b826e73 100644 --- a/test/asv.linux.cuda.conf.json +++ b/test/asv.linux.cuda.conf.json @@ -43,7 +43,7 @@ "return-code=any python -mpip uninstall -y {project}" ], "build_command": [ - "python -mpip install -U scikit-build cython", + "python -mpip install -U scikit-build", "pip install git+https://github.com/Qiskit/qiskit-terra", "pip install git+https://github.com/Qiskit/qiskit-aqua", "pip install pyscf", diff --git a/test/terra/pulse/test_duffing_model_generators.py b/test/terra/pulse/test_duffing_model_generators.py index 134d8a4527..b18067a659 100644 --- a/test/terra/pulse/test_duffing_model_generators.py +++ b/test/terra/pulse/test_duffing_model_generators.py @@ -19,8 +19,9 @@ from qiskit.providers.aer.pulse.system_models.pulse_system_model import PulseSystemModel from qiskit.providers.aer.pulse.system_models.hamiltonian_model import HamiltonianModel from qiskit.providers.aer.pulse.system_models import duffing_model_generators as model_gen -from qiskit.providers.aer.pulse.qutip_extra_lite.qobj_generators import get_oper +from qiskit.providers.aer.pulse.system_models.string_model_parser.operator_generators import get_oper from qiskit.providers.models.backendconfiguration import UchannelLO +from qiskit.quantum_info.operators.operator import Operator class TestDuffingModelGenerators(QiskitAerTestCase): """Tests for functions in duffing_model_generators.py""" @@ -551,8 +552,8 @@ def _compare_str_lists(self, list1, list2): def _operator_array_from_str(self, dim, op_str_list): - op = array([[1.]]) - for c in op_str_list: - op = kron(op, get_oper(c, dim)) + op = get_oper(op_str_list[0], dim) + for c in op_str_list[1:]: + op = op.tensor(get_oper(c, dim)) return op diff --git a/test/terra/pulse/test_system_models.py b/test/terra/pulse/test_system_models.py index 5caa2aafe9..91debecb26 100644 --- a/test/terra/pulse/test_system_models.py +++ b/test/terra/pulse/test_system_models.py @@ -139,7 +139,7 @@ def test_qubit_lo_from_configurable_backend(self): qubit_lo_from_hamiltonian = test_model.hamiltonian.get_qubit_lo_from_drift() freqs = test_model.calculate_channel_frequencies(qubit_lo_from_hamiltonian) expected = getattr(backend.configuration(), 'hamiltonian')['vars']['wq0'] / (2 * np. pi) - self.assertAlmostEqual(freqs['D0'], expected, places=4) + self.assertAlmostEqual(freqs['D0'], expected, places=5) def _compute_u_lo_freqs(self, qubit_lo_freq): """ diff --git a/test/terra/test_python_to_cpp.py b/test/terra/test_python_to_cpp.py index f8f820d470..0b158bf020 100644 --- a/test/terra/test_python_to_cpp.py +++ b/test/terra/test_python_to_cpp.py @@ -12,12 +12,12 @@ import unittest import numpy as np -from qiskit.providers.aer.pulse.qutip_extra_lite.qobj import Qobj from qiskit.providers.aer.pulse.controllers.test_python_to_cpp import \ test_py_list_to_cpp_vec, test_py_list_of_lists_to_cpp_vector_of_vectors,\ test_py_dict_string_numeric_to_cpp_map_string_numeric,\ test_py_dict_string_list_of_list_of_doubles_to_cpp_map_string_vec_of_vecs_of_doubles,\ - test_np_array_of_doubles, test_evaluate_hamiltonians, test_py_ordered_map + test_np_array_of_doubles, test_np_2D_array_of_doubles, test_evaluate_hamiltonians,\ + test_py_ordered_map from .common import QiskitAerTestCase @@ -45,6 +45,10 @@ def test_np_array_of_doubles(self): arg = np.array([0., 1., 2., 3.]) self.assertTrue(test_np_array_of_doubles(arg)) + def test_np_2D_array_of_doubles(self): + arg = np.array([[0., 1., 2., 3.], [10., 20., 30., 40.]]) + self.assertTrue(test_np_2D_array_of_doubles(arg)) + def test_evaluate_hamiltonians(self): """ TODO: Evaluate different hamiltoninan expressions?""" self.assertEqual(True, True) From c5da3faa7a596b5289abb4390931911862f46c1e Mon Sep 17 00:00:00 2001 From: Yael Ben-Haim Date: Wed, 18 Nov 2020 11:21:58 +0200 Subject: [PATCH 046/126] Adding rotation gates to the MPS simulator (#1042) --- .../providers/aer/backends/qasm_simulator.py | 3 +- .../matrix_product_state.hpp | 43 +++++++++++++++++- .../matrix_product_state_internal.cpp | 45 +++++++++++++++++++ .../matrix_product_state_internal.hpp | 13 ++++-- .../matrix_product_state_tensor.hpp | 3 -- 5 files changed, 99 insertions(+), 8 deletions(-) diff --git a/qiskit/providers/aer/backends/qasm_simulator.py b/qiskit/providers/aer/backends/qasm_simulator.py index fbe687794f..e3fb439f5d 100644 --- a/qiskit/providers/aer/backends/qasm_simulator.py +++ b/qiskit/providers/aer/backends/qasm_simulator.py @@ -450,7 +450,8 @@ def _method_configuration(method=None): config.description = 'A C++ QasmQobj matrix product state simulator with noise' config.basis_gates = [ 'u1', 'u2', 'u3', 'u', 'p', 'cp', 'cx', 'cz', 'id', 'x', 'y', 'z', 'h', 's', - 'sdg', 'sx', 't', 'tdg', 'swap', 'ccx', 'unitary', 'roerror', 'delay' + 'sdg', 'sx', 't', 'tdg', 'swap', 'ccx', 'unitary', 'roerror', 'delay', + 'r', 'rx', 'ry', 'rz', 'rxx', 'ryy', 'rzz', 'rzx' ] # Stabilizer method diff --git a/src/simulators/matrix_product_state/matrix_product_state.hpp b/src/simulators/matrix_product_state/matrix_product_state.hpp index 2a24361d0a..ec3833d7d9 100644 --- a/src/simulators/matrix_product_state/matrix_product_state.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state.hpp @@ -53,7 +53,7 @@ const Operations::OpSet StateOpSet( // Gates {"id", "x", "y", "z", "s", "sdg", "h", "t", "tdg", "p", "u1", "u2", "u3", "u", "U", "CX", "cx", "cz", "cp", "cu1", "swap", "ccx", - "sx"}, + "sx", "r", "rx", "ry", "rz", "rxx", "ryy", "rzz", "rzx"}, // Snapshots {"statevector", "memory", "register", "probabilities", "expectation_value_pauli", "expectation_value_pauli_with_variance", @@ -303,6 +303,10 @@ const stringmap_t State::gateset_({ {"sx", Gates::sx}, // Sqrt(X) gate {"t", Gates::t}, // T-gate (sqrt(S)) {"tdg", Gates::tdg}, // Conjguate-transpose of T gate + {"r", Gates::r}, // R rotation gate + {"rx", Gates::rx}, // Pauli-X rotation gate + {"ry", Gates::ry}, // Pauli-Y rotation gate + {"rz", Gates::rz}, // Pauli-Z rotation gate // Waltz Gates {"p", Gates::u1}, // zero-X90 pulse waltz gate {"u1", Gates::u1}, // zero-X90 pulse waltz gate @@ -317,6 +321,10 @@ const stringmap_t State::gateset_({ {"cu1", Gates::cu1}, // Controlled-U1 gate {"cp", Gates::cu1}, // Controlled-U1 gate {"swap", Gates::swap}, // SWAP gate + {"rxx", Gates::rxx}, // Pauli-XX rotation gate + {"ryy", Gates::ryy}, // Pauli-YY rotation gate + {"rzz", Gates::rzz}, // Pauli-ZZ rotation gate + {"rzx", Gates::rzx}, // Pauli-ZX rotation gate // Three-qubit gates {"ccx", Gates::mcx} // Controlled-CX gate (Toffoli) }); @@ -685,6 +693,23 @@ void State::apply_gate(const Operations::Op &op) { case Gates::tdg: qreg_.apply_tdg(op.qubits[0]); break; + case Gates::r: + qreg_.apply_r(op.qubits[0], + std::real(op.params[0]), + std::real(op.params[1])); + break; + case Gates::rx: + qreg_.apply_rx(op.qubits[0], + std::real(op.params[0])); + break; + case Gates::ry: + qreg_.apply_ry(op.qubits[0], + std::real(op.params[0])); + break; + case Gates::rz: + qreg_.apply_rz(op.qubits[0], + std::real(op.params[0])); + break; case Gates::swap: qreg_.apply_swap(op.qubits[0], op.qubits[1], true); break; @@ -695,6 +720,22 @@ void State::apply_gate(const Operations::Op &op) { qreg_.apply_cu1(op.qubits[0], op.qubits[1], std::real(op.params[0])); break; + case Gates::rxx: + qreg_.apply_rxx(op.qubits[0], op.qubits[1], + std::real(op.params[0])); + break; + case Gates::ryy: + qreg_.apply_ryy(op.qubits[0], op.qubits[1], + std::real(op.params[0])); + break; + case Gates::rzz: + qreg_.apply_rzz(op.qubits[0], op.qubits[1], + std::real(op.params[0])); + break; + case Gates::rzx: + qreg_.apply_rzx(op.qubits[0], op.qubits[1], + std::real(op.params[0])); + break; default: // We shouldn't reach here unless there is a bug in gateset throw std::invalid_argument( 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 7895f94bb1..2ce9991d1f 100644 --- a/src/simulators/matrix_product_state/matrix_product_state_internal.cpp +++ b/src/simulators/matrix_product_state/matrix_product_state_internal.cpp @@ -321,6 +321,26 @@ void MPS::apply_sx(uint_t index) get_qubit(index).apply_matrix(AER::Linalg::Matrix::SX); } +void MPS::apply_r(uint_t index, double phi, double lam) +{ + get_qubit(index).apply_matrix(AER::Linalg::Matrix::r(phi, lam)); +} + +void MPS::apply_rx(uint_t index, double theta) +{ + get_qubit(index).apply_matrix(AER::Linalg::Matrix::rx(theta)); +} + +void MPS::apply_ry(uint_t index, double theta) +{ + get_qubit(index).apply_matrix(AER::Linalg::Matrix::ry(theta)); +} + +void MPS::apply_rz(uint_t index, double theta) +{ + get_qubit(index).apply_matrix(AER::Linalg::Matrix::rz(theta)); +} + void MPS::apply_u1(uint_t index, double lambda) { get_qubit(index).apply_matrix(AER::Linalg::Matrix::u1(lambda)); @@ -349,12 +369,37 @@ void MPS::apply_cz(uint_t index_A, uint_t index_B) apply_2_qubit_gate(get_qubit_index(index_A), get_qubit_index(index_B), cz, cmatrix_t(1, 1)); } + void MPS::apply_cu1(uint_t index_A, uint_t index_B, double lambda) { cmatrix_t u1_matrix = AER::Linalg::Matrix::u1(lambda); apply_2_qubit_gate(get_qubit_index(index_A), get_qubit_index(index_B), cu1, u1_matrix); } +void MPS::apply_rxx(uint_t index_A, uint_t index_B, double theta) +{ + cmatrix_t rxx_matrix = AER::Linalg::Matrix::rxx(theta); + apply_2_qubit_gate(get_qubit_index(index_A), get_qubit_index(index_B), su4, rxx_matrix); +} + +void MPS::apply_ryy(uint_t index_A, uint_t index_B, double theta) +{ + cmatrix_t ryy_matrix = AER::Linalg::Matrix::ryy(theta); + apply_2_qubit_gate(get_qubit_index(index_A), get_qubit_index(index_B), su4, ryy_matrix); +} + +void MPS::apply_rzz(uint_t index_A, uint_t index_B, double theta) +{ + cmatrix_t rzz_matrix = AER::Linalg::Matrix::rzz(theta); + apply_2_qubit_gate(get_qubit_index(index_A), get_qubit_index(index_B), su4, rzz_matrix); +} + +void MPS::apply_rzx(uint_t index_A, uint_t index_B, double theta) +{ + cmatrix_t rzx_matrix = AER::Linalg::Matrix::rzx(theta); + apply_2_qubit_gate(get_qubit_index(index_A), get_qubit_index(index_B), su4, rzx_matrix); +} + void MPS::apply_ccx(const reg_t &qubits) { reg_t internal_qubits = get_internal_qubits(qubits); 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 88eef9c9c0..1baf66944c 100644 --- a/src/simulators/matrix_product_state/matrix_product_state_internal.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state_internal.hpp @@ -26,8 +26,8 @@ namespace MatrixProductState { // Allowed gates enum class enum Gates { - id, h, x, y, z, s, sdg, sx, t, tdg, u1, u2, u3, // single qubit - cx, cz, cu1, swap, su4, // two qubit + id, h, x, y, z, s, sdg, sx, t, tdg, u1, u2, u3, r, rx, ry, rz, // single qubit + cx, cz, cu1, swap, su4, rxx, ryy, rzz, rzx, // two qubit mcx // three qubit }; @@ -101,6 +101,10 @@ class MPS{ //---------------------------------------------------------------- void apply_h(uint_t index); void apply_sx(uint_t index); + void apply_r(uint_t index, double phi, double lam); + void apply_rx(uint_t index, double theta); + void apply_ry(uint_t index, double theta); + void apply_rz(uint_t index, double theta); void apply_x(uint_t index){ get_qubit(index).apply_x();} void apply_y(uint_t index){ get_qubit(index).apply_y();} void apply_z(uint_t index){ get_qubit(index).apply_z();} @@ -114,9 +118,12 @@ class MPS{ void apply_cnot(uint_t index_A, uint_t index_B); void apply_swap(uint_t index_A, uint_t index_B, bool swap_gate); - void apply_cz(uint_t index_A, uint_t index_B); void apply_cu1(uint_t index_A, uint_t index_B, double lambda); + void apply_rxx(uint_t index_A, uint_t index_B, double theta); + void apply_ryy(uint_t index_A, uint_t index_B, double theta); + void apply_rzz(uint_t index_A, uint_t index_B, double theta); + void apply_rzx(uint_t index_A, uint_t index_B, double theta); void apply_ccx(const reg_t &qubits); 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 8aeb56e2fb..f37b29d8a7 100644 --- a/src/simulators/matrix_product_state/matrix_product_state_tensor.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state_tensor.hpp @@ -140,9 +140,6 @@ class MPS_Tensor void apply_sdg(); void apply_t(); void apply_tdg(); - 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, bool swapped=false, bool is_diagonal=false); void apply_cnot(bool swapped = false); From b7b86c0b69c0a3bee8c6dfda13711255fd0328c0 Mon Sep 17 00:00:00 2001 From: Yael Ben-Haim Date: Wed, 18 Nov 2020 13:35:19 +0200 Subject: [PATCH 047/126] removed a debug print in test (#1041) --- test/terra/backends/qasm_simulator/qasm_standard_gates.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/terra/backends/qasm_simulator/qasm_standard_gates.py b/test/terra/backends/qasm_simulator/qasm_standard_gates.py index 5ae7e4cbf2..b4f6cc7b1d 100644 --- a/test/terra/backends/qasm_simulator/qasm_standard_gates.py +++ b/test/terra/backends/qasm_simulator/qasm_standard_gates.py @@ -103,7 +103,6 @@ def test_gate_statevector(self, gate_cls, num_params): circuit = self.gate_circuit(gate_cls, num_params=num_params, rng=self.RNG) - print(circuit.qasm()) target = Statevector.from_instruction(circuit) # Add snapshot and execute From b399e6ebd742c896b0d48d63de77c839d4574ddb Mon Sep 17 00:00:00 2001 From: hhorii Date: Thu, 19 Nov 2020 02:24:15 +0900 Subject: [PATCH 048/126] support cp in fusion to diagonal (#1024) --- src/transpile/fusion.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/transpile/fusion.hpp b/src/transpile/fusion.hpp index 50dab60b85..8fdb0c2521 100644 --- a/src/transpile/fusion.hpp +++ b/src/transpile/fusion.hpp @@ -441,7 +441,7 @@ bool Fusion::is_diagonal(const std::vector& ops, i += 2; continue; } - if (ops[i].name == "u1" || ops[i].name == "cu1") + if (ops[i].name == "u1" || ops[i].name == "cu1" || ops[i].name == "cp") continue; return false; } From d4345b23c10b264a3de0a70bbb87813309e534f6 Mon Sep 17 00:00:00 2001 From: Maureen McElaney Date: Wed, 18 Nov 2020 16:41:57 -0500 Subject: [PATCH 049/126] Qiskit projects point to main CoC (#1049) --- CODE_OF_CONDUCT.md | 116 +++------------------------------------------ 1 file changed, 6 insertions(+), 110 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 159eca449b..f82b61c5f6 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,113 +1,9 @@ -# Code of Conduct - -## Our Pledge - -The Qiskit Community is dedicated to our values of treating every individual -with respect and dignity. In the interest of fostering an open and welcoming -environment, all participants, including attendees, speakers, sponsors, -volunteers, online contributors, and IBM employees are expected to show -courtesy for each other and our community by creating a harassment-free -experience for everyone, regardless of age, personal appearance, disability, -ethnicity, gender identity and expression, body size, level of experience, -nationality, race, religion, caste, or sexual identity and orientation. -Expected behavior applies to both online and offline engagement within the -Qiskit Community. - -## Scope - -The purpose of this Code of Conduct is to define and enforce the values and -conduct of contributors and participants in the Qiskit open source community. -The Code of Conduct applies both within project spaces and in public spaces -when an individual is engaging with the Qiskit open source community. Examples -include attending a Qiskit event, contributing to online projects, commentary -on Slack, or representing a project or community, including using an official -project e-mail address, posting via an official social media account, or -acting as an appointed representative at an online or offline event. -Representation of a project may be further defined and clarified by project -maintainers. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: + -- Using welcoming and inclusive language -- Being respectful of differing viewpoints, experiences, and cultures -- Gracefully accepting constructive criticism -- Focusing on what is best for the community -- Showing empathy towards other community members -- Being mindful of your surroundings and your fellow participants and listening - to others -- Valuing the contributions of all participants -- Engaging in collaboration before conflict -- Pointing out unintentionally racist, sexist, casteist, or biased comments and - jokes made by community members when they happen - -Examples of unacceptable behavior by participants, even when presented as -"ironic" or "joking," include: - -- The use of sexualized language or imagery and unwelcome physical contact, - sexual attention, or advances -- Trolling, insulting/derogatory comments, and personal or political attacks -- Public or private harassment, including offensive or degrading language -- Publishing others' private information, such as a physical or electronic - address, without explicit permission. This includes any sort of "outing" of - any aspect of someone's identity without their consent. -- "Doxxing," Publishing screenshots or quotes, especially from identity slack - channels, private chat, or public events, without all quoted users' explicit - consent. -- Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Responsibilities & Enforcement - -The entire Qiskit community is responsible for upholding the terms of the Code -of Conduct in Qiskit Community events and spaces and reporting violations if -they see them. The internal Qiskit team at IBM is ultimately responsible for -clarifying the standards of acceptable behavior and enforcement, and is expected -to take appropriate and fair corrective action in response to any instances of -unacceptable behavior. - -If a participant or contributor engages in negative or harmful behavior, IBM -will take any action they deem appropriate, including but not limited to -issuing warnings, expulsion from an event with no refund, deleting comments, -permanent banning from future events or online community, or calling local law -enforcement. IBM has the right and responsibility to remove, edit, or reject -comments, commits, code, wiki edits, issues, and other contributions that are -not aligned to this Code of Conduct, or to temporarily or permanently ban any -contributor or participant for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -If you see a Code of Conduct violation: +# Code of Conduct +All members of this project agree to adhere to the Qiskit Code of Conduct listed at [https://github.com/Qiskit/qiskit/blob/master/CODE_OF_CONDUCT.md](https://github.com/Qiskit/qiskit/blob/master/CODE_OF_CONDUCT.md) -1. If you feel comfortable, let the person know that what they did is not - appropriate and ask them to stop and/or edit or delete their message(s) or - comment(s). -2. If the person does not immediately stop the behavior or correct the issue, - or if you're uncomfortable speaking up, flag a moderator and, if appropriate, - fill out the anonymous - [Code of Conduct violation form](https://airtable.com/shrl5mEF4Eun1aIDm). -3. The Qiskit Community will open an investigation upon receiving your form - entry. When reporting, please include any relevant details, links, - screenshots, context, or other information that may be used to better - understand and resolve the situation. -4. If the code of conduct violation occurs at an event and requires immediate - response or contains a concern about an individual attending an upcoming - event, contact the event's on-call Code of Conduct point of contact listed - in the event specific code of conduct document. If you don't feel comfortable - speaking to the point of contact in person, fill out a Code of Conduct - violation form entry and include the details of the event so that the Code of - Conduct enforcement board can contact the event's on-call Code of Conduct - point of contact. -5. If an IBM employee witnesses a Code of Conduct violation at any time, such as - at events, in a Slack channel, or open source forums, it is their - responsibility to file a Code of Conduct violation report. +---- -This Code of Conduct does not supersede existing IBM corporate policies, such as -the IBM Business Conduct Guidelines and IBM Business Partner Code of Conduct. -IBM employees must follow IBM's Business Conduct Guidelines. IBM's business -partners must follow the IBM Business Partner Code of Conduct. IBM employees -concerned with a fellow IBMer's behavior should follow IBM's own internal HR -reporting protocols, which include engaging the offending IBMer's manager and -involving IBM Concerns and Appeals. IBM employees concerned with an IBM -business partner's behavior should notify tellibm@us.ibm.com. +License: [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), +Copyright Contributors to Qiskit. From c8ee233f6db7e308d3d4e863ea042272ab40b0cd Mon Sep 17 00:00:00 2001 From: Yael Ben-Haim Date: Thu, 19 Nov 2020 12:42:59 +0200 Subject: [PATCH 050/126] added const (#1044) --- src/simulators/matrix_product_state/svd.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/simulators/matrix_product_state/svd.cpp b/src/simulators/matrix_product_state/svd.cpp index 73ab95d5e0..13ca968a86 100644 --- a/src/simulators/matrix_product_state/svd.cpp +++ b/src/simulators/matrix_product_state/svd.cpp @@ -135,7 +135,8 @@ void reduce_zeros(cmatrix_t &U, rvector_t &S, cmatrix_t &V, } } -void validate_SVD_result(cmatrix_t &A, cmatrix_t &U, rvector_t &S, cmatrix_t &V) { +void validate_SVD_result(const cmatrix_t &A, const cmatrix_t &U, + const rvector_t &S, const cmatrix_t &V) { const uint_t nrows = A.GetRows(), ncols = A.GetColumns(); cmatrix_t diag_S = diag(S, nrows, ncols); cmatrix_t product = U*diag_S; From 55d170a912031eadb0ce5ad3bff0ac65f2ffa20c Mon Sep 17 00:00:00 2001 From: Victor Villar Date: Mon, 23 Nov 2020 07:44:21 +0100 Subject: [PATCH 051/126] Remove all remaining cython references (#1050) --- .github/workflows/main.yml | 2 +- azure-pipelines.yml | 4 +- cmake/UseCython.cmake | 396 ------------------------------------- pyproject.toml | 2 +- test/asv.linux.conf.json | 2 +- 5 files changed, 5 insertions(+), 401 deletions(-) delete mode 100644 cmake/UseCython.cmake diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a78693e237..715d6d1b03 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -170,7 +170,7 @@ jobs: - name: Build Wheels env: CIBW_BEFORE_ALL_LINUX: "yum install -y openblas-devel" - CIBW_BEFORE_BUILD: "pip install -U Cython virtualenv pybind11" + CIBW_BEFORE_BUILD: "pip install -U virtualenv pybind11" CIBW_SKIP: "cp27-* cp34-* cp35-* pp*" CIBW_MANYLINUX_X86_64_IMAGE: "manylinux2010" CIBW_MANYLINUX_I686_IMAGE: "manylinux2010" diff --git a/azure-pipelines.yml b/azure-pipelines.yml index ce4c9870a0..af69c02292 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -99,7 +99,7 @@ stages: mkdir wheelhouse for version in 3.6 3.7 3.8 ; do source activate qiskit-aer-$version - conda install --yes --quiet --name qiskit-aer-$version python=$version numpy cmake pip setuptools pybind11 cython scipy + conda install --yes --quiet --name qiskit-aer-$version python=$version numpy cmake pip setuptools pybind11 scipy python -m pip install -U setuptools wheel python setup.py bdist_wheel -- -G "Visual Studio 15 2017" conda create --yes --quiet python=$version --name test-$version @@ -243,7 +243,7 @@ stages: source activate qiskit-aer conda update --yes -n base conda conda config --add channels conda-forge - conda install --yes --quiet --name qiskit-aer python=$(python.version) numpy cmake pip setuptools pybind11 cython scipy + conda install --yes --quiet --name qiskit-aer python=$(python.version) numpy cmake pip setuptools pybind11 scipy displayName: Create Anaconda environments - bash: | set -x diff --git a/cmake/UseCython.cmake b/cmake/UseCython.cmake deleted file mode 100644 index a38eb65c35..0000000000 --- a/cmake/UseCython.cmake +++ /dev/null @@ -1,396 +0,0 @@ -#.rst: -# -# The following functions are defined: -# -# .. cmake:command:: add_cython_target -# -# Create a custom rule to generate the source code for a Python extension module -# using cython. -# -# add_cython_target( [] -# [EMBED_MAIN] -# [C | CXX] -# [PY2 | PY3] -# [OUTPUT_VAR ]) -# -# ```` is the name of the new target, and ```` -# is the path to a cython source file. Note that, despite the name, no new -# targets are created by this function. Instead, see ``OUTPUT_VAR`` for -# retrieving the path to the generated source for subsequent targets. -# -# If only ```` is provided, and it ends in the ".pyx" extension, then it -# is assumed to be the ````. The name of the input without the -# extension is used as the target name. If only ```` is provided, and it -# does not end in the ".pyx" extension, then the ```` is assumed to -# be ``.pyx``. -# -# The Cython include search path is amended with any entries found in the -# ``INCLUDE_DIRECTORIES`` property of the directory containing the -# ```` file. Use ``include_directories`` to add to the Cython -# include search path. -# -# Options: -# -# ``EMBED_MAIN`` -# Embed a main() function in the generated output (for stand-alone -# applications that initialize their own Python runtime). -# -# ``C | CXX`` -# Force the generation of either a C or C++ file. By default, a C file is -# generated, unless the C language is not enabled for the project; in this -# case, a C++ file is generated by default. -# -# ``PY2 | PY3`` -# Force compilation using either Python-2 or Python-3 syntax and code -# semantics. By default, Python-2 syntax and semantics are used if the major -# version of Python found is 2. Otherwise, Python-3 syntax and sematics are -# used. -# -# ``OUTPUT_VAR `` -# Set the variable ```` in the parent scope to the path to the -# generated source file. By default, ```` is used as the output -# variable name. -# -# Defined variables: -# -# ```` -# The path of the generated source file. -# -# Cache variables that effect the behavior include: -# -# ``CYTHON_ANNOTATE`` -# whether to create an annotated .html file when compiling -# -# ``CYTHON_FLAGS`` -# additional flags to pass to the Cython compiler -# -# Example usage -# ^^^^^^^^^^^^^ -# -# .. code-block:: cmake -# -# find_package(Cython) -# -# # Note: In this case, either one of these arguments may be omitted; their -# # value would have been inferred from that of the other. -# add_cython_target(cy_code cy_code.pyx) -# -# add_library(cy_code MODULE ${cy_code}) -# target_link_libraries(cy_code ...) -# -#============================================================================= -# Copyright 2011 Kitware, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#============================================================================= - -# Configuration options. -set(CYTHON_ANNOTATE OFF - CACHE BOOL "Create an annotated .html file when compiling *.pyx.") - -set(CYTHON_FLAGS "" CACHE STRING - "Extra flags to the cython compiler.") -mark_as_advanced(CYTHON_ANNOTATE CYTHON_FLAGS) -string(REGEX REPLACE " " ";" CYTHON_FLAGS_LIST "${CYTHON_FLAGS}") - -find_package(PythonLibs REQUIRED) - -set(CYTHON_CXX_EXTENSION "cxx") -set(CYTHON_C_EXTENSION "c") - -get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES) - -function(add_cython_target _name) - set(options EMBED_MAIN C CXX PY2 PY3) - set(options1 OUTPUT_VAR) - cmake_parse_arguments(_args "${options}" "${options1}" "" ${ARGN}) - - list(GET _args_UNPARSED_ARGUMENTS 0 _arg0) - - # if provided, use _arg0 as the input file path - if(_arg0) - set(_source_file ${_arg0}) - - # otherwise, must determine source file from name, or vice versa - else() - get_filename_component(_name_ext "${_name}" EXT) - - # if extension provided, _name is the source file - if(_name_ext) - set(_source_file ${_name}) - get_filename_component(_name "${_source_file}" NAME_WE) - - # otherwise, assume the source file is ${_name}.pyx - else() - set(_source_file ${_name}.pyx) - endif() - endif() - - set(_embed_main FALSE) - - if("C" IN_LIST languages) - set(_output_syntax "C") - elseif("CXX" IN_LIST languages) - set(_output_syntax "CXX") - else() - message(FATAL_ERROR "Either C or CXX must be enabled to use Cython") - endif() - - if("${PYTHONLIBS_VERSION_STRING}" MATCHES "^2.") - set(_input_syntax "PY2") - else() - set(_input_syntax "PY3") - endif() - - if(_args_EMBED_MAIN) - set(_embed_main TRUE) - endif() - - if(_args_C) - set(_output_syntax "C") - endif() - - if(_args_CXX) - set(_output_syntax "CXX") - endif() - - if(_args_PY2) - set(_input_syntax "PY2") - endif() - - if(_args_PY3) - set(_input_syntax "PY3") - endif() - - set(embed_arg "") - if(_embed_main) - set(embed_arg "--embed") - endif() - - set(cxx_arg "") - set(extension "c") - if(_output_syntax STREQUAL "CXX") - set(cxx_arg "--cplus") - set(extension "cxx") - endif() - - set(py_version_arg "") - if(_input_syntax STREQUAL "PY2") - set(py_version_arg "-2") - elseif(_input_syntax STREQUAL "PY3") - set(py_version_arg "-3") - endif() - - set(generated_file "${CMAKE_CURRENT_BINARY_DIR}/${_name}.${extension}") - set_source_files_properties(${generated_file} PROPERTIES GENERATED TRUE) - - set(_output_var ${_name}) - if(_args_OUTPUT_VAR) - set(_output_var ${_args_OUTPUT_VAR}) - endif() - set(${_output_var} ${generated_file} PARENT_SCOPE) - - file(RELATIVE_PATH generated_file_relative - ${CMAKE_BINARY_DIR} ${generated_file}) - - set(comment "Generating ${_output_syntax} source ${generated_file_relative}") - set(cython_include_directories "") - set(pxd_dependencies "") - set(c_header_dependencies "") - - # Get the include directories. - get_source_file_property(pyx_location ${_source_file} LOCATION) - get_filename_component(pyx_path ${pyx_location} PATH) - get_directory_property(cmake_include_directories - DIRECTORY ${pyx_path} - INCLUDE_DIRECTORIES) - list(APPEND cython_include_directories ${cmake_include_directories}) - - # Determine dependencies. - # Add the pxd file with the same basename as the given pyx file. - get_filename_component(pyx_file_basename ${_source_file} NAME_WE) - unset(corresponding_pxd_file CACHE) - find_file(corresponding_pxd_file ${pyx_file_basename}.pxd - PATHS "${pyx_path}" ${cmake_include_directories} - NO_DEFAULT_PATH) - if(corresponding_pxd_file) - list(APPEND pxd_dependencies "${corresponding_pxd_file}") - endif() - - # pxd files to check for additional dependencies - set(pxds_to_check "${_source_file}" "${pxd_dependencies}") - set(pxds_checked "") - set(number_pxds_to_check 1) - while(number_pxds_to_check GREATER 0) - foreach(pxd ${pxds_to_check}) - list(APPEND pxds_checked "${pxd}") - list(REMOVE_ITEM pxds_to_check "${pxd}") - - # look for C headers - file(STRINGS "${pxd}" extern_from_statements - REGEX "cdef[ ]+extern[ ]+from.*$") - foreach(statement ${extern_from_statements}) - # Had trouble getting the quote in the regex - string(REGEX REPLACE - "cdef[ ]+extern[ ]+from[ ]+[\"]([^\"]+)[\"].*" "\\1" - header "${statement}") - unset(header_location CACHE) - find_file(header_location ${header} PATHS ${cmake_include_directories}) - if(header_location) - list(FIND c_header_dependencies "${header_location}" header_idx) - if(${header_idx} LESS 0) - list(APPEND c_header_dependencies "${header_location}") - endif() - endif() - endforeach() - - # check for pxd dependencies - # Look for cimport statements. - set(module_dependencies "") - file(STRINGS "${pxd}" cimport_statements REGEX cimport) - foreach(statement ${cimport_statements}) - if(${statement} MATCHES from) - string(REGEX REPLACE - "from[ ]+([^ ]+).*" "\\1" - module "${statement}") - else() - string(REGEX REPLACE - "cimport[ ]+([^ ]+).*" "\\1" - module "${statement}") - endif() - list(APPEND module_dependencies ${module}) - endforeach() - - # check for pxi dependencies - # Look for include statements. - set(include_dependencies "") - file(STRINGS "${pxd}" include_statements REGEX include) - foreach(statement ${include_statements}) - string(REGEX REPLACE - "include[ ]+[\"]([^\"]+)[\"].*" "\\1" - module "${statement}") - list(APPEND include_dependencies ${module}) - endforeach() - - list(REMOVE_DUPLICATES module_dependencies) - list(REMOVE_DUPLICATES include_dependencies) - - # Add modules to the files to check, if appropriate. - foreach(module ${module_dependencies}) - unset(pxd_location CACHE) - find_file(pxd_location ${module}.pxd - PATHS "${pyx_path}" ${cmake_include_directories} - NO_DEFAULT_PATH) - if(pxd_location) - list(FIND pxds_checked ${pxd_location} pxd_idx) - if(${pxd_idx} LESS 0) - list(FIND pxds_to_check ${pxd_location} pxd_idx) - if(${pxd_idx} LESS 0) - list(APPEND pxds_to_check ${pxd_location}) - list(APPEND pxd_dependencies ${pxd_location}) - endif() # if it is not already going to be checked - endif() # if it has not already been checked - endif() # if pxd file can be found - endforeach() # for each module dependency discovered - - # Add includes to the files to check, if appropriate. - foreach(_include ${include_dependencies}) - unset(pxi_location CACHE) - find_file(pxi_location ${_include} - PATHS "${pyx_path}" ${cmake_include_directories} - NO_DEFAULT_PATH) - if(pxi_location) - list(FIND pxds_checked ${pxi_location} pxd_idx) - if(${pxd_idx} LESS 0) - list(FIND pxds_to_check ${pxi_location} pxd_idx) - if(${pxd_idx} LESS 0) - list(APPEND pxds_to_check ${pxi_location}) - list(APPEND pxd_dependencies ${pxi_location}) - endif() # if it is not already going to be checked - endif() # if it has not already been checked - endif() # if include file can be found - endforeach() # for each include dependency discovered - endforeach() # for each include file to check - - list(LENGTH pxds_to_check number_pxds_to_check) - endwhile() - - # Set additional flags. - set(annotate_arg "") - if(CYTHON_ANNOTATE) - set(annotate_arg "--annotate") - endif() - - set(no_docstrings_arg "") - if(CMAKE_BUILD_TYPE STREQUAL "Release" OR - CMAKE_BUILD_TYPE STREQUAL "MinSizeRel") - set(no_docstrings_arg "--no-docstrings") - endif() - - set(cython_debug_arg "") - set(embed_pos_arg "") - set(line_directives_arg "") - if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR - CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") - set(cython_debug_arg "--gdb") - set(embed_pos_arg "--embed-positions") - set(line_directives_arg "--line-directives") - endif() - - # Include directory arguments. - list(REMOVE_DUPLICATES cython_include_directories) - set(include_directory_arg "") - foreach(_include_dir ${cython_include_directories}) - set(include_directory_arg - ${include_directory_arg} "--include-dir" "${_include_dir}") - endforeach() - - list(REMOVE_DUPLICATES pxd_dependencies) - list(REMOVE_DUPLICATES c_header_dependencies) - - # Add the command to run the compiler. - add_custom_command(OUTPUT ${generated_file} - COMMAND ${CYTHON_EXECUTABLE} - ARGS ${cxx_arg} ${include_directory_arg} ${py_version_arg} - ${embed_arg} ${annotate_arg} ${no_docstrings_arg} - ${cython_debug_arg} ${embed_pos_arg} - ${line_directives_arg} ${CYTHON_FLAGS_LIST} ${pyx_location} - --output-file ${generated_file} - DEPENDS ${_source_file} - ${pxd_dependencies} - IMPLICIT_DEPENDS ${_output_syntax} - ${c_header_dependencies} - COMMENT ${comment}) - - # NOTE(opadron): I thought about making a proper target, but after trying it - # out, I decided that it would be far too convenient to use the same name as - # the target for the extension module (e.g.: for single-file modules): - # - # ... - # add_cython_target(_module.pyx) - # add_library(_module ${_module}) - # ... - # - # The above example would not be possible since the "_module" target name - # would already be taken by the cython target. Since I can't think of a - # reason why someone would need the custom target instead of just using the - # generated file directly, I decided to leave this commented out. - # - # add_custom_target(${_name} DEPENDS ${generated_file}) - - # Remove their visibility to the user. - set(corresponding_pxd_file "" CACHE INTERNAL "") - set(header_location "" CACHE INTERNAL "") - set(pxd_location "" CACHE INTERNAL "") -endfunction() - diff --git a/pyproject.toml b/pyproject.toml index 0e00e6d818..e2afe703fa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,2 +1,2 @@ [build-system] -requires = ["setuptools", "wheel", "urllib3<1.26", "conan>=1.22.2", "scikit-build", "cmake!=3.17.1,!=3.17.0", "ninja", "pybind11>2.4", "Cython>0.27.1"] +requires = ["setuptools", "wheel", "urllib3<1.26", "conan>=1.22.2", "scikit-build", "cmake!=3.17.1,!=3.17.0", "ninja", "pybind11>2.4"] diff --git a/test/asv.linux.conf.json b/test/asv.linux.conf.json index 597cbe453f..19a372418d 100644 --- a/test/asv.linux.conf.json +++ b/test/asv.linux.conf.json @@ -43,7 +43,7 @@ "return-code=any python -mpip uninstall -y {project}" ], "build_command": [ - "python -mpip install -U scikit-build cython", + "python -mpip install -U scikit-build", "pip install git+https://github.com/Qiskit/qiskit-terra", "pip install git+https://github.com/Qiskit/qiskit-aqua", "pip install pyscf", From 325ae570b3b7cbe5630a3ec21ed4efcaf2540f09 Mon Sep 17 00:00:00 2001 From: Victor Villar Date: Tue, 24 Nov 2020 08:27:35 +0100 Subject: [PATCH 052/126] Run C++ unit tests on CI (#1051) --- .github/workflows/main.yml | 19 +++++++++++++++++-- test/CMakeLists.txt | 5 +++++ test/src/test_linalg.cpp | 2 ++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 715d6d1b03..17397c016e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -95,17 +95,32 @@ jobs: - name: Compile Standalone Windows run: | set -e - mkdir out; cd out; cmake .. + mkdir out; cd out; cmake .. -DBUILD_TESTS=1 cmake --build . --config Release shell: bash if: runner.os == 'Windows' - name: Compile Standalone run: | set -e - mkdir out; cd out; cmake .. + mkdir out; cd out; cmake .. -DBUILD_TESTS=1 make shell: bash if: runner.os != 'Windows' + - name: Run Unit Tests + run: | + cd out/bin + for test in test* + do echo $test + if ! ./$test + then + ERR=1 + fi + done + if [ ! -z "$ERR" ] + then + exit 1 + fi + shell: bash sdist: name: compile-sdist-python${{ matrix.python-version }}-${{ matrix.platform.os }} runs-on: ${{ matrix.platform.os }} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4bf917e347..ea92f6946c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -11,6 +11,11 @@ macro(add_test_executable target_name) PRIVATE AER_DEPENDENCY_PKG::catch2 PRIVATE ${AER_LIBRARIES}) add_test(${target_name} ${target_name}) + if(WIN32 AND NOT BLAS_LIB_PATH) + add_custom_command(TARGET test_linalg POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${BACKEND_REDIST_DEPS} + $) + endif() endmacro() add_test_executable(test_linalg "src/test_linalg.cpp") diff --git a/test/src/test_linalg.cpp b/test/src/test_linalg.cpp index f1fdfffecc..e3843f1544 100644 --- a/test/src/test_linalg.cpp +++ b/test/src/test_linalg.cpp @@ -12,6 +12,8 @@ * that they have been altered from the originals. */ +#define _USE_MATH_DEFINES +#include #include #include #include From 294fd36bb7275c6e2f2402a47011db5fba49ca53 Mon Sep 17 00:00:00 2001 From: hhorii Date: Wed, 25 Nov 2020 12:36:32 +0900 Subject: [PATCH 053/126] reduce overhads to check available methods in qasm simulator (#1053) --- qiskit/providers/aer/backends/backend_utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/qiskit/providers/aer/backends/backend_utils.py b/qiskit/providers/aer/backends/backend_utils.py index 053722aeae..6d080cc465 100644 --- a/qiskit/providers/aer/backends/backend_utils.py +++ b/qiskit/providers/aer/backends/backend_utils.py @@ -61,6 +61,7 @@ def available_methods(controller, methods): for method in methods: qobj = assemble(dummy_circ, optimization_level=0, + shots=1, method=method) result = cpp_execute(controller, qobj) if result.get('success', False): From 47820f367967851e45fbce76d609d62e678d70b4 Mon Sep 17 00:00:00 2001 From: Victor Villar Date: Wed, 25 Nov 2020 09:26:55 +0100 Subject: [PATCH 054/126] Fix mismatch between BLAS_LIB_PATH and AER_BLAS_LIB_PATH (#1054) Co-authored-by: Christopher J. Wood --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 354fbf6127..ad0ba19b06 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -193,8 +193,8 @@ if(STATIC_LINKING) set(BLA_STATIC TRUE) endif() -if(BLAS_LIB_PATH) - find_BLAS_in_specific_path(${BLAS_LIB_PATH}) +if(AER_BLAS_LIB_PATH) + find_BLAS_in_specific_path(${AER_BLAS_LIB_PATH}) else() if(APPLE) message(STATUS "Looking for Apple BLAS & Lapack library...") @@ -350,7 +350,7 @@ else() # Standalone build PRIVATE ${AER_SIMULATOR_CPP_EXTERNAL_LIBS}) target_compile_definitions(qasm_simulator PRIVATE ${AER_COMPILER_DEFINITIONS}) - if(WIN32 AND NOT BLAS_LIB_PATH) + if(WIN32 AND NOT AER_BLAS_LIB_PATH) add_custom_command(TARGET qasm_simulator POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${BACKEND_REDIST_DEPS} $) From 1b6accdb7fbf32dfd668ddb0a753706c63ba7d27 Mon Sep 17 00:00:00 2001 From: "Christopher J. Wood" Date: Thu, 26 Nov 2020 13:44:33 -0500 Subject: [PATCH 055/126] Fix bug with nested omp being applied incorrectly (#1055) --- .../fix-omp-nested-9d120cd1a08725ab.yaml | 5 ++++ src/controllers/controller.hpp | 26 ++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 releasenotes/notes/fix-omp-nested-9d120cd1a08725ab.yaml diff --git a/releasenotes/notes/fix-omp-nested-9d120cd1a08725ab.yaml b/releasenotes/notes/fix-omp-nested-9d120cd1a08725ab.yaml new file mode 100644 index 0000000000..bab20a0be8 --- /dev/null +++ b/releasenotes/notes/fix-omp-nested-9d120cd1a08725ab.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + Fixes a bug with nested OpenMP flag was being set to true when it + shouldn't be. diff --git a/src/controllers/controller.hpp b/src/controllers/controller.hpp index 4d620c0f3e..0aab6130c8 100755 --- a/src/controllers/controller.hpp +++ b/src/controllers/controller.hpp @@ -218,6 +218,7 @@ class Controller { int parallel_experiments_; int parallel_shots_; int parallel_state_update_; + bool parallel_nested_ = false; }; //========================================================================= @@ -252,6 +253,7 @@ void Controller::set_config(const json_t &config) { max_parallel_threads_ = 1; max_parallel_shots_ = 1; max_parallel_experiments_ = 1; + parallel_nested_ = false; #endif // Load configurations for parallelization @@ -298,6 +300,7 @@ void Controller::clear_parallelization() { parallel_experiments_ = 1; parallel_shots_ = 1; parallel_state_update_ = 1; + parallel_nested_ = false; explicit_parallelization_ = false; max_memory_mb_ = get_system_memory_mb() / 2; @@ -542,8 +545,16 @@ Result Controller::execute(std::vector &circuits, result.metadata["max_memory_mb"] = max_memory_mb_; #ifdef _OPENMP - if (parallel_shots_ > 1 || parallel_state_update_ > 1) + // Check if circuit parallelism is nested with one of the others + if (parallel_experiments_ > 1 && parallel_experiments_ < max_parallel_threads_) { + // Nested parallel experiments + parallel_nested_ = true; omp_set_nested(1); + result.metadata["omp_nested"] = parallel_nested_; + } else { + parallel_nested_ = false; + omp_set_nested(0); + } #endif // then- and else-blocks have intentionally duplication. // Nested omp has significant overheads even though a guard condition exists. @@ -645,6 +656,19 @@ void Controller::execute_circuit(Circuit &circ, // Vector to store parallel thread output data std::vector par_results(parallel_shots_); std::vector error_msgs(parallel_shots_); + + #ifdef _OPENMP + if (!parallel_nested_) { + if (parallel_shots_ > 1 && parallel_state_update_ > 1) { + // Nested parallel shots + state update + omp_set_nested(1); + result.metadata["omp_nested"] = true; + } else { + omp_set_nested(0); + } + } + #endif + #pragma omp parallel for if (parallel_shots_ > 1) num_threads(parallel_shots_) for (int i = 0; i < parallel_shots_; i++) { try { From 0cb6cc4741bf29aa3e67a8333047c8cb7c37db9c Mon Sep 17 00:00:00 2001 From: "Christopher J. Wood" Date: Wed, 2 Dec 2020 05:14:30 -0500 Subject: [PATCH 056/126] Remove deprecated usage of omp_set_nested (#1061) On mac and linux use `omp_set_max_active_levels` instead of `omp_set_nested` --- src/controllers/controller.hpp | 16 ++++++++++++++++ src/misc/clang_omp_symbols.hpp | 6 ++++++ src/misc/gcc_omp_symbols.hpp | 6 ++++++ 3 files changed, 28 insertions(+) diff --git a/src/controllers/controller.hpp b/src/controllers/controller.hpp index 0aab6130c8..d2a9787c80 100755 --- a/src/controllers/controller.hpp +++ b/src/controllers/controller.hpp @@ -549,11 +549,19 @@ Result Controller::execute(std::vector &circuits, if (parallel_experiments_ > 1 && parallel_experiments_ < max_parallel_threads_) { // Nested parallel experiments parallel_nested_ = true; + #ifdef _WIN32 omp_set_nested(1); + #else + omp_set_max_active_levels(3); + #endif result.metadata["omp_nested"] = parallel_nested_; } else { parallel_nested_ = false; + #ifdef _WIN32 omp_set_nested(0); + #else + omp_set_max_active_levels(1); + #endif } #endif // then- and else-blocks have intentionally duplication. @@ -661,10 +669,18 @@ void Controller::execute_circuit(Circuit &circ, if (!parallel_nested_) { if (parallel_shots_ > 1 && parallel_state_update_ > 1) { // Nested parallel shots + state update + #ifdef _WIN32 omp_set_nested(1); + #else + omp_set_max_active_levels(2); + #endif result.metadata["omp_nested"] = true; } else { + #ifdef _WIN32 omp_set_nested(0); + #else + omp_set_max_active_levels(1); + #endif } } #endif diff --git a/src/misc/clang_omp_symbols.hpp b/src/misc/clang_omp_symbols.hpp index 5d405d2b2b..0e3bae3671 100644 --- a/src/misc/clang_omp_symbols.hpp +++ b/src/misc/clang_omp_symbols.hpp @@ -218,6 +218,11 @@ extern "C" { void __KAI_KMPC_CONVENTION omp_set_nested(int foo){ _hook_omp_set_nested(foo); } + using omp_set_max_active_levels_t = void(*)(int); + omp_set_max_active_levels_t _hook_omp_set_max_active_levels; + void __KAI_KMPC_CONVENTION omp_set_max_active_levels(int foo){ + _hook_omp_set_max_active_levels(foo); + } using omp_get_num_procs_t = int(*)(void); omp_get_num_procs_t _hook_omp_get_num_procs; int __KAI_KMPC_CONVENTION omp_get_num_procs(void) { @@ -325,6 +330,7 @@ void populate_hooks(void * handle){ _hook_omp_get_num_threads = reinterpret_cast(dlsym(handle, "omp_get_num_threads")); _hook_omp_get_thread_num = reinterpret_cast(dlsym(handle, "omp_get_thread_num")); _hook_omp_set_nested = reinterpret_cast(dlsym(handle, "omp_set_nested")); + _hook_omp_set_max_active_levels = reinterpret_cast(dlsym(handle, "omp_set_max_active_levels")); _hook_omp_get_num_procs = reinterpret_cast(dlsym(handle, "omp_get_num_procs")); } diff --git a/src/misc/gcc_omp_symbols.hpp b/src/misc/gcc_omp_symbols.hpp index 3268d1dbee..3ff2b0f162 100644 --- a/src/misc/gcc_omp_symbols.hpp +++ b/src/misc/gcc_omp_symbols.hpp @@ -71,6 +71,11 @@ extern "C" { void __KAI_KMPC_CONVENTION omp_set_nested(int foo){ _hook_omp_set_nested(foo); } + using omp_set_max_active_levels_t = void(*)(int); + omp_set_max_active_levels_t _hook_omp_set_max_active_levels; + void __KAI_KMPC_CONVENTION omp_set_max_active_levels(int foo){ + _hook_omp_set_max_active_levels(foo); + } using omp_get_num_threads_t = int(*)(void); omp_get_num_threads_t _hook_omp_get_num_threads; int __KAI_KMPC_CONVENTION omp_get_num_threads(void) { @@ -101,6 +106,7 @@ namespace Hacks { _hook_omp_get_num_threads = reinterpret_cast(dlsym(handle, "omp_get_num_threads")); _hook_omp_get_max_threads = reinterpret_cast(dlsym(handle, "omp_get_max_threads")); _hook_omp_set_nested = reinterpret_cast(dlsym(handle, "omp_set_nested")); + _hook_omp_set_max_active_levels = reinterpret_cast(dlsym(handle, "omp_set_max_active_levels")); _hook_omp_get_thread_num = reinterpret_cast(dlsym(handle, "omp_get_thread_num")); _hook_omp_get_num_procs = reinterpret_cast(dlsym(handle, "omp_get_num_procs")); } From 90727a9e96d8ff122aa5277dfc696274e1e1fe01 Mon Sep 17 00:00:00 2001 From: "Christopher J. Wood" Date: Wed, 2 Dec 2020 17:30:59 -0500 Subject: [PATCH 057/126] Break main GHA into multiple workflows (#1064) --- .github/workflows/build.yml | 86 +++++ .github/workflows/{wheels.yml => deploy.yml} | 2 +- .github/workflows/docs.yml | 88 +++++ .github/workflows/main.yml | 318 ------------------- .github/workflows/tests_linux.yml | 126 ++++++++ .github/workflows/tests_mac.yml | 125 ++++++++ .github/workflows/tests_windows.yml | 83 +++++ 7 files changed, 509 insertions(+), 319 deletions(-) create mode 100644 .github/workflows/build.yml rename .github/workflows/{wheels.yml => deploy.yml} (99%) create mode 100644 .github/workflows/docs.yml delete mode 100644 .github/workflows/main.yml create mode 100644 .github/workflows/tests_linux.yml create mode 100644 .github/workflows/tests_mac.yml create mode 100644 .github/workflows/tests_windows.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000000..c4e18a5eca --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,86 @@ +name: Build +on: + push: + branches: [master, 'stable/*'] + pull_request: + branches: [master, 'stable/*'] +jobs: + standalone: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: ["macOS-latest", "ubuntu-latest", "windows-latest"] + steps: + - uses: actions/checkout@v2 + - name: Set up Python 3.7 + uses: actions/setup-python@v2 + with: + python-version: 3.7 + - name: Install deps + run: pip install "urllib3<1.26" conan + - name: Install openblas + run: | + set -e + sudo apt-get update + sudo apt-get install -y libopenblas-dev + shell: bash + if: runner.os == 'Linux' + - name: Add msbuild to PATH + uses: microsoft/setup-msbuild@v1.0.2 + if: runner.os == 'Windows' + - name: Compile Standalone Windows + run: | + set -e + mkdir out; cd out; cmake .. -DBUILD_TESTS=1 + cmake --build . --config Release + shell: bash + if: runner.os == 'Windows' + - name: Compile Standalone + run: | + set -e + mkdir out; cd out; cmake .. -DBUILD_TESTS=1 + make + shell: bash + if: runner.os != 'Windows' + - name: Run Unit Tests + run: | + cd out/bin + for test in test* + do echo $test + if ! ./$test + then + ERR=1 + fi + done + if [ ! -z "$ERR" ] + then + exit 1 + fi + shell: bash + wheel: + runs-on: ${{ matrix.os }} + needs: ["standalone"] + strategy: + matrix: + os: ["macOS-latest", "ubuntu-latest"] + steps: + - uses: actions/checkout@v2 + - name: Set up Python Python 3.8 + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: Install deps + run: python -m pip install -U cibuildwheel==1.7.0 + - name: Build Wheels + env: + CIBW_BEFORE_ALL_LINUX: "yum install -y openblas-devel" + CIBW_BEFORE_BUILD: "pip install -U virtualenv pybind11" + CIBW_SKIP: "cp27-* cp34-* cp35-* cp39-* pp*" + CIBW_MANYLINUX_X86_64_IMAGE: "manylinux2010" + CIBW_MANYLINUX_I686_IMAGE: "manylinux2010" + CIBW_TEST_COMMAND: "python3 {project}/tools/verify_wheels.py" + CIBW_TEST_REQUIRES: "git+https://github.com/Qiskit/qiskit-terra.git" + run: cibuildwheel --output-dir wheelhouse + - uses: actions/upload-artifact@v2 + with: + path: ./wheelhouse/*.whl diff --git a/.github/workflows/wheels.yml b/.github/workflows/deploy.yml similarity index 99% rename from .github/workflows/wheels.yml rename to .github/workflows/deploy.yml index 932f0f8249..8784790f5c 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/deploy.yml @@ -1,4 +1,4 @@ -name: Build +name: Deploy on: push: tags: diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000000..0b09f548c7 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,88 @@ +name: Docs and Tutorial +on: + push: + branches: [master, 'stable/*'] + pull_request: + branches: [master, 'stable/*'] +jobs: + docs: + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + matrix: + python-version: [3.7] + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Pip cache + uses: actions/cache@v2 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-${{ matrix.python-version}}-pip-docs-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} + restore-keys: | + ${{ runner.os }}-${{ matrix.python-version}}-pip-docs- + ${{ runner.os }}-${{ matrix.python-version}}-pip- + ${{ runner.os }}-${{ matrix.python-version}}- + - name: Install Deps + run: | + set -e + pip install -U pip virtualenv wheel + pip install -U tox + sudo apt-get update + sudo apt-get install -y build-essential libopenblas-dev + shell: bash + - name: Run Docs Build + run: tox -edocs + - uses: actions/upload-artifact@v2 + with: + name: html_docs + path: docs/_build/html + tutorials: + runs-on: ubuntu-latest + needs: [docs] + strategy: + matrix: + python-version: [3.7] + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Pip cache + uses: actions/cache@v2 + with: + path: ~\AppData\Local\pip\Cache + key: ${{ runner.os }}-${{ matrix.python-version}}-pip-tutorials-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} + restore-keys: | + ${{ runner.os }}-${{ matrix.python-version}}-pip-tutorials- + ${{ runner.os }}-${{ matrix.python-version}}-pip- + ${{ runner.os }}-${{ matrix.python-version}}}- + - name: Setup tutorials job + run: | + set -e + git clone https://github.com/Qiskit/qiskit-tutorials --depth=1 + python -m pip install --upgrade pip wheel + pip install -U -r requirements-dev.txt -c constraints.txt + pip install -c constraints.txt git+https://github.com/Qiskit/qiskit-terra + pip install -c constraints.txt . + pip install -U "qiskit-ibmq-provider" "z3-solver" "qiskit-ignis" "qiskit-aqua" "pyscf<1.7.4" "matplotlib<3.3.0" jupyter pylatexenc sphinx nbsphinx sphinx_rtd_theme cvxpy -c constraints.txt + python setup.py build_ext --inplace + sudo apt install -y graphviz pandoc libopenblas-dev + pip check + shell: bash + - name: Run Tutorials + run: | + set -e + cd qiskit-tutorials + rm -rf tutorials/chemistry tutorials/circuits tutorials/circuits_advanced tutorials/finance tutorials/optimization tutorials/noise + sphinx-build -b html . _build/html + - uses: actions/upload-artifact@v2 + with: + name: tutorials_html + path: qiskit-tutorials/_build/html diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index 17397c016e..0000000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,318 +0,0 @@ -name: Compile tests -on: - push: - branches: [master, 'stable/*'] - pull_request: - branches: [master, 'stable/*'] -jobs: - lint: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Set up Python 3.8 - uses: actions/setup-python@v2 - with: - python-version: 3.8 - - name: Pip cache - uses: actions/cache@v2 - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-lint-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} - restore-keys: | - ${{ runner.os }}-pip-lint- - ${{ runner.os }}-pip- - ${{ runner.os }}- - - name: Install deps - run: | - set -e - pip install -U pip wheel - pip install -U -c constraints.txt git+https://github.com/Qiskit/qiskit-terra - pip install -U -c constraints.txt -r requirements-dev.txt - shell: bash - - name: Run Lint - run: | - set -e - pycodestyle --ignore=E402,W504 --max-line-length=100 qiskit/providers/aer - pylint -j 2 -rn qiskit/providers/aer - docs: - runs-on: ubuntu-latest - timeout-minutes: 60 - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - name: Set up Python 3.7 - uses: actions/setup-python@v2 - with: - python-version: 3.7 - - name: Pip cache - uses: actions/cache@v2 - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-docs-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} - restore-keys: | - ${{ runner.os }}-pip-docs- - ${{ runner.os }}-pip- - ${{ runner.os }}- - - name: Install Deps - run: | - set -e - pip install -U pip virtualenv wheel - pip install -U tox - sudo apt-get update - sudo apt-get install -y build-essential libopenblas-dev - shell: bash - - name: Run Docs Build - run: tox -edocs - - uses: actions/upload-artifact@v2 - with: - name: html_docs - path: docs/_build/html - standalone: - name: compile-standalone-${{ matrix.os }} - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: ["macOS-latest", "ubuntu-latest", "windows-latest"] - steps: - - uses: actions/checkout@v2 - - name: Set up Python 3.7 - uses: actions/setup-python@v2 - with: - python-version: 3.7 - - name: Install deps - run: pip install "urllib3<1.26" conan - - name: Install openblas - run: | - set -e - sudo apt-get update - sudo apt-get install -y libopenblas-dev - shell: bash - if: runner.os == 'Linux' - - name: Add msbuild to PATH - uses: microsoft/setup-msbuild@v1.0.2 - if: runner.os == 'Windows' - - name: Compile Standalone Windows - run: | - set -e - mkdir out; cd out; cmake .. -DBUILD_TESTS=1 - cmake --build . --config Release - shell: bash - if: runner.os == 'Windows' - - name: Compile Standalone - run: | - set -e - mkdir out; cd out; cmake .. -DBUILD_TESTS=1 - make - shell: bash - if: runner.os != 'Windows' - - name: Run Unit Tests - run: | - cd out/bin - for test in test* - do echo $test - if ! ./$test - then - ERR=1 - fi - done - if [ ! -z "$ERR" ] - then - exit 1 - fi - shell: bash - sdist: - name: compile-sdist-python${{ matrix.python-version }}-${{ matrix.platform.os }} - runs-on: ${{ matrix.platform.os }} - needs: ["lint"] - strategy: - matrix: - python-version: [3.6, 3.7, 3.8] - platform: [ - { os: "macOS-latest", python-architecture: "x64"}, - { os: "ubuntu-latest", python-architecture: "x64" }, - ] - steps: - - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Pip cache - uses: actions/cache@v2 - with: - path: ~/.cache/pip - key: ${{ runner.os }}-${{ matrix.python-version}}-pip-sdist-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} - restore-keys: | - ${{ runner.os }}-${{ matrix.python-version}}-pip-sdist- - ${{ runner.os }}-${{ matrix.python-version}}-pip- - ${{ runner.os }}-${{ matrix.python-version}}- - - name: Install Deps - run: python -m pip install -U setuptools wheel virtualenv - - name: Install openblas - run: | - set -e - sudo apt-get update - sudo apt-get install -y libopenblas-dev - shell: bash - if: runner.os == 'Linux' - - name: Build Sdist - run: python setup.py sdist - - name: Install from sdist and test - run: | - set -e - mkdir out; cd out; virtualenv aer-test - aer-test/bin/pip install ../dist/*tar.gz - aer-test/bin/pip install -c ../constraints.txt git+https://github.com/Qiskit/qiskit-terra - aer-test/bin/python ../tools/verify_wheels.py - aer-test/bin/pip check - shell: bash - wheel: - name: compile-wheel-${{ matrix.os }} - runs-on: ${{ matrix.os }} - needs: ["lint"] - strategy: - matrix: - os: ["macOS-latest", "ubuntu-latest"] - steps: - - uses: actions/checkout@v2 - - name: Set up Python Python 3.8 - uses: actions/setup-python@v2 - with: - python-version: 3.8 - - name: Install deps - run: python -m pip install -U cibuildwheel==1.5.5 - - name: Build Wheels - env: - CIBW_BEFORE_ALL_LINUX: "yum install -y openblas-devel" - CIBW_BEFORE_BUILD: "pip install -U virtualenv pybind11" - CIBW_SKIP: "cp27-* cp34-* cp35-* pp*" - CIBW_MANYLINUX_X86_64_IMAGE: "manylinux2010" - CIBW_MANYLINUX_I686_IMAGE: "manylinux2010" - CIBW_TEST_COMMAND: "python3 {project}/tools/verify_wheels.py" - CIBW_TEST_REQUIRES: "git+https://github.com/Qiskit/qiskit-terra.git" - run: cibuildwheel --output-dir wheelhouse - - uses: actions/upload-artifact@v2 - with: - path: ./wheelhouse/*.whl - tests: - name: tests-python${{ matrix.python-version }}-${{ matrix.os }} - runs-on: ${{ matrix.os }} - needs: [standalone, sdist, lint, docs] - timeout-minutes: 25 - strategy: - matrix: - python-version: [3.6, 3.7, 3.8] - os: ["macOS-latest", "ubuntu-latest", "windows-latest"] - env: - AER_THRUST_BACKEND: OMP - QISKIT_TEST_CAPTURE_STREAMS: 1 - steps: - - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Pip cache - uses: actions/cache@v2 - with: - path: ~/.cache/pip - key: ${{ runner.os }}-${{ matrix.python-version}}-pip-test-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} - restore-keys: | - ${{ runner.os }}-${{ matrix.python-version}}-pip-test- - ${{ runner.os }}-${{ matrix.python-version}}-pip- - ${{ runner.os }}-${{ matrix.python-version}}- - if: runner.os != 'Windows' - - name: Pip cache - uses: actions/cache@v2 - with: - path: ~\AppData\Local\pip\Cache - key: ${{ runner.os }}-${{ matrix.python-version}}-pip-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} - restore-keys: | - ${{ runner.os }}-${{ matrix.python-version}}-pip-test- - ${{ runner.os }}-${{ matrix.python-version}}-pip- - ${{ runner.os }}-${{ matrix.python-version}}- - if: runner.os == 'Windows' - - name: Add msbuild to PATH - uses: microsoft/setup-msbuild@v1.0.2 - if: runner.os == 'Windows' - - name: Install Deps - run: python -m pip install -U -r requirements-dev.txt wheel git+https://github.com/Qiskit/qiskit-terra - - name: Install openblas - run: | - set -e - sudo apt-get update - sudo apt-get install -y libopenblas-dev - shell: bash - if: runner.os == 'Linux' - - name: Install Aer - run: python -m pip install -U . - if: runner.os != 'Windows' - - name: Install Aer Windows - run: | - set -e - python setup.py bdist_wheel -- -G 'Visual Studio 16 2019' - pip install --find-links=dist qiskit-aer - shell: bash - if: runner.os == 'Windows' - - name: Run Tests - env: - QISKIT_SUPPRESS_PACKAGING_WARNINGS: Y - run: | - set -e - pip check - stestr run --slowest - shell: bash - if: runner.os != 'macOS' || matrix.python-version != '3.8' - - name: Run Tests macOS 3.8 - env: - QISKIT_SUPPRESS_PACKAGING_WARNINGS: Y - QISKIT_IN_PARALLEL: TRUE - run: | - set -e - pip check - stestr run --slowest - shell: bash - if: runner.os == 'macOS' && matrix.python-version == '3.8' - tutorials: - name: Tutorials - runs-on: ubuntu-latest - needs: [standalone, sdist, lint, docs] - steps: - - uses: actions/checkout@v2 - - name: Set up Python 3.7 - uses: actions/setup-python@v2 - with: - python-version: 3.7 - - name: Pip cache - uses: actions/cache@v2 - with: - path: ~\AppData\Local\pip\Cache - key: ${{ runner.os }}-pip-tutorials-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} - restore-keys: | - ${{ runner.os }}-pip-tutorials- - ${{ runner.os }}-pip- - ${{ runner.os }}- - - name: Setup tutorials job - run: | - set -e - git clone https://github.com/Qiskit/qiskit-tutorials --depth=1 - python -m pip install --upgrade pip wheel - pip install -U -r requirements-dev.txt -c constraints.txt - pip install -c constraints.txt git+https://github.com/Qiskit/qiskit-terra - pip install -c constraints.txt . - pip install -U "qiskit-ibmq-provider" "z3-solver" "qiskit-ignis" "qiskit-aqua" "pyscf<1.7.4" "matplotlib<3.3.0" jupyter pylatexenc sphinx nbsphinx sphinx_rtd_theme cvxpy -c constraints.txt - python setup.py build_ext --inplace - sudo apt install -y graphviz pandoc libopenblas-dev - pip check - shell: bash - - name: Run Tutorials - run: | - set -e - cd qiskit-tutorials - rm -rf tutorials/chemistry tutorials/circuits tutorials/circuits_advanced tutorials/finance tutorials/optimization tutorials/noise - sphinx-build -b html . _build/html - - uses: actions/upload-artifact@v2 - with: - name: tutorials_html - path: qiskit-tutorials/_build/html diff --git a/.github/workflows/tests_linux.yml b/.github/workflows/tests_linux.yml new file mode 100644 index 0000000000..ccb2523f74 --- /dev/null +++ b/.github/workflows/tests_linux.yml @@ -0,0 +1,126 @@ +name: Tests Linux +on: + push: + branches: [master, 'stable/*'] + pull_request: + branches: [master, 'stable/*'] +jobs: + lint: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.8] + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Pip cache + uses: actions/cache@v2 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-${{ matrix.python-version}}-pip-lint-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} + restore-keys: | + ${{ runner.os }}-${{ matrix.python-version}}-pip-lint- + ${{ runner.os }}-${{ matrix.python-version}}-pip- + ${{ runner.os }}-${{ matrix.python-version}}- + - name: Install deps + run: | + set -e + pip install -U pip wheel + pip install -U -c constraints.txt git+https://github.com/Qiskit/qiskit-terra + pip install -U -c constraints.txt -r requirements-dev.txt + shell: bash + - name: Run Lint + run: | + set -e + pycodestyle --ignore=E402,W504 --max-line-length=100 qiskit/providers/aer + pylint -j 2 -rn qiskit/providers/aer + sdist: + runs-on: ${{ matrix.platform.os }} + needs: ["lint"] + strategy: + matrix: + python-version: [3.6, 3.7, 3.8] + platform: [ + { os: "ubuntu-latest", python-architecture: "x64" }, + ] + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Pip cache + uses: actions/cache@v2 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-${{ matrix.python-version}}-pip-sdist-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} + restore-keys: | + ${{ runner.os }}-${{ matrix.python-version}}-pip-sdist- + ${{ runner.os }}-${{ matrix.python-version}}-pip- + ${{ runner.os }}-${{ matrix.python-version}}- + - name: Install Deps + run: python -m pip install -U setuptools wheel virtualenv + - name: Install openblas + run: | + set -e + sudo apt-get update + sudo apt-get install -y libopenblas-dev + shell: bash + - name: Build Sdist + run: python setup.py sdist + - name: Install from sdist and test + run: | + set -e + mkdir out; cd out; virtualenv aer-test + aer-test/bin/pip install ../dist/*tar.gz + aer-test/bin/pip install -c ../constraints.txt git+https://github.com/Qiskit/qiskit-terra + aer-test/bin/python ../tools/verify_wheels.py + aer-test/bin/pip check + shell: bash + tests: + runs-on: ${{ matrix.os }} + needs: [sdist, lint] + timeout-minutes: 25 + strategy: + matrix: + python-version: [3.6, 3.7, 3.8] + os: ["ubuntu-latest"] + env: + AER_THRUST_BACKEND: OMP + QISKIT_TEST_CAPTURE_STREAMS: 1 + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Pip cache + uses: actions/cache@v2 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-${{ matrix.python-version}}-pip-test-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} + restore-keys: | + ${{ runner.os }}-${{ matrix.python-version}}-pip-test- + ${{ runner.os }}-${{ matrix.python-version}}-pip- + ${{ runner.os }}-${{ matrix.python-version}}- + - name: Install Deps + run: python -m pip install -U -r requirements-dev.txt wheel git+https://github.com/Qiskit/qiskit-terra + - name: Install openblas + run: | + set -e + sudo apt-get update + sudo apt-get install -y libopenblas-dev + shell: bash + - name: Install Aer + run: python -m pip install -U . + - name: Run Tests + env: + QISKIT_SUPPRESS_PACKAGING_WARNINGS: Y + run: | + set -e + pip check + stestr run --slowest + shell: bash diff --git a/.github/workflows/tests_mac.yml b/.github/workflows/tests_mac.yml new file mode 100644 index 0000000000..44045d0b74 --- /dev/null +++ b/.github/workflows/tests_mac.yml @@ -0,0 +1,125 @@ +name: Tests MacOS +on: + push: + branches: [master, 'stable/*'] + pull_request: + branches: [master, 'stable/*'] +jobs: + lint: + runs-on: macOS-latest + strategy: + matrix: + python-version: [3.8] + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Pip cache + uses: actions/cache@v2 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-${{ matrix.python-version}}-pip-lint-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} + restore-keys: | + ${{ runner.os }}-${{ matrix.python-version}}-pip-lint- + ${{ runner.os }}-${{ matrix.python-version}}-pip- + ${{ runner.os }}-${{ matrix.python-version}}- + - name: Install deps + run: | + set -e + pip install -U pip wheel + pip install -U -c constraints.txt git+https://github.com/Qiskit/qiskit-terra + pip install -U -c constraints.txt -r requirements-dev.txt + shell: bash + - name: Run Lint + run: | + set -e + pycodestyle --ignore=E402,W504 --max-line-length=100 qiskit/providers/aer + pylint -j 2 -rn qiskit/providers/aer + sdist: + runs-on: ${{ matrix.platform.os }} + needs: ["lint"] + strategy: + matrix: + python-version: [3.6, 3.7, 3.8] + platform: [ + { os: "macOS-latest", python-architecture: "x64"}, + ] + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Pip cache + uses: actions/cache@v2 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-${{ matrix.python-version}}-pip-sdist-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} + restore-keys: | + ${{ runner.os }}-${{ matrix.python-version}}-pip-sdist- + ${{ runner.os }}-${{ matrix.python-version}}-pip- + ${{ runner.os }}-${{ matrix.python-version}}- + - name: Install Deps + run: python -m pip install -U setuptools wheel virtualenv + - name: Build Sdist + run: python setup.py sdist + - name: Install from sdist and test + run: | + set -e + mkdir out; cd out; virtualenv aer-test + aer-test/bin/pip install ../dist/*tar.gz + aer-test/bin/pip install -c ../constraints.txt git+https://github.com/Qiskit/qiskit-terra + aer-test/bin/python ../tools/verify_wheels.py + aer-test/bin/pip check + shell: bash + tests: + runs-on: ${{ matrix.os }} + needs: [sdist, lint] + timeout-minutes: 25 + strategy: + matrix: + python-version: [3.6, 3.7, 3.8] + os: ["macOS-latest"] + env: + AER_THRUST_BACKEND: OMP + QISKIT_TEST_CAPTURE_STREAMS: 1 + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Pip cache + uses: actions/cache@v2 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-${{ matrix.python-version}}-pip-test-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} + restore-keys: | + ${{ runner.os }}-${{ matrix.python-version}}-pip-test- + ${{ runner.os }}-${{ matrix.python-version}}-pip- + ${{ runner.os }}-${{ matrix.python-version}}- + - name: Install Deps + run: python -m pip install -U -r requirements-dev.txt wheel git+https://github.com/Qiskit/qiskit-terra + - name: Install Aer + run: python -m pip install -U . + - name: Run Tests + env: + QISKIT_SUPPRESS_PACKAGING_WARNINGS: Y + run: | + set -e + pip check + stestr run --slowest + shell: bash + if: runner.os != 'macOS' || matrix.python-version != '3.8' + - name: Run Tests macOS 3.8 + env: + QISKIT_SUPPRESS_PACKAGING_WARNINGS: Y + QISKIT_IN_PARALLEL: TRUE + run: | + set -e + pip check + stestr run --slowest + shell: bash + if: runner.os == 'macOS' && matrix.python-version == '3.8' diff --git a/.github/workflows/tests_windows.yml b/.github/workflows/tests_windows.yml new file mode 100644 index 0000000000..4e1a8e01d4 --- /dev/null +++ b/.github/workflows/tests_windows.yml @@ -0,0 +1,83 @@ +name: Tests Windows +on: + push: + branches: [master, 'stable/*'] + pull_request: + branches: [master, 'stable/*'] +jobs: + lint: + runs-on: windows-latest + strategy: + matrix: + python-version: [3.8] + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Pip cache + uses: actions/cache@v2 + with: + path: ~\AppData\Local\pip\Cache + key: ${{ runner.os }}-${{ matrix.python-version}}-pip-lint-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} + restore-keys: | + ${{ runner.os }}-${{ matrix.python-version}}-pip-lint- + ${{ runner.os }}-${{ matrix.python-version}}-pip- + ${{ runner.os }}-${{ matrix.python-version}}- + - name: Install deps + run: | + set -e + pip install -U -c constraints.txt git+https://github.com/Qiskit/qiskit-terra + pip install -U -c constraints.txt -r requirements-dev.txt + shell: bash + - name: Run Lint + run: | + set -e + pycodestyle --ignore=E402,W504 --max-line-length=100 qiskit/providers/aer + pylint -j 2 -rn qiskit/providers/aer + shell: bash + tests: + runs-on: ${{ matrix.os }} + needs: ["lint"] + timeout-minutes: 25 + strategy: + matrix: + python-version: [3.6, 3.7, 3.8] + os: ["windows-latest"] + env: + AER_THRUST_BACKEND: OMP + QISKIT_TEST_CAPTURE_STREAMS: 1 + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Pip cache + uses: actions/cache@v2 + with: + path: ~\AppData\Local\pip\Cache + key: ${{ runner.os }}-${{ matrix.python-version}}-pip-test-${{ hashFiles('setup.py','requirements-dev.txt','constraints.txt') }} + restore-keys: | + ${{ runner.os }}-${{ matrix.python-version}}-pip-test- + ${{ runner.os }}-${{ matrix.python-version}}-pip- + ${{ runner.os }}-${{ matrix.python-version}}- + - name: Add msbuild to PATH + uses: microsoft/setup-msbuild@v1.0.2 + - name: Install Deps + run: python -m pip install -U -r requirements-dev.txt wheel git+https://github.com/Qiskit/qiskit-terra + - name: Install Aer Windows + run: | + set -e + python setup.py bdist_wheel -- -G 'Visual Studio 16 2019' + pip install --find-links=dist qiskit-aer + shell: bash + - name: Run Tests + env: + QISKIT_SUPPRESS_PACKAGING_WARNINGS: Y + run: | + set -e + pip check + stestr run --slowest + shell: bash From 6d5028bb3ff23c211167b7417920bd15093acf4a Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Thu, 3 Dec 2020 09:07:45 -0500 Subject: [PATCH 058/126] Bump manylinux2010 docker image for wheel jobs (#1066) The default version of the manylinux2010 docker images used by cibuildwheel are trying to use a nonexistent yum repository now that centos 6 is eol. The latest version of the docker image has been updated. This commit manually sets the docker image to the latest version to unblock CI. This PR can be reverted when cibuildwheel releases a new version that bumps their default manylinux2010 version (see joerick/cibuildwheel#472 for more details on that). --- .github/workflows/build.yml | 6 +++--- .github/workflows/deploy.yml | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c4e18a5eca..555bbb9a6d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -73,11 +73,11 @@ jobs: run: python -m pip install -U cibuildwheel==1.7.0 - name: Build Wheels env: - CIBW_BEFORE_ALL_LINUX: "yum install -y openblas-devel" + CIBW_BEFORE_ALL_LINUX: "yum install -y https://archives.fedoraproject.org/pub/archive/epel/6/x86_64/epel-release-6-8.noarch.rpm && yum install -y openblas-devel" CIBW_BEFORE_BUILD: "pip install -U virtualenv pybind11" CIBW_SKIP: "cp27-* cp34-* cp35-* cp39-* pp*" - CIBW_MANYLINUX_X86_64_IMAGE: "manylinux2010" - CIBW_MANYLINUX_I686_IMAGE: "manylinux2010" + CIBW_MANYLINUX_X86_64_IMAGE: "quay.io/pypa/manylinux2010_x86_64:2020-12-03-912b0de" + CIBW_MANYLINUX_I686_IMAGE: "quay.io/pypa/manylinux2010_i686:2020-12-03-912b0de" CIBW_TEST_COMMAND: "python3 {project}/tools/verify_wheels.py" CIBW_TEST_REQUIRES: "git+https://github.com/Qiskit/qiskit-terra.git" run: cibuildwheel --output-dir wheelhouse diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 8784790f5c..2ad5c1f7a0 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -21,11 +21,11 @@ jobs: python -m pip install cibuildwheel==1.5.5 - name: Build wheels env: - CIBW_BEFORE_ALL_LINUX: "yum install -y openblas-devel" + CIBW_BEFORE_ALL_LINUX: "yum install -y https://archives.fedoraproject.org/pub/archive/epel/6/x86_64/epel-release-6-8.noarch.rpm && yum install -y openblas-devel" CIBW_BEFORE_BUILD: "pip install -U Cython pip virtualenv pybind11" CIBW_SKIP: "cp27-* cp34-* cp35-* pp*" - CIBW_MANYLINUX_X86_64_IMAGE: "manylinux2010" - CIBW_MANYLINUX_I686_IMAGE: "manylinux2010" + CIBW_MANYLINUX_X86_64_IMAGE: "quay.io/pypa/manylinux2010_x86_64:2020-12-03-912b0de" + CIBW_MANYLINUX_I686_IMAGE: "quay.io/pypa/manylinux2010_i686:2020-12-03-912b0de" CIBW_TEST_COMMAND: "python3 {project}/tools/verify_wheels.py" CIBW_TEST_REQUIRES: "git+https://github.com/Qiskit/qiskit-terra.git" run: | @@ -77,11 +77,11 @@ jobs: python -m pip install cibuildwheel==1.5.5 - name: Build wheels env: - CIBW_BEFORE_ALL: "yum install -y yum-utils wget && wget https://developer.download.nvidia.com/compute/cuda/10.1/Prod/local_installers/cuda-repo-rhel6-10-1-local-10.1.243-418.87.00-1.0-1.x86_64.rpm && rpm -i cuda-repo-rhel6-10-1-local-10.1.243-418.87.00-1.0-1.x86_64.rpm && yum clean all && yum -y install cuda-10-1" + CIBW_BEFORE_ALL: "yum install -y yum-utils wget && wget https://developer.download.nvidia.com/compute/cuda/10.1/Prod/local_installers/cuda-repo-rhel6-10-1-local-10.1.243-418.87.00-1.0-1.x86_64.rpm && rpm -i cuda-repo-rhel6-10-1-local-10.1.243-418.87.00-1.0-1.x86_64.rpm && yum clean all && yum -y install cuda-10-1 && yum install -y https://archives.fedoraproject.org/pub/archive/epel/6/x86_64/epel-release-6-8.noarch.rpm" CIBW_BEFORE_BUILD: "pip install -U Cython pip virtualenv pybind11 && yum install -y openblas-devel" CIBW_SKIP: "cp27-* cp34-* cp35-* *-manylinux_i686 pp*" - CIBW_MANYLINUX_X86_64_IMAGE: "manylinux2010" - CIBW_MANYLINUX_I686_IMAGE: "manylinux2010" + CIBW_MANYLINUX_X86_64_IMAGE: "quay.io/pypa/manylinux2010_x86_64:2020-12-03-912b0de" + CIBW_MANYLINUX_I686_IMAGE: "quay.io/pypa/manylinux2010_i686:2020-12-03-912b0de" CIBW_ENVIRONMENT: QISKIT_AER_PACKAGE_NAME=qiskit-aer-gpu AER_THRUST_BACKEND=CUDA CUDACXX=/usr/local/cuda/bin/nvcc CIBW_TEST_COMMAND: "python3 {project}/tools/verify_wheels.py" CIBW_TEST_REQUIRES: "git+https://github.com/Qiskit/qiskit-terra.git" From 466a6ac13d9640914155c35ca08edd7025e39ad1 Mon Sep 17 00:00:00 2001 From: Yael Ben-Haim Date: Thu, 3 Dec 2020 17:07:41 +0200 Subject: [PATCH 059/126] Remove a redundant function for getting qubits together (#1043) * removed a redundant function for getting qubits together * removed reverse_number, which was a duplicate of reverse_bits * replaced uint by uint_t * added braces Co-authored-by: Victor Villar --- .../matrix_product_state_internal.cpp | 95 +++++++------------ .../matrix_product_state_internal.hpp | 17 ---- 2 files changed, 35 insertions(+), 77 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 2ce9991d1f..90140704b2 100644 --- a/src/simulators/matrix_product_state/matrix_product_state_internal.cpp +++ b/src/simulators/matrix_product_state/matrix_product_state_internal.cpp @@ -92,7 +92,11 @@ uint_t reorder_qubits(const reg_t qubits, uint_t index); //---------------------------------------------------------------- template std::vector reverse_all_bits(const std::vector& statevector, uint_t num_qubits); + +// with 5 qubits, the number 2 in binary is 00010, +// when reversed it is 01000, which is the number 8 uint_t reverse_bits(uint_t num, uint_t len); + std::vector calc_new_indices(const reg_t &indices); // The following two functions are helper functions used by @@ -169,6 +173,8 @@ uint_t reorder_qubits(const reg_t qubits, uint_t index) { return new_index; } +// with 5 qubits, the number 2 in binary is 00010, +// when reversed it is 01000, which is the number 8 uint_t reverse_bits(uint_t num, uint_t len) { uint_t sum = 0; for (uint_t i=0; i 0) q_reg_[first].div_Gamma_by_left_Lambda(lambda_reg_[first-1]); - - for (uint_t i=1; i=0; right_index--) { - // find "largest" element and move it to the right end - uint_t next_right = qubits[right_index]; - for (uint_t i=0; i Date: Fri, 4 Dec 2020 01:44:52 +0900 Subject: [PATCH 060/126] fix apply_pauli (#1059) --- src/simulators/statevector/qubitvector.hpp | 3 +-- test/terra/reference/ref_1q_clifford.py | 9 +++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/simulators/statevector/qubitvector.hpp b/src/simulators/statevector/qubitvector.hpp index 71bea6d67e..c9b777f3d1 100755 --- a/src/simulators/statevector/qubitvector.hpp +++ b/src/simulators/statevector/qubitvector.hpp @@ -25,7 +25,6 @@ #include #include #include - #include #include @@ -1903,13 +1902,13 @@ void QubitVector::apply_pauli(const reg_t &qubits, const std::string &pa int_t idxs[2]; idxs[0] = ((i << 1) & mask_u) | (i & mask_l); idxs[1] = idxs[0] ^ x_mask; + std::swap(data_[idxs[0]], data_[idxs[1]]); for (int_t j = 0; j < 2; ++j) { if (z_mask && (AER::Utils::popcount(idxs[j] & z_mask) & 1)) { data_[idxs[j]] *= -1; } data_[idxs[j]] *= phase; } - std::swap(data_[idxs[0]], data_[idxs[1]]); }; apply_lambda(lambda, (size_t) 0, (data_size_ >> 1)); } diff --git a/test/terra/reference/ref_1q_clifford.py b/test/terra/reference/ref_1q_clifford.py index f32ffac6fd..7995799054 100644 --- a/test/terra/reference/ref_1q_clifford.py +++ b/test/terra/reference/ref_1q_clifford.py @@ -755,6 +755,13 @@ def pauli_gate_circuits_deterministic(final_measure=True): circuit.measure(qr, cr) circuits.append(circuit) + circuit = QuantumCircuit(*regs) + circuit.pauli('XYZ', qr) + if final_measure: + circuit.barrier(qr) + circuit.measure(qr, cr) + circuits.append(circuit) + return circuits def pauli_gate_counts_deterministic(shots, hex_counts=True): @@ -763,7 +770,9 @@ def pauli_gate_counts_deterministic(shots, hex_counts=True): if hex_counts: targets.append({'0x3': shots}) targets.append({'0x5': shots}) + targets.append({'0x6': shots}) else: targets.append({'110': shots}) targets.append({'101': shots}) + targets.append({'011': shots}) return targets From cd397bec0b69ce79834434512da8a8d8351d088e Mon Sep 17 00:00:00 2001 From: Yael Ben-Haim Date: Thu, 3 Dec 2020 20:41:37 +0200 Subject: [PATCH 061/126] test gates on all basis states (#1057) Co-authored-by: Christopher J. Wood Co-authored-by: Victor Villar --- .../qasm_simulator/qasm_standard_gates.py | 93 ++++++++++--------- .../statevector_gates.py | 24 ++--- .../unitary_simulator/unitary_gates.py | 24 ++--- test/terra/common.py | 29 ++++-- 4 files changed, 100 insertions(+), 70 deletions(-) diff --git a/test/terra/backends/qasm_simulator/qasm_standard_gates.py b/test/terra/backends/qasm_simulator/qasm_standard_gates.py index b4f6cc7b1d..85e48e9d56 100644 --- a/test/terra/backends/qasm_simulator/qasm_standard_gates.py +++ b/test/terra/backends/qasm_simulator/qasm_standard_gates.py @@ -100,31 +100,34 @@ def test_gate_statevector(self, gate_cls, num_params): 'matrix_product_state' ] - circuit = self.gate_circuit(gate_cls, - num_params=num_params, - rng=self.RNG) - target = Statevector.from_instruction(circuit) - - # Add snapshot and execute - circuit.snapshot_statevector('final') backend_options = self.BACKEND_OPTS.copy() method = backend_options.pop('method', 'automatic') backend = self.SIMULATOR backend.set_options(method=method) - result = execute(circuit, backend, shots=1, **backend_options).result() - - # Check results - success = getattr(result, 'success', False) - msg = '{}, method = {}'.format(gate_cls.__name__, method) - if method not in SUPPORTED_METHODS: - self.assertFalse(success) - else: - self.assertTrue(success, msg=msg) - self.assertSuccess(result) - snapshots = result.data(0).get("snapshots", {}).get("statevector", {}) - value = snapshots.get('final', [None])[0] - fidelity = state_fidelity(target, value) - self.assertGreater(fidelity, 0.99999, msg=msg) + + circuits = self.gate_circuits(gate_cls, + num_params=num_params, + rng=self.RNG) + + for circuit in circuits: + target = Statevector.from_instruction(circuit) + + # Add snapshot and execute + circuit.snapshot_statevector('final') + result = execute(circuit, backend, shots=1, **backend_options).result() + + # Check results + success = getattr(result, 'success', False) + msg = '{}, method = {}'.format(gate_cls.__name__, method) + if method not in SUPPORTED_METHODS: + self.assertFalse(success) + else: + self.assertTrue(success, msg=msg) + self.assertSuccess(result) + snapshots = result.data(0).get("snapshots", {}).get("statevector", {}) + value = snapshots.get('final', [None])[0] + fidelity = state_fidelity(target, value) + self.assertGreater(fidelity, 0.99999, msg=msg) @ddt @@ -144,29 +147,35 @@ def test_gate_density_matrix(self, gate_cls, num_params): 'automatic', 'statevector', 'statevector_gpu', 'statevector_thrust', 'density_matrix', 'density_matrix_gpu', 'density_matrix_thrust' ] - circuit = self.gate_circuit(gate_cls, - num_params=num_params, - rng=self.RNG) - target = Statevector.from_instruction(circuit) - # Add snapshot and execute - circuit.snapshot_density_matrix('final') backend_options = self.BACKEND_OPTS.copy() method = backend_options.pop('method', 'automatic') backend = self.SIMULATOR backend.set_options(method=method) - result = execute(circuit, backend, shots=1, **backend_options).result() - - # Check results - success = getattr(result, 'success', False) - msg = '{}, method = {}'.format(gate_cls.__name__, method) - if method not in SUPPORTED_METHODS: - self.assertFalse(success) - else: - self.assertTrue(success, msg=msg) - self.assertSuccess(result) - snapshots = result.data(0).get("snapshots", - {}).get("density_matrix", {}) - value = snapshots.get('final', [{'value': None}])[0]['value'] - fidelity = state_fidelity(target, value) - self.assertGreater(fidelity, 0.99999, msg=msg) + + circuits = self.gate_circuits(gate_cls, + num_params=num_params, + rng=self.RNG) + + for circuit in circuits: + target = Statevector.from_instruction(circuit) + + # Add snapshot and execute + circuit.snapshot_density_matrix('final') + + result = execute(circuit, backend, shots=1, **backend_options).result() + + # Check results + success = getattr(result, 'success', False) + msg = '{}, method = {}'.format(gate_cls.__name__, method) + if method not in SUPPORTED_METHODS: + self.assertFalse(success) + else: + self.assertTrue(success, msg=msg) + self.assertSuccess(result) + snapshots = result.data(0).get("snapshots", + {}).get("density_matrix", {}) + value = snapshots.get('final', [{'value': None}])[0]['value'] + fidelity = state_fidelity(target, value) + self.assertGreater(fidelity, 0.99999, msg=msg) + diff --git a/test/terra/backends/statevector_simulator/statevector_gates.py b/test/terra/backends/statevector_simulator/statevector_gates.py index 4d3416aef8..1e77ffeaf2 100644 --- a/test/terra/backends/statevector_simulator/statevector_gates.py +++ b/test/terra/backends/statevector_simulator/statevector_gates.py @@ -103,14 +103,16 @@ class StatevectorGateTests: @unpack def test_gate(self, gate_cls, num_params, basis_gates): """Test standard gate simulation.""" - circuit = self.gate_circuit(gate_cls, - num_params=num_params, - rng=self.RNG) - target = Statevector.from_instruction(circuit) - result = execute(circuit, self.SIMULATOR, - basis_gates=basis_gates).result() - self.assertSuccess(result) - value = Statevector(result.get_statevector(0)) - self.assertTrue(target.equiv(value), - msg='{}, basis_gates = {}'.format( - gate_cls.__name__, basis_gates)) + circuits = self.gate_circuits(gate_cls, + num_params=num_params, + rng=self.RNG) + + for circuit in circuits: + target = Statevector.from_instruction(circuit) + result = execute(circuit, self.SIMULATOR, + basis_gates=basis_gates).result() + self.assertSuccess(result) + value = Statevector(result.get_statevector(0)) + self.assertTrue(target.equiv(value), + msg='{}, basis_gates = {}'.format( + gate_cls.__name__, basis_gates)) diff --git a/test/terra/backends/unitary_simulator/unitary_gates.py b/test/terra/backends/unitary_simulator/unitary_gates.py index 2c4d8f7472..d8a97ebe9c 100644 --- a/test/terra/backends/unitary_simulator/unitary_gates.py +++ b/test/terra/backends/unitary_simulator/unitary_gates.py @@ -103,14 +103,16 @@ class UnitaryGateTests: @unpack def test_gate(self, gate_cls, num_params, basis_gates): """Test standard gate simulation.""" - circuit = self.gate_circuit(gate_cls, - num_params=num_params, - rng=self.RNG) - target = Operator(circuit) - result = execute(circuit, self.SIMULATOR, - basis_gates=basis_gates).result() - self.assertSuccess(result) - value = Operator(result.get_unitary(0)) - self.assertTrue(target.equiv(value), - msg='{}, basis_gates = {}'.format( - gate_cls.__name__, basis_gates)) + circuits = self.gate_circuits(gate_cls, + num_params=num_params, + rng=self.RNG) + + for circuit in circuits: + target = Operator(circuit) + result = execute(circuit, self.SIMULATOR, + basis_gates=basis_gates).result() + self.assertSuccess(result) + value = Operator(result.get_unitary(0)) + self.assertTrue(target.equiv(value), + msg='{}, basis_gates = {}'.format( + gate_cls.__name__, basis_gates)) diff --git a/test/terra/common.py b/test/terra/common.py index 6ac7109c64..10ec510dfe 100644 --- a/test/terra/common.py +++ b/test/terra/common.py @@ -105,8 +105,13 @@ def assertSuccess(self, result): self.assertTrue(success, msg=msg) @staticmethod - def gate_circuit(gate_cls, num_params=0, rng=None): - """Construct a circuit from a gate class.""" + def gate_circuits(gate_cls, num_params=0, rng=None, basis_states=None): + """ + Construct circuits from a gate class. + Example of basis_states: ['010, '100']. + When basis_states is None, tests all basis states + with the gate's number of qubits. + """ if num_params: if rng is None: rng = np.random.default_rng() @@ -114,10 +119,22 @@ def gate_circuit(gate_cls, num_params=0, rng=None): gate = gate_cls(*params) else: gate = gate_cls() - - circ = QuantumCircuit(gate.num_qubits) - circ.append(gate, range(gate.num_qubits)) - return circ + + if basis_states is None: + basis_states = [bin(i)[2:].zfill(gate.num_qubits) \ + for i in range(1< Date: Tue, 8 Dec 2020 17:52:55 -0500 Subject: [PATCH 062/126] Restrict cvxpy testing to python 3.7 and 3.8 (#1074) * Restrict cvxpy testing to python 3.7 and 3.8 The cvxpy packaging (more specifically scs) is causing issues in CI for us because since it is incorrectly trying to install numpy from a pre-release package which does not support python 3.6. The nature of this issue is difficult to pin because it's not using pip to install numpy. Since cvxpy is only used in a single place, noise transformations, instead of trying to workaround these scs packaging issues this commit just restricts the test requirements on cvxpy to only match pytho 3.7 or 3.8. If cvxpy is not installed the noise transformation tests will now skip instead of fail. * Update tutorials skip list The tutorials repo has added some new types of tutorials for different parts of aqua. These should be skipped since they don't really exercise the aer api. This commit updates the tutorials job definition to stop running these new tutorials. * Fix delay instruction bug in pulse simulator Delay instructions are no longer present in the pulse library of a qobj, resulting in a key error in the pulse digest when looking up properties of instructions in the internal pulse-simulator representation of the pulse library. The bug was fixed by modifying the code that loops through instructions in an experiment to simply do nothing when a delay instruction is found. * fixing array comparison in config pulse simulator test * Add back noise skips that were accidently removed Co-authored-by: DanPuzzuoli --- .github/workflows/docs.yml | 2 +- .../providers/aer/pulse/controllers/digest_pulse_qobj.py | 4 +++- requirements-dev.txt | 2 +- test/terra/backends/test_config_pulse_simulator.py | 2 +- test/terra/noise/test_noise_transformation.py | 7 +++++++ 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 0b09f548c7..893ab04efa 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -80,7 +80,7 @@ jobs: run: | set -e cd qiskit-tutorials - rm -rf tutorials/chemistry tutorials/circuits tutorials/circuits_advanced tutorials/finance tutorials/optimization tutorials/noise + rm -rf tutorials/chemistry tutorials/circuits tutorials/circuits_advanced tutorials/finance tutorials/optimization tutorials/algorithms tutorials/operators tutorials/noise sphinx-build -b html . _build/html - uses: actions/upload-artifact@v2 with: diff --git a/qiskit/providers/aer/pulse/controllers/digest_pulse_qobj.py b/qiskit/providers/aer/pulse/controllers/digest_pulse_qobj.py index e504e75d66..b0a3d8a557 100644 --- a/qiskit/providers/aer/pulse/controllers/digest_pulse_qobj.py +++ b/qiskit/providers/aer/pulse/controllers/digest_pulse_qobj.py @@ -340,7 +340,9 @@ def experiment_to_structs(experiment, ham_chans, pulse_inds, pulse_to_int, dt, q structs['channels'][chan_name][1].extend([inst['t0'] * dt, inst['phase'], cond]) - + # Delay instruction + elif inst['name'] == 'delay': + pass # nothing to be done in this case # A standard pulse else: start = inst['t0'] * dt diff --git a/requirements-dev.txt b/requirements-dev.txt index 152516ba5c..d5d99f0a58 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -3,7 +3,7 @@ cmake!=3.17.1,!=3.17.0 conan>=1.22.2 scikit-build asv -cvxpy>=1.0.0 +cvxpy>=1.0.0;python_version>'3.6' and python_version<='3.8' pylint pycodestyle Sphinx>=1.8.3 diff --git a/test/terra/backends/test_config_pulse_simulator.py b/test/terra/backends/test_config_pulse_simulator.py index c88185b4df..171ff48c5a 100644 --- a/test/terra/backends/test_config_pulse_simulator.py +++ b/test/terra/backends/test_config_pulse_simulator.py @@ -66,7 +66,7 @@ def test_from_backend(self): for idx, entry in enumerate(sim_dict[key]): for entry_key in entry: if entry_key == 'samples': - self.assertTrue(all(entry[entry_key] == backend_dict[key][idx][entry_key])) + self.assertTrue(np.array_equal(entry[entry_key], backend_dict[key][idx][entry_key])) else: self.assertTrue(entry[entry_key] == backend_dict[key][idx][entry_key]) else: diff --git a/test/terra/noise/test_noise_transformation.py b/test/terra/noise/test_noise_transformation.py index a35eb7a40f..edda242942 100644 --- a/test/terra/noise/test_noise_transformation.py +++ b/test/terra/noise/test_noise_transformation.py @@ -13,6 +13,7 @@ NoiseTransformer class tests """ +import unittest from ..common import QiskitAerTestCase import numpy @@ -26,7 +27,13 @@ from qiskit.providers.aer.noise.errors.standard_errors import pauli_error from qiskit.providers.aer.noise.errors.quantum_error import QuantumError +try: + import cvxpy + HAS_CVXPY = True +except ImportError: + HAS_CVXPY = False +@unittest.skipUnless(HAS_CVXPY, 'cvxpy is required to run these tests') class TestNoiseTransformer(QiskitAerTestCase): def setUp(self): super().setUp() From efa221bb9491b1d2e557bee19659cff810885b31 Mon Sep 17 00:00:00 2001 From: Victor Villar Date: Wed, 9 Dec 2020 10:07:47 +0100 Subject: [PATCH 063/126] Fix numpy not found issue when installing (#1056) When doing python ./setup.py install in a clean env, CMake is unable to find numpy. Here we force the installation of numpy if it is not installed before CMake is called. Co-authored-by: Christopher J. Wood --- pyproject.toml | 3 ++- setup.py | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index e2afe703fa..e5e63618d1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,2 +1,3 @@ [build-system] -requires = ["setuptools", "wheel", "urllib3<1.26", "conan>=1.22.2", "scikit-build", "cmake!=3.17.1,!=3.17.0", "ninja", "pybind11>2.4"] +requires = ["setuptools", "wheel", "urllib3<1.26", "conan>=1.22.2", "scikit-build", + "cmake!=3.17.1,!=3.17.0", "ninja", "pybind11>2.4", "numpy>1.16.3"] diff --git a/setup.py b/setup.py index 188d94fe49..8fcd1df680 100644 --- a/setup.py +++ b/setup.py @@ -35,6 +35,11 @@ except ImportError: subprocess.call([sys.executable, '-m', 'pip', 'install', 'pybind11>=2.4']) +try: + from numpy import array +except ImportError: + subprocess.call([sys.executable, '-m', 'pip', 'install', 'numpy>=1.16.3']) + from skbuild import setup From 5c3a2d61b1b7149ed0472b8287c6c358a975872b Mon Sep 17 00:00:00 2001 From: Yael Ben-Haim Date: Thu, 10 Dec 2020 09:01:11 +0200 Subject: [PATCH 064/126] Small cleaning in the MPS simulator (#1072) Co-authored-by: Christopher J. Wood --- .../matrix_product_state_internal.cpp | 38 +++++-------------- .../matrix_product_state_internal.hpp | 23 ++--------- 2 files changed, 14 insertions(+), 47 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 90140704b2..0df9326479 100644 --- a/src/simulators/matrix_product_state/matrix_product_state_internal.cpp +++ b/src/simulators/matrix_product_state/matrix_product_state_internal.cpp @@ -553,11 +553,8 @@ void MPS::apply_3_qubit_gate(const reg_t &qubits, throw std::runtime_error(ss.str()); } - bool ordered = true; reg_t new_qubits(qubits.size()); - reg_t sorted_qubits(qubits.size()); - - centralize_and_sort_qubits(qubits, sorted_qubits, new_qubits, ordered); + centralize_qubits(qubits, new_qubits); // The controlled (or target) qubit, is qubit[2]. Since in new_qubits the qubits are sorted, // the relative position of the controlled qubit will be 0, 1, or 2 depending on @@ -656,11 +653,8 @@ void MPS::apply_multi_qubit_gate(const reg_t &qubits, void MPS::apply_unordered_multi_qubit_gate(const reg_t &qubits, const cmatrix_t &mat, bool is_diagonal){ - bool ordered = true; reg_t new_qubits(qubits.size()); - reg_t sorted_qubits(qubits.size()); - - centralize_and_sort_qubits(qubits, sorted_qubits, new_qubits, ordered); + centralize_qubits(qubits, new_qubits); apply_matrix_to_target_qubits(new_qubits, mat, is_diagonal); } @@ -766,32 +760,25 @@ void MPS::apply_kraus_internal(const reg_t &qubits, } } -void MPS::centralize_qubits(const reg_t &qubits, - reg_t &new_indices, bool & ordered) { +void MPS::centralize_qubits(const reg_t &qubits, + reg_t ¢ralized_qubits) { reg_t sorted_indices; - centralize_and_sort_qubits(qubits, sorted_indices, new_indices, ordered); -} - -void MPS::centralize_and_sort_qubits(const reg_t &qubits, reg_t &sorted_indices, - reg_t ¢ralized_qubits, bool & ordered) { - find_centralized_indices(qubits, sorted_indices, centralized_qubits, ordered); + find_centralized_indices(qubits, sorted_indices, centralized_qubits); move_qubits_to_centralized_indices(sorted_indices, centralized_qubits); } void MPS::find_centralized_indices(const reg_t &qubits, reg_t &sorted_indices, - reg_t ¢ralized_qubits, - bool & ordered) const { + reg_t ¢ralized_qubits) const { sorted_indices = qubits; uint_t num_qubits = qubits.size(); - ordered = false; if (num_qubits == 1) { centralized_qubits = qubits; - ordered = true; return; } + bool ordered = true; for (uint_t index=0; index < num_qubits-1; index++) { if (qubits[index] > qubits[index+1]){ ordered = false; @@ -890,11 +877,10 @@ cmatrix_t MPS::density_matrix_internal(const reg_t &qubits) const { rvector_t MPS::diagonal_of_density_matrix(const reg_t &qubits) const { - bool ordered = true; reg_t new_qubits; MPS temp_MPS; temp_MPS.initialize(*this); - temp_MPS.centralize_qubits(qubits, new_qubits, ordered); + temp_MPS.centralize_qubits(qubits, new_qubits); MPS_Tensor psi = temp_MPS.state_vec_as_MPS(new_qubits.front(), new_qubits.back()); @@ -908,13 +894,10 @@ rvector_t MPS::diagonal_of_density_matrix(const reg_t &qubits) const } void MPS::MPS_with_new_indices(const reg_t &qubits, - reg_t &sorted_qubits, reg_t ¢ralized_qubits, MPS& temp_MPS) const { temp_MPS.initialize(*this); - bool ordered = true; - temp_MPS.centralize_and_sort_qubits(qubits, sorted_qubits, - centralized_qubits, ordered); + temp_MPS.centralize_qubits(qubits, centralized_qubits); } @@ -1141,9 +1124,8 @@ uint_t MPS::get_max_bond_dimensions() const { } MPS_Tensor MPS::state_vec_as_MPS(const reg_t &qubits) { - bool ordered = true; reg_t new_qubits; - centralize_qubits(qubits, new_qubits, ordered); + centralize_qubits(qubits, new_qubits); return state_vec_as_MPS(new_qubits.front(), new_qubits.back()); } 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 7b16f35487..609eebc83a 100644 --- a/src/simulators/matrix_product_state/matrix_product_state_internal.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state_internal.hpp @@ -168,12 +168,10 @@ class MPS{ // Description: Moves the indices of the selected qubits for more efficient computation // of the expectation value // Parameters: The qubits for which we compute expectation value. - // Returns: sorted_qubits - the qubits, after sorting - // centralized_qubits - the qubits, after sorting and centralizing + // Returns: centralized_qubits - the qubits, after sorting and centralizing // //---------------------------------------------------------------- void MPS_with_new_indices(const reg_t &qubits, - reg_t &sorted_qubits, reg_t ¢ralized_qubits, MPS& temp_MPS) const; @@ -361,27 +359,15 @@ class MPS{ const reg_t &qubits) const; void initialize_from_matrix(uint_t num_qubits, cmatrix_t mat); + //---------------------------------------------------------------- // Function name: centralize_qubits // Description: Creates a new MPS where a subset of the qubits is // moved to be in consecutive positions. Used for // computations involving a subset of the qubits. - // Parameters: Input: new_MPS - the MPS with the shifted qubits - // qubits - the subset of qubits - // Returns: new_first, new_last - new positions of the - // first and last qubits respectively - // ordered - are the qubits in ascending order - // Returns: none. //---------------------------------------------------------------- void centralize_qubits(const reg_t &qubits, - reg_t &new_qubits, bool &ordered); - - //---------------------------------------------------------------- - // Function name: centralize_and_sort_qubits - // Description: Similar to centralize_qubits, but also returns the sorted qubit vector - //---------------------------------------------------------------- - void centralize_and_sort_qubits(const reg_t &qubits, reg_t &sorted_indexes, - reg_t ¢ralized_qubits, bool &ordered); + reg_t ¢ralized_qubits); //---------------------------------------------------------------- // Function name: find_centralized_indices @@ -390,8 +376,7 @@ class MPS{ //---------------------------------------------------------------- void find_centralized_indices(const reg_t &qubits, reg_t &sorted_indices, - reg_t ¢ralized_qubits, - bool & ordered) const; + reg_t ¢ralized_qubits) const; //---------------------------------------------------------------- // Function name: move_qubits_to_centralized_indices From 1dbb97e21790c54a52d0faec9216935a730dfb53 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Thu, 10 Dec 2020 10:14:30 -0500 Subject: [PATCH 065/126] Add Python 3.9 support (#1071) * Add Python 3.9 support This commit adds official python 3.9 support to qiskit-aer. This includes CI, release notes, and package metadata. Fixes #1067 * Remove wheel job 3.9 skip * Remove unused assertNoLogs method The assertNoLogs methods was built using a private class from python's stdlib unittest library. This should never have been done as it's explicitly marked as private. Accordingly in Python 3.9 this private class has been removed and no longer exists. It turns out this method was not used anywhere in all of qiskit (the same identical code was removed from terra as part of Qiskit/qiskit-terra#5189 in https://github.com/Qiskit/qiskit-terra/pull/5189/commits/ed5155b95c6e93f10d67c2154b58385a8a83b30d). Since the implementation is not sound and nothing uses it this commit just removes the class and method. * Fix azure pipelines job matrix typo Co-authored-by: Victor Villar --- .github/workflows/build.yml | 4 +-- .github/workflows/deploy.yml | 4 +-- .github/workflows/tests_linux.yml | 4 +-- .github/workflows/tests_mac.yml | 4 +-- .github/workflows/tests_windows.yml | 2 +- azure-pipelines.yml | 4 +++ .../notes/add-python3.9-83b3b4e5c3d59571.yaml | 10 ++++++ setup.py | 1 + test/terra/common.py | 34 ------------------- tox.ini | 2 +- 10 files changed, 25 insertions(+), 44 deletions(-) create mode 100644 releasenotes/notes/add-python3.9-83b3b4e5c3d59571.yaml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 555bbb9a6d..840476f306 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -70,12 +70,12 @@ jobs: with: python-version: 3.8 - name: Install deps - run: python -m pip install -U cibuildwheel==1.7.0 + run: python -m pip install -U cibuildwheel==1.7.1 - name: Build Wheels env: CIBW_BEFORE_ALL_LINUX: "yum install -y https://archives.fedoraproject.org/pub/archive/epel/6/x86_64/epel-release-6-8.noarch.rpm && yum install -y openblas-devel" CIBW_BEFORE_BUILD: "pip install -U virtualenv pybind11" - CIBW_SKIP: "cp27-* cp34-* cp35-* cp39-* pp*" + CIBW_SKIP: "cp27-* cp34-* cp35-* pp*" CIBW_MANYLINUX_X86_64_IMAGE: "quay.io/pypa/manylinux2010_x86_64:2020-12-03-912b0de" CIBW_MANYLINUX_I686_IMAGE: "quay.io/pypa/manylinux2010_i686:2020-12-03-912b0de" CIBW_TEST_COMMAND: "python3 {project}/tools/verify_wheels.py" diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 2ad5c1f7a0..720d10b490 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -18,7 +18,7 @@ jobs: python-version: '3.7' - name: Install cibuildwheel run: | - python -m pip install cibuildwheel==1.5.5 + python -m pip install cibuildwheel==1.7.1 - name: Build wheels env: CIBW_BEFORE_ALL_LINUX: "yum install -y https://archives.fedoraproject.org/pub/archive/epel/6/x86_64/epel-release-6-8.noarch.rpm && yum install -y openblas-devel" @@ -74,7 +74,7 @@ jobs: python-version: '3.7' - name: Install cibuildwheel run: | - python -m pip install cibuildwheel==1.5.5 + python -m pip install cibuildwheel==1.7.1 - name: Build wheels env: CIBW_BEFORE_ALL: "yum install -y yum-utils wget && wget https://developer.download.nvidia.com/compute/cuda/10.1/Prod/local_installers/cuda-repo-rhel6-10-1-local-10.1.243-418.87.00-1.0-1.x86_64.rpm && rpm -i cuda-repo-rhel6-10-1-local-10.1.243-418.87.00-1.0-1.x86_64.rpm && yum clean all && yum -y install cuda-10-1 && yum install -y https://archives.fedoraproject.org/pub/archive/epel/6/x86_64/epel-release-6-8.noarch.rpm" diff --git a/.github/workflows/tests_linux.yml b/.github/workflows/tests_linux.yml index ccb2523f74..28387c7d31 100644 --- a/.github/workflows/tests_linux.yml +++ b/.github/workflows/tests_linux.yml @@ -42,7 +42,7 @@ jobs: needs: ["lint"] strategy: matrix: - python-version: [3.6, 3.7, 3.8] + python-version: [3.6, 3.7, 3.8, 3.9] platform: [ { os: "ubuntu-latest", python-architecture: "x64" }, ] @@ -86,7 +86,7 @@ jobs: timeout-minutes: 25 strategy: matrix: - python-version: [3.6, 3.7, 3.8] + python-version: [3.6, 3.7, 3.8, 3.9] os: ["ubuntu-latest"] env: AER_THRUST_BACKEND: OMP diff --git a/.github/workflows/tests_mac.yml b/.github/workflows/tests_mac.yml index 44045d0b74..5d7b2e4d70 100644 --- a/.github/workflows/tests_mac.yml +++ b/.github/workflows/tests_mac.yml @@ -42,7 +42,7 @@ jobs: needs: ["lint"] strategy: matrix: - python-version: [3.6, 3.7, 3.8] + python-version: [3.6, 3.7, 3.8, 3.9] platform: [ { os: "macOS-latest", python-architecture: "x64"}, ] @@ -80,7 +80,7 @@ jobs: timeout-minutes: 25 strategy: matrix: - python-version: [3.6, 3.7, 3.8] + python-version: [3.6, 3.7, 3.8, 3.9] os: ["macOS-latest"] env: AER_THRUST_BACKEND: OMP diff --git a/.github/workflows/tests_windows.yml b/.github/workflows/tests_windows.yml index 4e1a8e01d4..3b95d868ea 100644 --- a/.github/workflows/tests_windows.yml +++ b/.github/workflows/tests_windows.yml @@ -43,7 +43,7 @@ jobs: timeout-minutes: 25 strategy: matrix: - python-version: [3.6, 3.7, 3.8] + python-version: [3.6, 3.7, 3.8, 3.9] os: ["windows-latest"] env: AER_THRUST_BACKEND: OMP diff --git a/azure-pipelines.yml b/azure-pipelines.yml index af69c02292..c5e105034d 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -140,6 +140,8 @@ stages: python.version: '3.7' Python38: python.version: '3.8' + Python39: + python.version: '3.9' variables: PIP_CACHE_DIR: $(Pipeline.Workspace)/.pip steps: @@ -229,6 +231,8 @@ stages: python.version: '3.7' Python38: python.version: '3.8' + Python39: + python.version: '3.9' variables: PIP_CACHE_DIR: $(Pipeline.Workspace)/.pip steps: diff --git a/releasenotes/notes/add-python3.9-83b3b4e5c3d59571.yaml b/releasenotes/notes/add-python3.9-83b3b4e5c3d59571.yaml new file mode 100644 index 0000000000..dd4629c5cf --- /dev/null +++ b/releasenotes/notes/add-python3.9-83b3b4e5c3d59571.yaml @@ -0,0 +1,10 @@ +--- +features: + - | + Python 3.9 support has been added in this release. You can now run Qiskit + Aer using Python 3.9 without building from source. +deprecations: + - | + Python 3.6 support has been deprecated and will be removed in a future + release. When support is removed you will need to upgrade the Python + version you're using to Python 3.7 or above. diff --git a/setup.py b/setup.py index 8fcd1df680..06e59c12a8 100644 --- a/setup.py +++ b/setup.py @@ -108,6 +108,7 @@ "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", "Topic :: Scientific/Engineering", ], python_requires=">=3.6", diff --git a/test/terra/common.py b/test/terra/common.py index 10ec510dfe..f456d8d279 100644 --- a/test/terra/common.py +++ b/test/terra/common.py @@ -86,14 +86,6 @@ def _get_resource_path(filename, path=Path.TEST): """ return os.path.normpath(os.path.join(path.value, filename)) - def assertNoLogs(self, logger=None, level=None): - """ - Context manager to test that no message is sent to the specified - logger and level (the opposite of TestCase.assertLogs()). - """ - # pylint: disable=invalid-name - return _AssertNoLogsContext(self, logger, level) - def assertSuccess(self, result): """Assert that simulation executed without errors""" success = getattr(result, 'success', False) @@ -329,32 +321,6 @@ def assertDictAlmostEqual(self, dict1, dict2, delta=None, msg=None, raise self.failureException(msg) -class _AssertNoLogsContext(unittest.case._AssertLogsContext): - """A context manager used to implement TestCase.assertNoLogs().""" - - # pylint: disable=inconsistent-return-statements - def __exit__(self, exc_type, exc_value, tb): - """ - This is a modified version of TestCase._AssertLogsContext.__exit__(...) - """ - self.logger.handlers = self.old_handlers - self.logger.propagate = self.old_propagate - self.logger.setLevel(self.old_level) - if exc_type is not None: - # let unexpected exceptions pass through - return False - - if self.watcher.records: - msg = 'logs of level {} or higher triggered on {}:\n'.format( - logging.getLevelName(self.level), self.logger.name) - for record in self.watcher.records: - msg += 'logger %s %s:%i: %s\n' % (record.name, record.pathname, - record.lineno, - record.getMessage()) - - self._raiseFailure(msg) - - def _is_ci_fork_pull_request(): """ Check if the tests are being run in a CI environment and if it is a pull diff --git a/tox.ini b/tox.ini index 96f8d7dcb5..1145705ef6 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 2.1 -envlist = py36, py37, py38, lint +envlist = py36, py37, py38, py39, lint skipsdist = True [testenv] From cee5c4f24a1bec330d7c740840d9cbc5fe2b99bf Mon Sep 17 00:00:00 2001 From: Victor Villar Date: Mon, 14 Dec 2020 20:29:47 +0100 Subject: [PATCH 066/126] Fix CI problem when updating wheels (#1081) * Fix CI problem when updating wheels Updating wheel with pip fails in azure sdist_builds. Installing it with Conda works. * Remove wheel from pip install --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c5e105034d..2b5cb6ffd3 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -247,7 +247,7 @@ stages: source activate qiskit-aer conda update --yes -n base conda conda config --add channels conda-forge - conda install --yes --quiet --name qiskit-aer python=$(python.version) numpy cmake pip setuptools pybind11 scipy + conda install --yes --quiet --name qiskit-aer python=$(python.version) numpy cmake pip setuptools wheel pybind11 scipy displayName: Create Anaconda environments - bash: | set -x @@ -259,7 +259,7 @@ stages: set -x set -e source activate qiskit-aer - pip install -U setuptools wheel + pip install -U setuptools pip install dist/*tar.gz pip install git+https://github.com/Qiskit/qiskit-terra python tools/verify_wheels.py From 509f3094dc970470fa90b4125b7fd99f77e46485 Mon Sep 17 00:00:00 2001 From: Victor Villar Date: Tue, 15 Dec 2020 15:57:08 +0100 Subject: [PATCH 067/126] Increase delta in a non deterministic test to avoid CI failing. (#1083) --- test/terra/backends/test_qasm_simulator_extended_stabilizer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/terra/backends/test_qasm_simulator_extended_stabilizer.py b/test/terra/backends/test_qasm_simulator_extended_stabilizer.py index 57b6b9372b..e8c18a5b81 100644 --- a/test/terra/backends/test_qasm_simulator_extended_stabilizer.py +++ b/test/terra/backends/test_qasm_simulator_extended_stabilizer.py @@ -563,7 +563,7 @@ def test_sparse_output_probabilities(self): job = QasmSimulator().run(qobj, **self.BACKEND_OPTS_NE) result = job.result() self.assertSuccess(result) - self.compare_counts(result, [circ], [target], delta=0.05 * shots) + self.compare_counts(result, [circ], [target], delta=0.1 * shots) if __name__ == '__main__': From 4a82bab1d5329730bf5ebecfcaf1d24441d95ae9 Mon Sep 17 00:00:00 2001 From: merav-aharoni <46567124+merav-aharoni@users.noreply.github.com> Date: Wed, 16 Dec 2020 08:59:22 +0200 Subject: [PATCH 068/126] Snapshot amplitudes in MPS (#1034) Co-authored-by: Victor Villar --- .../aer/extensions/snapshot_amplitudes.py | 67 +++++++++++ .../snapshot_amplitudes-c2be90ac2830517e.yaml | 11 ++ src/framework/operations.hpp | 23 ++++ .../matrix_product_state.hpp | 28 ++++- .../matrix_product_state_internal.cpp | 44 +++++++ .../matrix_product_state_internal.hpp | 3 + .../backends/qasm_simulator/qasm_snapshot.py | 80 +++++++++++++ ...est_qasm_simulator_matrix_product_state.py | 2 + .../extensions/test_snapshot_amplitudes.py | 74 ++++++++++++ .../reference/ref_snapshot_amplitudes.py | 112 ++++++++++++++++++ 10 files changed, 441 insertions(+), 3 deletions(-) create mode 100644 qiskit/providers/aer/extensions/snapshot_amplitudes.py create mode 100644 releasenotes/notes/snapshot_amplitudes-c2be90ac2830517e.yaml create mode 100644 test/terra/extensions/test_snapshot_amplitudes.py create mode 100644 test/terra/reference/ref_snapshot_amplitudes.py diff --git a/qiskit/providers/aer/extensions/snapshot_amplitudes.py b/qiskit/providers/aer/extensions/snapshot_amplitudes.py new file mode 100644 index 0000000000..eaa7b48414 --- /dev/null +++ b/qiskit/providers/aer/extensions/snapshot_amplitudes.py @@ -0,0 +1,67 @@ +# 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. + +""" +Simulator command to snapshot internal simulator representation. +""" + +from qiskit import QuantumCircuit +from .snapshot import Snapshot + + +class SnapshotAmplitudes(Snapshot): + """ Snapshot instruction for amplitudes snapshot type """ + + def __init__(self, label: str, params: list, num_qubits=0): + """Create an amplitudes snapshot instruction. + + Args: + label (str): the snapshot label. + params (List[int]): the basis values whose amplitudes to return + num_qubits (int): the instruction barrier size [Default: 0]. + + Raises: + ExtensionError: if snapshot is invalid. + + Additional Information: + This snapshot is always performed on all qubits in a circuit. + The number of qubits parameter specifies the size of the + instruction as a barrier and should be set to the number of + qubits in the circuit. + """ + super().__init__(label, snapshot_type='amplitudes', params=params, num_qubits=num_qubits) + + +def snapshot_amplitudes(self, label, params): + """Take a snapshot of a subset of the amplitudes of the simulator state. + + Args: + label (str): a snapshot label to report the result. + params (List[int]): the basis values whose amplitudes to return + + Returns: + QuantumCircuit: with attached instruction. + + Raises: + ExtensionError: if snapshot is invalid. + + Additional Information: + This snapshot is always performed on all qubits in a circuit. + """ + snapshot_register = Snapshot.define_snapshot_register(self) + + return self.append( + SnapshotAmplitudes(label, params, num_qubits=len(snapshot_register)), + snapshot_register) + + +QuantumCircuit.snapshot_amplitudes = snapshot_amplitudes diff --git a/releasenotes/notes/snapshot_amplitudes-c2be90ac2830517e.yaml b/releasenotes/notes/snapshot_amplitudes-c2be90ac2830517e.yaml new file mode 100644 index 0000000000..4ca3c3042b --- /dev/null +++ b/releasenotes/notes/snapshot_amplitudes-c2be90ac2830517e.yaml @@ -0,0 +1,11 @@ +--- + +features: + - | + Added a new snapshot: `snapshot_amplitudes`. See PR #1034. + The user can request a subset of + the amplitudes appearing in the full statevector. The user provides as input + the base values, as an array of hexa or integers. This instruction outputs + the corresponding array of amplitudes, in the same order as the given base values. + This snapshot is supported in simulation methods: `statevector` and `matrix_product_state`. + diff --git a/src/framework/operations.hpp b/src/framework/operations.hpp index 195e1d53ca..f0a5786fff 100755 --- a/src/framework/operations.hpp +++ b/src/framework/operations.hpp @@ -136,6 +136,7 @@ struct Op { // 1 x M row-matrices // Projector vectors are stored as // M x 1 column-matrices + std::vector params_amplitudes; // Vector of base values }; inline std::ostream& operator<<(std::ostream& s, const Op& op) { @@ -401,6 +402,7 @@ Op json_to_op_snapshot(const json_t &js); Op json_to_op_snapshot_default(const json_t &js); Op json_to_op_snapshot_matrix(const json_t &js); Op json_to_op_snapshot_pauli(const json_t &js); +Op json_to_op_snapshot_amplitudes(const json_t &js); // Matrices Op json_to_op_unitary(const json_t &js); @@ -839,6 +841,8 @@ Op json_to_op_snapshot(const json_t &js) { return json_to_op_snapshot_pauli(js); if (snapshot_type.find("expectation_value_matrix") != std::string::npos) return json_to_op_snapshot_matrix(js); + if (snapshot_type.find("amplitudes") != std::string::npos) + return json_to_op_snapshot_amplitudes(js); // Default snapshot: has "type", "label", "qubits" auto op = json_to_op_snapshot_default(js); // Conditional @@ -862,6 +866,25 @@ Op json_to_op_snapshot_default(const json_t &js) { return op; } +Op json_to_op_snapshot_amplitudes(const json_t &js) { + // Load default snapshot parameters + Op op = json_to_op_snapshot_default(js); + + // Check qubits are valid + check_empty_qubits(op); + check_duplicate_qubits(op); + + // Get components + if (JSON::check_key("params", js) && js["params"].is_array()) { + for (complex_t base_value : js["params"]) { + op.params_amplitudes.emplace_back(static_cast(real(base_value))); + } + } else { + throw std::invalid_argument("Invalid amplitudes snapshot (param component invalid"); + } + return op; +} + Op json_to_op_snapshot_pauli(const json_t &js) { // Load default snapshot parameters diff --git a/src/simulators/matrix_product_state/matrix_product_state.hpp b/src/simulators/matrix_product_state/matrix_product_state.hpp index ec3833d7d9..feaff8d1df 100644 --- a/src/simulators/matrix_product_state/matrix_product_state.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state.hpp @@ -55,7 +55,7 @@ const Operations::OpSet StateOpSet( "u2", "u3", "u", "U", "CX", "cx", "cz", "cp", "cu1", "swap", "ccx", "sx", "r", "rx", "ry", "rz", "rxx", "ryy", "rzz", "rzx"}, // Snapshots - {"statevector", "memory", "register", "probabilities", + {"statevector", "amplitudes", "memory", "register", "probabilities", "expectation_value_pauli", "expectation_value_pauli_with_variance", "expectation_value_pauli_single_shot", "expectation_value_matrix", "expectation_value_matrix_with_variance", @@ -65,7 +65,7 @@ const Operations::OpSet StateOpSet( // Allowed snapshots enum class enum class Snapshots { - statevector, cmemory, cregister, + statevector, amplitudes, cmemory, cregister, probs, probs_var, densmat, densmat_var, expval_pauli, expval_pauli_var, expval_pauli_shot, expval_matrix, expval_matrix_var, expval_matrix_shot @@ -263,6 +263,10 @@ class State : public Base::State { ExperimentResult &result, std::string name = ""); + void snapshot_amplitudes(const Operations::Op &op, + ExperimentResult &result, + std::string name = ""); + //----------------------------------------------------------------------- // Single-qubit gate helpers //----------------------------------------------------------------------- @@ -331,6 +335,7 @@ const stringmap_t State::gateset_({ const stringmap_t State::snapshotset_({ {"statevector", Snapshots::statevector}, + {"amplitudes", Snapshots::amplitudes}, {"probabilities", Snapshots::probs}, {"expectation_value_pauli", Snapshots::expval_pauli}, {"expectation_value_matrix", Snapshots::expval_matrix}, @@ -555,7 +560,6 @@ void State::snapshot_matrix_expval(const Operations::Op &op, } complex_t expval(0., 0.); double one_expval = 0; - for (const auto ¶m : op.params_expval_matrix) { complex_t coeff = param.first; @@ -594,6 +598,20 @@ void State::snapshot_state(const Operations::Op &op, result.data.add_pershot_snapshot("statevector", op.string_params[0], statevector); } +void State::snapshot_amplitudes(const Operations::Op &op, + ExperimentResult &result, + std::string name) { + if (op.params_amplitudes.empty()) { + throw std::invalid_argument("Invalid amplitudes snapshot (No base value given)."); + } + reg_t base_values; + for (const auto ¶m : op.params_amplitudes) { + base_values.push_back(param); + } + auto amplitude_vector = qreg_.get_amplitude_vector(base_values); + result.data.add_pershot_snapshot("amplitudes", op.string_params[0], amplitude_vector); +} + void State::snapshot_probabilities(const Operations::Op &op, ExperimentResult &result, SnapshotDataType type) { @@ -904,6 +922,10 @@ void State::apply_snapshot(const Operations::Op &op, ExperimentResult &result) { snapshot_state(op, result, "statevector"); break; } + case Snapshots::amplitudes: { + snapshot_amplitudes(op, result, "amplitudes"); + break; + } case Snapshots::cmemory: BaseState::snapshot_creg_memory(op, result); break; 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 0df9326479..15880103cc 100644 --- a/src/simulators/matrix_product_state/matrix_product_state_internal.cpp +++ b/src/simulators/matrix_product_state/matrix_product_state_internal.cpp @@ -1178,6 +1178,50 @@ void MPS::full_state_vector_internal(cvector_t& statevector, statevector = reverse_all_bits(temp_statevector, num_qubits); } +cvector_t MPS::get_amplitude_vector(const reg_t &base_values) { + uint_t num_values = base_values.size(); + std::string base_value; + cvector_t amplitude_vector(num_values); + + #pragma omp parallel for if (num_values > omp_threshold_ && omp_threads_ > 1) num_threads(omp_threads_) + for (int_t i=0; i(num_values); i++) { + // Since the qubits may not be ordered, we determine the actual index + // by the internal order of the qubits, to obtain the actual_base_value + uint_t actual_base_value = reorder_qubits(qubit_ordering_.order_, base_values[i]); + base_value = AER::Utils::int2string(actual_base_value); + amplitude_vector[i] = get_single_amplitude(base_value); + } + return amplitude_vector; +} + +complex_t MPS::get_single_amplitude(const std::string &base_value) { + // We take the bits of the base value from right to left in order not to expand the + // base values to the full width of 2^n + // We contract from left to right because the representation in Qiskit is from left + // to right, i.e., 1=1000, 2=0100, ... + + int_t pos = base_value.length()-1; + uint_t bit = base_value[pos]=='0' ? 0 : 1; + pos--; + cmatrix_t temp = q_reg_[0].get_data(bit); + + for (int_t qubit=0; qubit=0) + bit = base_value[pos]=='0' ? 0 : 1; + else + bit = 0; + for (uint_t row=0; row + circuit = QuantumCircuit(*regs) + if not post_measure: + for label, params in snapshot_amplitudes_labels_params().items(): + circuit.snapshot_amplitudes(label, params) + circuit.snapshot_statevector(label) + circuit.barrier(qr) + circuit.measure(qr, cr) + if post_measure: + for label, params in snapshot_amplitudes_labels_params().items(): + circuit.snapshot_amplitudes(label, params) + circuit.snapshot_statevector(label) + + circuits.append(circuit) + + # Snapshot |111> + circuit = QuantumCircuit(*regs) + circuit.x(qr) + if not post_measure: + for label, params in snapshot_amplitudes_labels_params().items(): + circuit.snapshot_amplitudes(label, params) + circuit.snapshot_statevector(label) + circuit.barrier(qr) + circuit.measure(qr, cr) + if post_measure: + for label, params in snapshot_amplitudes_labels_params().items(): + circuit.snapshot_amplitudes(label, params) + circuit.snapshot_statevector(label) + + circuits.append(circuit) + + # Snapshot 0.25*(|001>+|011>+|100>+|101>) + circuit = QuantumCircuit(*regs) + circuit.h(0) + circuit.h(2) + if not post_measure: + for label, params in snapshot_amplitudes_labels_params().items(): + circuit.snapshot_amplitudes(label, params) + circuit.snapshot_statevector(label) + circuit.barrier(qr) + circuit.measure(qr, cr) + if post_measure: + for label, params in snapshot_amplitudes_labels_params().items(): + circuit.snapshot_amplitudes(label, params) + circuit.snapshot_statevector(label) + + circuits.append(circuit) + + return circuits + + +def snapshot_amplitudes_counts(shots): + """Snapshot Amplitudes test circuits reference counts.""" + targets = [] + # Snapshot |000> + targets.append({'0x0': shots}) + # Snapshot |111> + targets.append({'0x7': shots}) + # Snapshot 0.25*(|001>+|011>+|100>+|101>) + targets.append({'0x0': shots/4, '0x1': shots/4, '0x4': shots/4, '0x5': shots/4,}) + return targets + + From bd11f1ecc9da234f4cc62a61d9458cd4add0927c Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Tue, 12 Jan 2021 03:36:44 -0500 Subject: [PATCH 069/126] Fix GPU wheel job (#1082) For the 0.7.2 release the GPU wheel build failed because of recent issues around the epel yum repository with centos 6. These issues were caused by a configuration ordering problem with an older manylinux2010 docker image. Basically we were trying to manually configure EPEL too late and cuda installation failed, but newer docker images fix the epel configuration so we no longer need to do it manually. This commit fixes the gpu wheel jobs by using the latest docker image version and removing the manual centos 6 epel configuration. Co-authored-by: Victor Villar --- .github/workflows/deploy.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 720d10b490..af0a05a75c 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -77,11 +77,11 @@ jobs: python -m pip install cibuildwheel==1.7.1 - name: Build wheels env: - CIBW_BEFORE_ALL: "yum install -y yum-utils wget && wget https://developer.download.nvidia.com/compute/cuda/10.1/Prod/local_installers/cuda-repo-rhel6-10-1-local-10.1.243-418.87.00-1.0-1.x86_64.rpm && rpm -i cuda-repo-rhel6-10-1-local-10.1.243-418.87.00-1.0-1.x86_64.rpm && yum clean all && yum -y install cuda-10-1 && yum install -y https://archives.fedoraproject.org/pub/archive/epel/6/x86_64/epel-release-6-8.noarch.rpm" + CIBW_BEFORE_ALL: "yum install -y yum-utils wget && wget https://developer.download.nvidia.com/compute/cuda/10.1/Prod/local_installers/cuda-repo-rhel6-10-1-local-10.1.243-418.87.00-1.0-1.x86_64.rpm && rpm -i cuda-repo-rhel6-10-1-local-10.1.243-418.87.00-1.0-1.x86_64.rpm && yum clean all && yum -y install cuda-10-1" CIBW_BEFORE_BUILD: "pip install -U Cython pip virtualenv pybind11 && yum install -y openblas-devel" CIBW_SKIP: "cp27-* cp34-* cp35-* *-manylinux_i686 pp*" - CIBW_MANYLINUX_X86_64_IMAGE: "quay.io/pypa/manylinux2010_x86_64:2020-12-03-912b0de" - CIBW_MANYLINUX_I686_IMAGE: "quay.io/pypa/manylinux2010_i686:2020-12-03-912b0de" + CIBW_MANYLINUX_X86_64_IMAGE: "quay.io/pypa/manylinux2010_x86_64:latest" + CIBW_MANYLINUX_I686_IMAGE: "quay.io/pypa/manylinux2010_i686:latest" CIBW_ENVIRONMENT: QISKIT_AER_PACKAGE_NAME=qiskit-aer-gpu AER_THRUST_BACKEND=CUDA CUDACXX=/usr/local/cuda/bin/nvcc CIBW_TEST_COMMAND: "python3 {project}/tools/verify_wheels.py" CIBW_TEST_REQUIRES: "git+https://github.com/Qiskit/qiskit-terra.git" From 5335ce9e4ed93a14bd969892b89caa8934f6dba5 Mon Sep 17 00:00:00 2001 From: Victor Villar Date: Tue, 12 Jan 2021 12:50:31 +0100 Subject: [PATCH 070/126] Remove unused imports making tests fail (#1098) --- test/terra/pulse/test_system_models.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/terra/pulse/test_system_models.py b/test/terra/pulse/test_system_models.py index 91debecb26..52670a09bb 100644 --- a/test/terra/pulse/test_system_models.py +++ b/test/terra/pulse/test_system_models.py @@ -18,11 +18,7 @@ import numpy as np from numpy.linalg import norm from test.terra.common import QiskitAerTestCase -import qiskit from qiskit.test.mock import FakeOpenPulse2Q -import qiskit.pulse as pulse -from qiskit.pulse import pulse_lib -from qiskit.compiler import assemble from qiskit.providers.aer.pulse.system_models.pulse_system_model import PulseSystemModel from qiskit.providers.aer.pulse.system_models.hamiltonian_model import HamiltonianModel from qiskit.test.mock import FakeArmonk From b96cd88a301d22c9fe6edd236cc439598590a89a Mon Sep 17 00:00:00 2001 From: Victor Villar Date: Tue, 12 Jan 2021 17:08:38 +0100 Subject: [PATCH 071/126] Honor DISABLE_CONAN environment variable (#1080) --- CMakeLists.txt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ad0ba19b06..9bb53968a5 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,12 +47,9 @@ option(BUILD_TESTS "Specify whether we want to build tests or not" FALSE) # Allow disabling conan for downstream package managers. Requires all libraries to be present in path # Default is value of environment variable if defined or ON -if(DEFINED ENV{DISABLE_CONAN}) - set(_DISABLE_CONAN_DEFAULT ENV{DISABLE_CONAN}) -else() - set(_DISABLE_CONAN_DEFAULT OFF) +if(NOT DEFINED DISABLE_CONAN AND DEFINED ENV{DISABLE_CONAN}) + set(DISABLE_CONAN $ENV{DISABLE_CONAN}) endif() -option(DISABLE_CONAN "Disable Conan package manager to find dependencies. If disabled, you must have all dependencies present on your system." ${_DISABLE_CONAN_DEFAULT}) include(CTest) include(compiler_utils) From 72961a92bcbfd1ce603a19eed5fe44571eede644 Mon Sep 17 00:00:00 2001 From: Victor Villar Date: Wed, 13 Jan 2021 08:19:28 +0100 Subject: [PATCH 072/126] Compile CUDA on win (#1065) Co-authored-by: Christopher J. Wood --- CMakeLists.txt | 5 ++++- pyproject.toml | 2 +- .../notes/allow_cuda_on_win-c3e5c920528eb282.yaml | 8 ++++++++ setup.py | 4 ++-- 4 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 releasenotes/notes/allow_cuda_on_win-c3e5c920528eb282.yaml diff --git a/CMakeLists.txt b/CMakeLists.txt index 9bb53968a5..df010505d5 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -149,6 +149,9 @@ setup_dependencies() # If we do not set them with a space CMake fails afterwards if nothing is set for this vars! set(AER_LINKER_FLAGS " ") set(AER_COMPILER_FLAGS " ") +if(MSVC) + set(AER_COMPILER_FLAGS " /bigobj") +endif () if(NOT OPENMP_FOUND) # Could already be setup for macos with conan message(STATUS "Looking for OpenMP support...") @@ -256,7 +259,7 @@ if(AER_THRUST_SUPPORTED) cuda_select_nvcc_arch_flags(AER_CUDA_ARCH_FLAGS ${AER_CUDA_ARCH}) string(REPLACE ";" " " AER_CUDA_ARCH_FLAGS_EXPAND "${AER_CUDA_ARCH_FLAGS}") - set(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS} -ccbin \"${CMAKE_CXX_COMPILER}\" ${AER_CUDA_ARCH_FLAGS_EXPAND} -DAER_THRUST_CUDA -I${AER_SIMULATOR_CPP_SRC_DIR} -isystem ${AER_SIMULATOR_CPP_SRC_DIR}/third-party/headers -use_fast_math --expt-extended-lambda") + set(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS} ${AER_CUDA_ARCH_FLAGS_EXPAND} -DAER_THRUST_CUDA -I${AER_SIMULATOR_CPP_SRC_DIR} -isystem ${AER_SIMULATOR_CPP_SRC_DIR}/third-party/headers -use_fast_math --expt-extended-lambda") set(AER_COMPILER_DEFINITIONS ${AER_COMPILER_DEFINITIONS} THRUST_DEVICE_SYSTEM=THRUST_DEVICE_SYSTEM_CUDA) set(THRUST_DEPENDENT_LIBS "") diff --git a/pyproject.toml b/pyproject.toml index e5e63618d1..20397d69e0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,3 @@ [build-system] requires = ["setuptools", "wheel", "urllib3<1.26", "conan>=1.22.2", "scikit-build", - "cmake!=3.17.1,!=3.17.0", "ninja", "pybind11>2.4", "numpy>1.16.3"] + "cmake!=3.17.1,!=3.17.0", "ninja", "pybind11>2.6", "numpy>1.16.3"] diff --git a/releasenotes/notes/allow_cuda_on_win-c3e5c920528eb282.yaml b/releasenotes/notes/allow_cuda_on_win-c3e5c920528eb282.yaml new file mode 100644 index 0000000000..ce10e274b3 --- /dev/null +++ b/releasenotes/notes/allow_cuda_on_win-c3e5c920528eb282.yaml @@ -0,0 +1,8 @@ +--- +features: + - | + It is now possible to build AER with CUDA enabled in Windows. +upgrade: + - | + ``pybind11`` minimum version required is 2.6 instead of 2.4. This is needed + in order to support CUDA enabled compilation in Windows. diff --git a/setup.py b/setup.py index 06e59c12a8..8c017f842e 100644 --- a/setup.py +++ b/setup.py @@ -33,7 +33,7 @@ try: import pybind11 except ImportError: - subprocess.call([sys.executable, '-m', 'pip', 'install', 'pybind11>=2.4']) + subprocess.call([sys.executable, '-m', 'pip', 'install', 'pybind11>=2.6']) try: from numpy import array @@ -49,7 +49,7 @@ common_requirements = [ 'numpy>=1.16.3', 'scipy>=1.0', - 'pybind11>=2.4' # This isn't really an install requirement, + 'pybind11>=2.6' # This isn't really an install requirement, # Pybind11 is required to be pre-installed for # CMake to successfully find header files. # This should be fixed in the CMake build files. From 36c385f689f2face82c1eb819dccfb87c2189b2d Mon Sep 17 00:00:00 2001 From: Victor Villar Date: Thu, 14 Jan 2021 11:46:22 +0100 Subject: [PATCH 073/126] Update minimum Conan version to 1.31.2. (#1097) This new version correctly handles urllib3 compatibility, so there is no need to pre-install urllib3 anymore. It also adds native AppleClang12 compatibility, so there's no need to provide our own conan settings file. Co-authored-by: Matthew Treinish --- .github/workflows/build.yml | 2 +- cmake/conan_utils.cmake | 3 - conan_settings/settings.yml | 98 ------------------- pyproject.toml | 2 +- .../notes/update-conan-0e891458bcc96ee2.yaml | 7 ++ requirements-dev.txt | 4 +- setup.py | 6 +- 7 files changed, 11 insertions(+), 111 deletions(-) delete mode 100644 conan_settings/settings.yml create mode 100644 releasenotes/notes/update-conan-0e891458bcc96ee2.yaml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 840476f306..58a800be3a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,7 +17,7 @@ jobs: with: python-version: 3.7 - name: Install deps - run: pip install "urllib3<1.26" conan + run: pip install "conan>=1.31.2" - name: Install openblas run: | set -e diff --git a/cmake/conan_utils.cmake b/cmake/conan_utils.cmake index 2fbc30f53b..1d89aed4e0 100644 --- a/cmake/conan_utils.cmake +++ b/cmake/conan_utils.cmake @@ -43,9 +43,6 @@ macro(setup_conan) list(APPEND AER_CONAN_LIBS catch2) endif() - # Add Appleclang-12 until officially supported by Conan - conan_config_install(ITEM ${PROJECT_SOURCE_DIR}/conan_settings) - conan_cmake_run(REQUIRES ${REQUIREMENTS} OPTIONS ${CONAN_OPTIONS} ENV CONAN_CMAKE_PROGRAM=${CMAKE_COMMAND} diff --git a/conan_settings/settings.yml b/conan_settings/settings.yml deleted file mode 100644 index 67fdaa7213..0000000000 --- a/conan_settings/settings.yml +++ /dev/null @@ -1,98 +0,0 @@ - -# Only for cross building, 'os_build/arch_build' is the system that runs Conan -os_build: [Windows, WindowsStore, Linux, Macos, FreeBSD, SunOS, AIX] -arch_build: [x86, x86_64, ppc32be, ppc32, ppc64le, ppc64, armv5el, armv5hf, armv6, armv7, armv7hf, armv7s, armv7k, armv8, armv8_32, armv8.3, sparc, sparcv9, mips, mips64, avr, s390, s390x, sh4le] - -# Only for building cross compilation tools, 'os_target/arch_target' is the system for -# which the tools generate code -os_target: [Windows, Linux, Macos, Android, iOS, watchOS, tvOS, FreeBSD, SunOS, AIX, Arduino, Neutrino] -arch_target: [x86, x86_64, ppc32be, ppc32, ppc64le, ppc64, armv5el, armv5hf, armv6, armv7, armv7hf, armv7s, armv7k, armv8, armv8_32, armv8.3, sparc, sparcv9, mips, mips64, avr, s390, s390x, asm.js, wasm, sh4le] - -# Rest of the settings are "host" settings: -# - For native building/cross building: Where the library/program will run. -# - For building cross compilation tools: Where the cross compiler will run. -os: - Windows: - subsystem: [None, cygwin, msys, msys2, wsl] - WindowsStore: - version: ["8.1", "10.0"] - WindowsCE: - platform: ANY - version: ["5.0", "6.0", "7.0", "8.0"] - Linux: - Macos: - version: [None, "10.6", "10.7", "10.8", "10.9", "10.10", "10.11", "10.12", "10.13", "10.14", "10.15"] - Android: - api_level: ANY - iOS: - version: ["7.0", "7.1", "8.0", "8.1", "8.2", "8.3", "9.0", "9.1", "9.2", "9.3", "10.0", "10.1", "10.2", "10.3", "11.0", "11.1", "11.2", "11.3", "11.4", "12.0", "12.1", "12.2", "12.3", "12.4", "13.0", "13.1", "13.2", "13.3", "13.4", "13.5", "13.6"] - watchOS: - version: ["4.0", "4.1", "4.2", "4.3", "5.0", "5.1", "5.2", "5.3", "6.0", "6.1"] - tvOS: - version: ["11.0", "11.1", "11.2", "11.3", "11.4", "12.0", "12.1", "12.2", "12.3", "12.4", "13.0"] - FreeBSD: - SunOS: - AIX: - Arduino: - board: ANY - Emscripten: - Neutrino: - version: ["6.4", "6.5", "6.6", "7.0", "7.1"] -arch: [x86, x86_64, ppc32be, ppc32, ppc64le, ppc64, armv4, armv4i, armv5el, armv5hf, armv6, armv7, armv7hf, armv7s, armv7k, armv8, armv8_32, armv8.3, sparc, sparcv9, mips, mips64, avr, s390, s390x, asm.js, wasm, sh4le] -compiler: - sun-cc: - version: ["5.10", "5.11", "5.12", "5.13", "5.14", "5.15"] - threads: [None, posix] - libcxx: [libCstd, libstdcxx, libstlport, libstdc++] - gcc: &gcc - version: ["4.1", "4.4", "4.5", "4.6", "4.7", "4.8", "4.9", - "5", "5.1", "5.2", "5.3", "5.4", "5.5", - "6", "6.1", "6.2", "6.3", "6.4", "6.5", - "7", "7.1", "7.2", "7.3", "7.4", "7.5", - "8", "8.1", "8.2", "8.3", "8.4", - "9", "9.1", "9.2", "9.3", - "10", "10.1"] - libcxx: [libstdc++, libstdc++11] - threads: [None, posix, win32] # Windows MinGW - exception: [None, dwarf2, sjlj, seh] # Windows MinGW - cppstd: [None, 98, gnu98, 11, gnu11, 14, gnu14, 17, gnu17, 20, gnu20] - Visual Studio: &visual_studio - runtime: [MD, MT, MTd, MDd] - version: ["8", "9", "10", "11", "12", "14", "15", "16"] - toolset: [None, v90, v100, v110, v110_xp, v120, v120_xp, - v140, v140_xp, v140_clang_c2, LLVM-vs2012, LLVM-vs2012_xp, - LLVM-vs2013, LLVM-vs2013_xp, LLVM-vs2014, LLVM-vs2014_xp, - LLVM-vs2017, LLVM-vs2017_xp, v141, v141_xp, v141_clang_c2, v142, - llvm, ClangCL] - cppstd: [None, 14, 17, 20] - clang: - version: ["3.3", "3.4", "3.5", "3.6", "3.7", "3.8", "3.9", "4.0", - "5.0", "6.0", "7.0", "7.1", - "8", "9", "10"] - libcxx: [None, libstdc++, libstdc++11, libc++, c++_shared, c++_static] - cppstd: [None, 98, gnu98, 11, gnu11, 14, gnu14, 17, gnu17, 20, gnu20] - runtime: [None, MD, MT, MTd, MDd] - apple-clang: &apple_clang - version: ["5.0", "5.1", "6.0", "6.1", "7.0", "7.3", "8.0", "8.1", "9.0", "9.1", "10.0", "11.0", "12.0"] - libcxx: [libstdc++, libc++] - cppstd: [None, 98, gnu98, 11, gnu11, 14, gnu14, 17, gnu17, 20, gnu20] - intel: - version: ["11", "12", "13", "14", "15", "16", "17", "18", "19", "19.1"] - base: - gcc: - <<: *gcc - threads: [None] - exception: [None] - Visual Studio: - <<: *visual_studio - apple-clang: - <<: *apple_clang - qcc: - version: ["4.4", "5.4", "8.3"] - libcxx: [cxx, gpp, cpp, cpp-ne, accp, acpp-ne, ecpp, ecpp-ne] - cppstd: [None, 98, gnu98, 11, gnu11, 14, gnu14, 17, gnu17] - -build_type: [None, Debug, Release, RelWithDebInfo, MinSizeRel] - - -cppstd: [None, 98, gnu98, 11, gnu11, 14, gnu14, 17, gnu17, 20, gnu20] # Deprecated, use compiler.cppstd diff --git a/pyproject.toml b/pyproject.toml index 20397d69e0..f9eec3ab09 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,3 @@ [build-system] -requires = ["setuptools", "wheel", "urllib3<1.26", "conan>=1.22.2", "scikit-build", +requires = ["setuptools", "wheel", "conan>=1.31.2", "scikit-build", "cmake!=3.17.1,!=3.17.0", "ninja", "pybind11>2.6", "numpy>1.16.3"] diff --git a/releasenotes/notes/update-conan-0e891458bcc96ee2.yaml b/releasenotes/notes/update-conan-0e891458bcc96ee2.yaml new file mode 100644 index 0000000000..a7355f6610 --- /dev/null +++ b/releasenotes/notes/update-conan-0e891458bcc96ee2.yaml @@ -0,0 +1,7 @@ +--- +upgrade: + - | + The minimum version of `Conan `__ has been increased to 1.31.2. This was necessary + to fix a compatibility issue with newer versions of the `urllib3 `__ (which + is a dependency of Conan). It also adds native support for AppleClang 12 which is useful for users with + new Apple computers. diff --git a/requirements-dev.txt b/requirements-dev.txt index d5d99f0a58..b06fe95ef3 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,6 +1,6 @@ stestr>=2.5.0 cmake!=3.17.1,!=3.17.0 -conan>=1.22.2 +conan>=1.31.2 scikit-build asv cvxpy>=1.0.0;python_version>'3.6' and python_version<='3.8' @@ -14,5 +14,3 @@ jupyter-sphinx;python_version<'3.8' reno>=3.1.0 ddt>=1.2.0,!=1.4.0 -# Problem with Conan and urllib3==1.26 -urllib3<1.26 diff --git a/setup.py b/setup.py index 8c017f842e..5d24e05d79 100644 --- a/setup.py +++ b/setup.py @@ -19,10 +19,7 @@ try: from conans import client except ImportError: - # Problem with Conan and urllib3 1.26 - subprocess.call([sys.executable, '-m', 'pip', 'install', 'urllib3<1.26']) - - subprocess.call([sys.executable, '-m', 'pip', 'install', 'conan']) + subprocess.call([sys.executable, '-m', 'pip', 'install', 'conan>=1.31.2']) from conans import client try: @@ -60,7 +57,6 @@ 'cmake!=3.17,!=3.17.0', ] if not _DISABLE_CONAN: - setup_requirements.append('urllib3<1.26') setup_requirements.append('conan>=1.22.2') requirements = common_requirements + ['qiskit-terra>=0.12.0'] From 5b58330966b5336088f8e2bdd26bc42e58822e8a Mon Sep 17 00:00:00 2001 From: Max Rossmannek Date: Thu, 14 Jan 2021 14:08:02 +0100 Subject: [PATCH 074/126] Add explanation for static wheel compilation (#1038) As discussed in #1033 we should document how to compile a static wheel of Qiskit Aer. This commit adds such documentation to `CONTRIBUTING.md`. I have attempted to make the explanation easy to follow but also easily searchable for potential pitfalls (thus, the inclusion of possible error messages). Hopefully, this will help with the visibility of this section and guide users through the process more easily. --- CONTRIBUTING.md | 64 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 68fc2d0cdf..3abae3205e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -630,6 +630,70 @@ Few notes on GPU builds: 3. We don't need NVIDIA® drivers for building, but we need them for running simulations 4. Only Linux platforms are supported +### Building a statically linked wheel + +If you encounter an error similar to the following, you may are likely in the need of compiling a +statically linked wheel. +``` + ImportError: libopenblas.so.0: cannot open shared object file: No such file or directory +``` +However, depending on your setup this can proof difficult at times. +Thus, here we present instructions which are known to work under Linux. + +In general, the workflow is: +1. Compile a wheel +``` + qiskit-aer$ python ./setup.py bdist_wheel +``` +2. Repair it with [auditwheel](https://github.com/pypa/auditwheel) +``` + qiskit-aer$ auditwheel repair dist/qiskit_aer*.whl +``` +> `auditwheel` vendors the shared libraries into the binary to make it fully self-contained. + +The command above will attempt to repair the wheel for a `manylinux*` platform and will store it +under `wheelhouse/` from where you can install it. + +It may happen that you encounter the following error: +``` + auditwheel: error: cannot repair "qiskit_aer-0.8.0-cp36-cp36m-linux_x86_64.whl" to "manylinux1_x86_64" ABI because of the presence of too-recent versioned symbols. You'll need to compile the wheel on an older toolchain. +``` +This means that your toolchain uses later versions of system libraries than are allowed by the +`manylinux*` platform specification (see also [1], [2] and [3]). +If you do not need your wheel to support the `manylinux*` platform you can resolve this issue by +limiting the compatibility of your wheel to your specific platform. +You can find out which platform this is through +``` + qiskit-aer$ auditwheel show dist/qiskit_aer*.whl +``` +This will list the _platform tag_ (e.g. `linux_x86_64`). +You can then repair the wheel for this specific platform using: +``` + qiskit-aer$ auditwheel repair --plat linux_x86_64 dist/qiskit_aer*.whl +``` +You can now go ahead and install the wheel stored in `wheelhouse/`. + +Should you encounter a runtime error like +``` + Inconsistency detected by ld.so: dl-version.c: 205: _dl_check_map_versions: Assertion `needed != NULL' failed! +``` +this means that your [patchelf](https://github.com/NixOS/patchelf) version (which is used by +`auditwheel` under the hood) is too old (https://github.com/pypa/auditwheel/issues/103) +Version `0.9` of `patchelf` is the earliest to include the patch +https://github.com/NixOS/patchelf/pull/85 which resolves this issue. +In the unlikely event that the `patchelf` package provided by your operating +system only provides an older version, fear not, because it is really easy to +[compile `patchelf` from source](https://github.com/NixOS/patchelf#compiling-and-testing). + +Hopefully, this information was helpful. +In case you need more detailed information on some of the errors which may occur be sure to read +through https://github.com/Qiskit/qiskit-aer/issues/1033. + +[1]: https://www.python.org/dev/peps/pep-0513/ +[2]: https://www.python.org/dev/peps/pep-0571/ +[3]: https://www.python.org/dev/peps/pep-0599/ + + ## Useful CMake flags From 33702ebe5c7b3d0cecbac5b7e2ddae7c1dd54dca Mon Sep 17 00:00:00 2001 From: "Christopher J. Wood" Date: Fri, 15 Jan 2021 10:36:31 -0500 Subject: [PATCH 075/126] Refactor experiment data (#1002) * Move current experiment data handling to legacy directory This is in preparation for refactoring experiment data while maintaining backwards compatability for deprecating current snapshot and data formats. * Add new result data structures - single data - accumulated data - average data - list data and a recursive DataMap class for nesting these structures in string-keyed maps, and a DataInserter mixing for later use in buidling containers of multiple DataMaps * Add new Data and Metadata class for results * Rename legacy ExperimentData as SnapshotData * Remove other data types from legacy data * Add helper methods to base state class for saving data Co-authored-by: Victor Villar --- .../aer/backends/wrappers/bindings.cc | 3 + src/controllers/controller.hpp | 55 +++-- src/controllers/qasm_controller.hpp | 18 +- src/controllers/statevector_controller.hpp | 4 +- src/controllers/unitary_controller.hpp | 6 +- src/framework/linalg/linops/linops_json.hpp | 6 +- src/framework/linalg/square.hpp | 4 +- src/framework/pybind_basics.hpp | 33 +++ src/framework/results/data/data.hpp | 229 ++++++++++++++++++ src/framework/results/data/metadata.hpp | 136 +++++++++++ .../results/data/mixins/data_cmatrix.hpp | 97 ++++++++ .../results/data/mixins/data_creg.hpp | 57 +++++ .../results/data/mixins/data_cvector.hpp | 69 ++++++ .../data/mixins/pybind_data_cmatrix.hpp | 63 +++++ .../results/data/mixins/pybind_data_creg.hpp | 51 ++++ .../data/mixins/pybind_data_cvector.hpp | 55 +++++ src/framework/results/data/pybind_data.hpp | 44 ++++ .../results/data/pybind_metadata.hpp | 42 ++++ .../results/data/subtypes/accum_data.hpp | 81 +++++++ .../results/data/subtypes/average_data.hpp | 114 +++++++++ .../results/data/subtypes/data_map.hpp | 220 +++++++++++++++++ .../results/data/subtypes/list_data.hpp | 71 ++++++ .../results/data/subtypes/pybind_data_map.hpp | 76 ++++++ .../results/data/subtypes/pybind_subtypes.hpp | 69 ++++++ .../results/data/subtypes/single_data.hpp | 80 ++++++ src/framework/results/experiment_result.hpp | 78 ++---- .../results/{data => legacy}/average_data.hpp | 24 +- .../{data => legacy}/average_snapshot.hpp | 8 +- .../{data => legacy}/data_container.hpp | 69 +----- .../results/{data => legacy}/pershot_data.hpp | 0 .../{data => legacy}/pershot_snapshot.hpp | 2 +- .../results/{ => legacy}/pybind_data.hpp | 129 +++------- .../snapshot_data.hpp} | 200 +++------------ src/framework/results/pybind_result.hpp | 37 +-- src/framework/results/result.hpp | 32 +-- src/framework/stl_ostream.hpp | 4 +- src/framework/utils.hpp | 3 + .../density_matrix/densitymatrix.hpp | 2 +- .../density_matrix/densitymatrix_state.hpp | 10 +- .../extended_stabilizer_state.hpp | 4 +- .../matrix_product_state.hpp | 41 ++-- .../matrix_product_state_internal.cpp | 1 - .../stabilizer/stabilizer_state.hpp | 10 +- src/simulators/state.hpp | 211 ++++++++++++++-- src/simulators/statevector/qubitvector.hpp | 3 +- .../statevector/statevector_state.hpp | 30 ++- .../superoperator/superoperator.hpp | 2 +- src/simulators/unitary/unitary_state.hpp | 2 +- src/transpile/delay_measure.hpp | 6 +- src/transpile/fusion.hpp | 37 ++- src/transpile/truncate_qubits.hpp | 6 +- 51 files changed, 2048 insertions(+), 586 deletions(-) create mode 100644 src/framework/results/data/data.hpp create mode 100644 src/framework/results/data/metadata.hpp create mode 100644 src/framework/results/data/mixins/data_cmatrix.hpp create mode 100644 src/framework/results/data/mixins/data_creg.hpp create mode 100644 src/framework/results/data/mixins/data_cvector.hpp create mode 100755 src/framework/results/data/mixins/pybind_data_cmatrix.hpp create mode 100755 src/framework/results/data/mixins/pybind_data_creg.hpp create mode 100755 src/framework/results/data/mixins/pybind_data_cvector.hpp create mode 100755 src/framework/results/data/pybind_data.hpp create mode 100755 src/framework/results/data/pybind_metadata.hpp create mode 100755 src/framework/results/data/subtypes/accum_data.hpp create mode 100755 src/framework/results/data/subtypes/average_data.hpp create mode 100755 src/framework/results/data/subtypes/data_map.hpp create mode 100755 src/framework/results/data/subtypes/list_data.hpp create mode 100755 src/framework/results/data/subtypes/pybind_data_map.hpp create mode 100755 src/framework/results/data/subtypes/pybind_subtypes.hpp create mode 100755 src/framework/results/data/subtypes/single_data.hpp rename src/framework/results/{data => legacy}/average_data.hpp (91%) rename src/framework/results/{data => legacy}/average_snapshot.hpp (93%) rename src/framework/results/{data => legacy}/data_container.hpp (80%) rename src/framework/results/{data => legacy}/pershot_data.hpp (100%) rename src/framework/results/{data => legacy}/pershot_snapshot.hpp (98%) rename src/framework/results/{ => legacy}/pybind_data.hpp (72%) rename src/framework/results/{experiment_data.hpp => legacy/snapshot_data.hpp} (61%) diff --git a/qiskit/providers/aer/backends/wrappers/bindings.cc b/qiskit/providers/aer/backends/wrappers/bindings.cc index 29572f9c23..3dade483ae 100644 --- a/qiskit/providers/aer/backends/wrappers/bindings.cc +++ b/qiskit/providers/aer/backends/wrappers/bindings.cc @@ -4,6 +4,9 @@ DISABLE_WARNING_PUSH #include DISABLE_WARNING_POP +#if defined(_MSC_VER) + #undef snprintf +#endif #include "framework/matrix.hpp" #include "framework/types.hpp" diff --git a/src/controllers/controller.hpp b/src/controllers/controller.hpp index d2a9787c80..59c3e78a48 100755 --- a/src/controllers/controller.hpp +++ b/src/controllers/controller.hpp @@ -179,6 +179,13 @@ class Controller { // Validation threshold for validating states and operators double validation_threshold_ = 1e-8; + // Save counts as memory list + bool save_creg_memory_ = false; + + // Save count data + void save_count_data(ExperimentResult &result, + const ClassicalRegister &creg) const; + //----------------------------------------------------------------------- // Parallelization Config //----------------------------------------------------------------------- @@ -234,6 +241,9 @@ void Controller::set_config(const json_t &config) { // Load validation threshold JSON::get_value(validation_threshold_, "validation_threshold", config); + // Load config for memory (creg list data) + JSON::get_value(save_creg_memory_, "memory", config); + #ifdef _OPENMP // Load OpenMP maximum thread settings if (JSON::check_key("max_parallel_threads", config)) @@ -503,8 +513,8 @@ Result Controller::execute(const json_t &qobj_js) { } // Stop the timer and add total timing data including qobj parsing auto timer_stop = myclock_t::now(); - result.metadata["time_taken"] = - std::chrono::duration(timer_stop - timer_start).count(); + auto time_taken = std::chrono::duration(timer_stop - timer_start).count(); + result.metadata.add(time_taken, "time_taken"); return result; } catch (std::exception &e) { // qobj was invalid, return valid output containing error message @@ -537,12 +547,12 @@ Result Controller::execute(std::vector &circuits, } #ifdef _OPENMP - result.metadata["omp_enabled"] = true; + result.metadata.add(true, "omp_enabled"); #else - result.metadata["omp_enabled"] = false; + result.metadata.add(false, "omp_enabled"); #endif - result.metadata["parallel_experiments"] = parallel_experiments_; - result.metadata["max_memory_mb"] = max_memory_mb_; + result.metadata.add(parallel_experiments_, "parallel_experiments"); + result.metadata.add(max_memory_mb_, "max_memory_mb"); #ifdef _OPENMP // Check if circuit parallelism is nested with one of the others @@ -554,7 +564,7 @@ Result Controller::execute(std::vector &circuits, #else omp_set_max_active_levels(3); #endif - result.metadata["omp_nested"] = parallel_nested_; + result.metadata.add(parallel_nested_, "omp_nested"); } else { parallel_nested_ = false; #ifdef _WIN32 @@ -566,16 +576,17 @@ Result Controller::execute(std::vector &circuits, #endif // then- and else-blocks have intentionally duplication. // Nested omp has significant overheads even though a guard condition exists. + const int NUM_RESULTS = result.results.size(); if (parallel_experiments_ > 1) { #pragma omp parallel for num_threads(parallel_experiments_) - for (int j = 0; j < result.results.size(); ++j) { + for (int j = 0; j < NUM_RESULTS; ++j) { // Make a copy of the noise model for each circuit execution // so that it can be modified if required auto circ_noise_model = noise_model; execute_circuit(circuits[j], circ_noise_model, config, result.results[j]); } } else { - for (int j = 0; j < result.results.size(); ++j) { + for (int j = 0; j < NUM_RESULTS; ++j) { // Make a copy of the noise model for each circuit execution // so that it can be modified if required auto circ_noise_model = noise_model; @@ -588,7 +599,7 @@ Result Controller::execute(std::vector &circuits, bool all_failed = true; result.status = Result::Status::completed; - for (size_t i = 0; i < result.results.size(); ++i) { + for (int i = 0; i < NUM_RESULTS; ++i) { auto& experiment = result.results[i]; if (experiment.status == ExperimentResult::Status::completed) { all_failed = false; @@ -604,8 +615,8 @@ Result Controller::execute(std::vector &circuits, // Stop the timer and add total timing data auto timer_stop = myclock_t::now(); - result.metadata["time_taken"] = - std::chrono::duration(timer_stop - timer_start).count(); + auto time_taken = std::chrono::duration(timer_stop - timer_start).count(); + result.metadata.add(time_taken, "time_taken"); } // If execution failed return valid output reporting error catch (std::exception &e) { @@ -624,7 +635,7 @@ void Controller::execute_circuit(Circuit &circ, auto timer_start = myclock_t::now(); // state circuit timer // Initialize circuit json return - result.data.set_config(config); + result.legacy_data.set_config(config); // Execute in try block so we can catch errors and return the error message // for individual circuit failures. @@ -674,7 +685,7 @@ void Controller::execute_circuit(Circuit &circ, #else omp_set_max_active_levels(2); #endif - result.metadata["omp_nested"] = true; + result.metadata.add(true, "omp_nested"); } else { #ifdef _WIN32 omp_set_nested(0); @@ -712,8 +723,8 @@ void Controller::execute_circuit(Circuit &circ, result.header = circ.header; result.shots = circ.shots; result.seed = circ.seed; - result.metadata["parallel_shots"] = parallel_shots_; - result.metadata["parallel_state_update"] = parallel_state_update_; + result.metadata.add(parallel_shots_, "parallel_shots"); + result.metadata.add(parallel_state_update_, "parallel_state_update"); // Add timer data auto timer_stop = myclock_t::now(); // stop timer double time_taken = @@ -727,6 +738,18 @@ void Controller::execute_circuit(Circuit &circ, } } + +void Controller::save_count_data(ExperimentResult &result, + const ClassicalRegister &creg) const { + if (creg.memory_size() > 0) { + std::string memory_hex = creg.memory_hex(); + result.data.add_accum(static_cast(1ULL), "counts", memory_hex); + if (save_creg_memory_) { + result.data.add_list(std::move(memory_hex), "memory"); + } + } +} + //------------------------------------------------------------------------- } // end namespace Base //------------------------------------------------------------------------- diff --git a/src/controllers/qasm_controller.hpp b/src/controllers/qasm_controller.hpp index c282baf6fc..edf1ba8ca2 100755 --- a/src/controllers/qasm_controller.hpp +++ b/src/controllers/qasm_controller.hpp @@ -883,13 +883,12 @@ void QasmController::run_circuit_helper(const Circuit& circ, // Output data container result.set_config(config); - result.add_metadata("method", state.name()); + result.metadata.add(state.name(), "method"); state.add_metadata(result); // Add measure sampling to metadata // Note: this will set to `true` if sampling is enabled for the circuit - result.add_metadata("measure_sampling", false); - + result.metadata.add(false, "measure_sampling"); // Choose execution method based on noise and method Circuit opt_circ; @@ -944,7 +943,7 @@ void QasmController::run_single_shot(const Circuit& circ, RngEngine& rng) const { initialize_state(circ, state, initial_state); state.apply_ops(circ.ops, result, rng, true); - state.add_creg_to_data(result); + Base::Controller::save_count_data(result, state.creg()); } template @@ -973,7 +972,7 @@ void QasmController::run_multi_shot(const Circuit& circ, measure_sampler(ops, shots, state, result, rng); // Add measure sampling metadata - result.add_metadata("measure_sampling", true); + result.metadata.add(true, "measure_sampling"); } else { // Perform standard execution if we cannot apply the // measurement sampling optimization @@ -1052,7 +1051,7 @@ void QasmController::measure_sampler( // Check if meas_circ is empty, and if so return initial creg if (meas_roerror_ops.empty()) { while (shots-- > 0) { - state.add_creg_to_data(result); + Base::Controller::save_count_data(result, state.creg()); } return; } @@ -1121,11 +1120,8 @@ void QasmController::measure_sampler( creg.apply_roerror(roerror, rng); } - auto memory = creg.memory_hex(); - result.data.add_memory_count(memory); - result.data.add_pershot_memory(memory); - - result.data.add_pershot_register(creg.register_hex()); + // Save count data + Base::Controller::save_count_data(result, creg); // pop off processed sample all_samples.pop_back(); diff --git a/src/controllers/statevector_controller.hpp b/src/controllers/statevector_controller.hpp index e5b9f8f6da..9a21fe070e 100755 --- a/src/controllers/statevector_controller.hpp +++ b/src/controllers/statevector_controller.hpp @@ -316,10 +316,10 @@ void StatevectorController::run_circuit_helper( } state.initialize_creg(circ.num_memory, circ.num_registers); state.apply_ops(*op_ptr, result, rng); - state.add_creg_to_data(result); + Base::Controller::save_count_data(result, state.creg()); // Add final state to the data - result.data.add_additional_data("statevector", state.qreg().move_to_vector()); + state.save_data_single(result, "statevector", state.qreg().move_to_vector()); } //------------------------------------------------------------------------- diff --git a/src/controllers/unitary_controller.hpp b/src/controllers/unitary_controller.hpp index 7d0b4eda0a..692dc55e81 100755 --- a/src/controllers/unitary_controller.hpp +++ b/src/controllers/unitary_controller.hpp @@ -293,7 +293,7 @@ void UnitaryController::run_circuit_helper( // Output data container result.set_config(config); - result.add_metadata("method", state.name()); + result.metadata.add(state.name(), "method"); // Optimize circuit const std::vector* op_ptr = &circ.ops; @@ -316,10 +316,10 @@ void UnitaryController::run_circuit_helper( } state.initialize_creg(circ.num_memory, circ.num_registers); state.apply_ops(*op_ptr, result, rng); - state.add_creg_to_data(result); + Base::Controller::save_count_data(result, state.creg()); // Add final state unitary to the data - result.data.add_additional_data("unitary", state.qreg().move_to_matrix()); + state.save_data_single(result, "unitary", state.qreg().move_to_matrix()); } //------------------------------------------------------------------------- diff --git a/src/framework/linalg/linops/linops_json.hpp b/src/framework/linalg/linops/linops_json.hpp index 03581ea5a7..8473bfbb82 100755 --- a/src/framework/linalg/linops/linops_json.hpp +++ b/src/framework/linalg/linops/linops_json.hpp @@ -28,7 +28,7 @@ namespace Linalg { //---------------------------------------------------------------------------- // Linear operations //---------------------------------------------------------------------------- -json_t& iadd(json_t& lhs, const json_t& rhs) { +inline json_t& iadd(json_t& lhs, const json_t& rhs) { // Null case if (lhs.is_null()) { lhs = rhs; @@ -57,12 +57,12 @@ json_t& iadd(json_t& lhs, const json_t& rhs) { return lhs; } -json_t add(const json_t& lhs, const json_t& rhs) { +inline json_t add(const json_t& lhs, const json_t& rhs) { json_t result = lhs; return iadd(result, rhs); } -json_t& isub(json_t& lhs, const json_t& rhs) { +inline json_t& isub(json_t& lhs, const json_t& rhs) { // Null case if (rhs.is_null()) { return lhs; diff --git a/src/framework/linalg/square.hpp b/src/framework/linalg/square.hpp index 43e4ba50c2..6baae7054f 100755 --- a/src/framework/linalg/square.hpp +++ b/src/framework/linalg/square.hpp @@ -157,7 +157,7 @@ Vector square(const Vector& vec) { // Entrywise square of JSON //---------------------------------------------------------------------------- -json_t& isquare(json_t& data) { +inline json_t& isquare(json_t& data) { // Terminating case if (data.is_number()) { double val = data; @@ -180,7 +180,7 @@ json_t& isquare(json_t& data) { throw std::invalid_argument("Input JSONs cannot be squared."); } -json_t square(const json_t& data) { +inline json_t square(const json_t& data) { json_t result = data; return isquare(result); } diff --git a/src/framework/pybind_basics.hpp b/src/framework/pybind_basics.hpp index 1f2e6c42d1..9a86c5d408 100755 --- a/src/framework/pybind_basics.hpp +++ b/src/framework/pybind_basics.hpp @@ -44,6 +44,14 @@ template py::object to_python(AER::Vector &&obj); // Move a Vector to Python via recusivly calling to_python on elements template py::object to_python(std::vector &&obj); +// Move an Unordered string map to Python object by calling to_python on elements +template py::object to_python(std::unordered_map &&obj); + +// Move an Unordered string map into an existing Python dict +template +void add_to_python(py::dict &pydata, std::unordered_map &&obj); + + // Template specialization for moving numeric std::vectors to Numpy arrays template <> py::object to_python(std::vector &&obj); template <> py::object to_python(std::vector &&obj); @@ -52,6 +60,10 @@ template <> py::object to_python(std::vector &&obj); template <> py::object to_python(std::vector> &&obj); template <> py::object to_python(std::vector> &&obj); +// Template specialization for JSON +// NOTE: this copies rather than moves +template <> py::object to_python(json_t &&obj); + //------------------------------------------------------------------------------ // Convert To Numpy Arrays //------------------------------------------------------------------------------ @@ -81,6 +93,27 @@ py::object to_python(T &&obj) { return py::cast(obj, py::return_value_policy::move); } +template <> +py::object to_python(json_t &&obj) { + py::object pydata; + from_json(obj, pydata); + return pydata; +} + +template +py::object to_python(std::unordered_map &&obj) { + py::dict pydata; + add_to_python(pydata, std::move(obj)); + return std::move(pydata); +} + +template +void add_to_python(py::dict &pydata, std::unordered_map &&obj) { + for(auto& elt : obj) { + pydata[elt.first.data()] = to_python(std::move(elt.second)); + } +} + template py::object to_python(std::vector &&obj) { py::list pydata; diff --git a/src/framework/results/data/data.hpp b/src/framework/results/data/data.hpp new file mode 100644 index 0000000000..ce0e945f5c --- /dev/null +++ b/src/framework/results/data/data.hpp @@ -0,0 +1,229 @@ +/** + * 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. + */ + +#ifndef _aer_framework_results_data_hpp_ +#define _aer_framework_results_data_hpp_ + +// Data primatives +#include "framework/results/data/subtypes/data_map.hpp" +#include "framework/results/data/subtypes/accum_data.hpp" +#include "framework/results/data/subtypes/average_data.hpp" +#include "framework/results/data/subtypes/list_data.hpp" +#include "framework/results/data/subtypes/single_data.hpp" + +// Data Containers +#include "framework/results/data/mixins/data_creg.hpp" +#include "framework/results/data/mixins/data_cmatrix.hpp" +#include "framework/results/data/mixins/data_cvector.hpp" + +namespace AER { + +//============================================================================ +// Result container for Qiskit-Aer +//============================================================================ + +struct Data : public DataCReg, + public DataCVector, + public DataCMatrix { + + //---------------------------------------------------------------- + // Measurement data + //---------------------------------------------------------------- + + // Add outcome to count dictionary + void add_count(const std::string &outcome); + + // Add outcome to memory list + void add_memory(const std::string &outcome); + void add_memory(std::string &&outcome); + + //---------------------------------------------------------------- + // Add single data + //---------------------------------------------------------------- + template + void add_single(const T &data, const std::string &outer_key, + const Args &... inner_keys); + + template + void add_single(T &data, const std::string &outer_key, + const Args &... inner_keys); + + template + void add_single(T &&data, const std::string &outer_key, + const Args &... inner_keys); + + //---------------------------------------------------------------- + // Add list data + //---------------------------------------------------------------- + template + void add_list(const T &data, const std::string &outer_key, + const Args &... inner_keys); + + template + void add_list(T &data, const std::string &outer_key, + const Args &... inner_keys); + + template + void add_list(T &&data, const std::string &outer_key, + const Args &... inner_keys); + + //---------------------------------------------------------------- + // Add accum data + //---------------------------------------------------------------- + template + void add_accum(const T &data, const std::string &outer_key, + const Args &... inner_keys); + + template + void add_accum(T &data, const std::string &outer_key, + const Args &... inner_keys); + + template + void add_accum(T &&data, const std::string &outer_key, + const Args &... inner_keys); + + //---------------------------------------------------------------- + // Add average data + //---------------------------------------------------------------- + template + void add_average(const T &data, const std::string &outer_key, + const Args &... inner_keys); + + template + void add_average(T &data, const std::string &outer_key, + const Args &... inner_keys); + + template + void add_average(T &&data, const std::string &outer_key, + const Args &... inner_keys); + + //---------------------------------------------------------------- + // Utility and config + //---------------------------------------------------------------- + + // Serialize engine data to JSON + json_t to_json(); + + // Combine stored data + Data &combine(Data &&other); +}; + +//------------------------------------------------------------------------------ +// Implementation +//------------------------------------------------------------------------------ + +Data &Data::combine(Data &&other) { + DataCVector::combine(std::move(other)); + DataCMatrix::combine(std::move(other)); + DataCReg::combine(std::move(other)); + return *this; +} + +json_t Data::to_json() { + json_t result; + DataCVector::add_to_json(result); + DataCMatrix::add_to_json(result); + DataCReg::add_to_json(result); + return result; +} + + +template +void Data::add_single(const T &data, const std::string &outer_key, + const Args &... inner_keys) { + DataMap::add(data, outer_key, + inner_keys...); +} + +template +void Data::add_single(T &data, const std::string &outer_key, + const Args &... inner_keys) { + DataMap::add(data, outer_key, + inner_keys...); +} + +template +void Data::add_single(T &&data, const std::string &outer_key, + const Args &... inner_keys) { + DataMap::add(std::move(data), outer_key, + inner_keys...); +} + +template +void Data::add_list(const T &data, const std::string &outer_key, + const Args &... inner_keys) { + DataMap::add(data, outer_key, + inner_keys...); +} + +template +void Data::add_list(T &data, const std::string &outer_key, + const Args &... inner_keys) { + DataMap::add(data, outer_key, + inner_keys...); +} + +template +void Data::add_list(T &&data, const std::string &outer_key, + const Args &... inner_keys) { + DataMap::add(std::move(data), outer_key, + inner_keys...); +} + +template +void Data::add_accum(const T &data, const std::string &outer_key, + const Args &... inner_keys) { + DataMap::add(data, outer_key, + inner_keys...); +} + +template +void Data::add_accum(T &data, const std::string &outer_key, + const Args &... inner_keys) { + DataMap::add(data, outer_key, + inner_keys...); +} + +template +void Data::add_accum(T &&data, const std::string &outer_key, + const Args &... inner_keys) { + DataMap::add(std::move(data), outer_key, + inner_keys...); +} + +template +void Data::add_average(const T &data, const std::string &outer_key, + const Args &... inner_keys) { + DataMap::add(data, outer_key, + inner_keys...); +} + +template +void Data::add_average(T &data, const std::string &outer_key, + const Args &... inner_keys) { + DataMap::add(data, outer_key, + inner_keys...); +} + +template +void Data::add_average(T &&data, const std::string &outer_key, + const Args &... inner_keys) { + DataMap::add(std::move(data), outer_key, + inner_keys...); +} + +//------------------------------------------------------------------------------ +} // end namespace AER +//------------------------------------------------------------------------------ +#endif diff --git a/src/framework/results/data/metadata.hpp b/src/framework/results/data/metadata.hpp new file mode 100644 index 0000000000..83820ea9f2 --- /dev/null +++ b/src/framework/results/data/metadata.hpp @@ -0,0 +1,136 @@ +/** + * 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. + */ + +#ifndef _aer_framework_results_data_metadata_hpp_ +#define _aer_framework_results_data_metadata_hpp_ + +#include "framework/results/data/subtypes/data_map.hpp" +#include "framework/results/data/subtypes/single_data.hpp" + +namespace AER { + +//============================================================================ +// Result container for Qiskit-Aer +//============================================================================ + +struct Metadata : public DataMap, + public DataMap, + public DataMap { + + //---------------------------------------------------------------- + // Add JSON metadata + //---------------------------------------------------------------- + template + void add(const json_t &data, const std::string &outer_key, + const Args &... inner_keys); + + template + void add(json_t &data, const std::string &outer_key, + const Args &... inner_keys); + + template + void add(json_t &&data, const std::string &outer_key, + const Args &... inner_keys); + + //---------------------------------------------------------------- + // Add general metadata + // + // These functions allow adding general data types via conversion + // to json_t. + //---------------------------------------------------------------- + template + void add(const T &data, const std::string &outer_key, + const Args &... inner_keys); + + template + void add(T &data, const std::string &outer_key, const Args &... inner_keys); + + template + void add(T &&data, const std::string &outer_key, const Args &... inner_keys); + + // Serialize engine data to JSON + json_t to_json(); + + // Combine stored data + Metadata &combine(Metadata &&other); +}; + +//------------------------------------------------------------------------------ +// Implementation +//------------------------------------------------------------------------------ + +Metadata &Metadata::combine(Metadata &&other) { + DataMap::combine(std::move(other)); + DataMap::combine(std::move(other)); + DataMap::combine(std::move(other)); + return *this; +} + +json_t Metadata::to_json() { + json_t result; + DataMap::add_to_json(result); + DataMap::add_to_json(result); + DataMap::add_to_json(result); + return result; +} + +template +void Metadata::add(const T &data, const std::string &outer_key, + const Args &... inner_keys) { + json_t tmp = data; + DataMap::add( + std::move(tmp), outer_key, inner_keys...); +} + +template +void Metadata::add(T &data, const std::string &outer_key, + const Args &... inner_keys) { + json_t tmp = data; + DataMap::add( + std::move(tmp), outer_key, inner_keys...); +} + +template +void Metadata::add(T &&data, const std::string &outer_key, + const Args &... inner_keys) { + json_t tmp = data; + DataMap::add( + std::move(tmp), outer_key, inner_keys...); +} + +template +void Metadata::add(const json_t &data, const std::string &outer_key, + const Args &... inner_keys) { + DataMap::add(data, outer_key, + inner_keys...); +} + +template +void Metadata::add(json_t &data, const std::string &outer_key, + const Args &... inner_keys) { + DataMap::add(data, outer_key, + inner_keys...); +} + +template +void Metadata::add(json_t &&data, const std::string &outer_key, + const Args &... inner_keys) { + DataMap::add( + std::move(data), outer_key, inner_keys...); +} + +//------------------------------------------------------------------------------ +} // end namespace AER +//------------------------------------------------------------------------------ +#endif diff --git a/src/framework/results/data/mixins/data_cmatrix.hpp b/src/framework/results/data/mixins/data_cmatrix.hpp new file mode 100644 index 0000000000..0ee169f659 --- /dev/null +++ b/src/framework/results/data/mixins/data_cmatrix.hpp @@ -0,0 +1,97 @@ +/** + * This code is part of Qiskit. + * + * (C) Copyright IBM 2020. + * + * 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. + */ + +#ifndef _aer_framework_results_data_cmatrix_hpp_ +#define _aer_framework_results_data_cmatrix_hpp_ + +#include "framework/results/data/subtypes/data_map.hpp" +#include "framework/results/data/subtypes/accum_data.hpp" +#include "framework/results/data/subtypes/average_data.hpp" +#include "framework/results/data/subtypes/list_data.hpp" +#include "framework/results/data/subtypes/single_data.hpp" +#include "framework/types.hpp" + +namespace AER { + +//============================================================================ +// Result container for Qiskit-Aer +//============================================================================ + +struct DataCMatrix : + public DataMap, 1>, + public DataMap, 1>, + public DataMap, 1>, + public DataMap, 1>, + public DataMap, 2>, + public DataMap, 2>, + public DataMap, 1>, + public DataMap, 1>, + public DataMap, 2>, + public DataMap, 2>, + public DataMap, 1>, + public DataMap, 1>, + public DataMap, 2>, + public DataMap, 2> { + + // Serialize engine data to JSON + void add_to_json(json_t &result); + + // Combine stored data + DataCMatrix &combine(DataCMatrix &&other); +}; + +//------------------------------------------------------------------------------ +// Implementation +//------------------------------------------------------------------------------ + +DataCMatrix &DataCMatrix::combine(DataCMatrix &&other) { + DataMap, 1>::combine(std::move(other)); + DataMap, 1>::combine(std::move(other)); + DataMap, 1>::combine(std::move(other)); + DataMap, 1>::combine(std::move(other)); + DataMap, 2>::combine(std::move(other)); + DataMap, 2>::combine(std::move(other)); + DataMap, 1>::combine(std::move(other)); + DataMap, 1>::combine(std::move(other)); + DataMap, 2>::combine(std::move(other)); + DataMap, 2>::combine(std::move(other)); + DataMap, 1>::combine(std::move(other)); + DataMap, 1>::combine(std::move(other)); + DataMap, 2>::combine(std::move(other)); + DataMap, 2>::combine(std::move(other)); + return *this; +} + +void DataCMatrix::add_to_json(json_t &result) { + + DataMap, 1>::add_to_json(result); + DataMap, 1>::add_to_json(result); + DataMap, 1>::add_to_json(result); + DataMap, 1>::add_to_json(result); + DataMap, 2>::add_to_json(result); + DataMap, 2>::add_to_json(result); + DataMap, 1>::add_to_json(result); + DataMap, 1>::add_to_json(result); + DataMap, 2>::add_to_json(result); + DataMap, 2>::add_to_json(result); + DataMap, 1>::add_to_json(result); + DataMap, 1>::add_to_json(result); + DataMap, 2>::add_to_json(result); + DataMap, 2>::add_to_json(result); +} + +//------------------------------------------------------------------------------ +} // end namespace AER +//------------------------------------------------------------------------------ +#endif diff --git a/src/framework/results/data/mixins/data_creg.hpp b/src/framework/results/data/mixins/data_creg.hpp new file mode 100644 index 0000000000..21da68cd56 --- /dev/null +++ b/src/framework/results/data/mixins/data_creg.hpp @@ -0,0 +1,57 @@ +/** + * This code is part of Qiskit. + * + * (C) Copyright IBM 2020. + * + * 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. + */ + +#ifndef _aer_framework_results_data_creg_hpp_ +#define _aer_framework_results_data_creg_hpp_ + +#include "framework/results/data/subtypes/data_map.hpp" +#include "framework/results/data/subtypes/list_data.hpp" +#include "framework/results/data/subtypes/single_data.hpp" +#include "framework/types.hpp" + +namespace AER { + +//============================================================================ +// Result container for Qiskit-Aer +//============================================================================ + +struct DataCReg : public DataMap, // Counts + public DataMap // Memory +{ + // Serialize engine data to JSON + void add_to_json(json_t &result); + + // Combine stored data + DataCReg &combine(DataCReg &&other); +}; + +//------------------------------------------------------------------------------ +// Implementation +//------------------------------------------------------------------------------ + +DataCReg &DataCReg::combine(DataCReg &&other) { + DataMap::combine(std::move(other)); + DataMap::combine(std::move(other)); + return *this; +} + +void DataCReg::add_to_json(json_t &result) { + DataMap::add_to_json(result); + DataMap::add_to_json(result); +} + +//------------------------------------------------------------------------------ +} // end namespace AER +//------------------------------------------------------------------------------ +#endif diff --git a/src/framework/results/data/mixins/data_cvector.hpp b/src/framework/results/data/mixins/data_cvector.hpp new file mode 100644 index 0000000000..c221e16cc2 --- /dev/null +++ b/src/framework/results/data/mixins/data_cvector.hpp @@ -0,0 +1,69 @@ +/** + * This code is part of Qiskit. + * + * (C) Copyright IBM 2020. + * + * 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. + */ + +#ifndef _aer_framework_results_data_cvector_hpp_ +#define _aer_framework_results_data_cvector_hpp_ + +#include "framework/results/data/subtypes/data_map.hpp" +#include "framework/results/data/subtypes/list_data.hpp" +#include "framework/results/data/subtypes/single_data.hpp" +#include "framework/types.hpp" + +namespace AER { + +//============================================================================ +// Result container for Qiskit-Aer +//============================================================================ + +struct DataCVector : public DataMap, 1>, + public DataMap, 1>, + public DataMap, 1>, + public DataMap, 1>, + public DataMap, 2>, + public DataMap, 2> { + + // Serialize engine data to JSON + void add_to_json(json_t &result); + + // Combine stored data + DataCVector &combine(DataCVector &&other); +}; + +//------------------------------------------------------------------------------ +// Implementation +//------------------------------------------------------------------------------ + +DataCVector &DataCVector::combine(DataCVector &&other) { + DataMap, 1>::combine(std::move(other)); + DataMap, 1>::combine(std::move(other)); + DataMap, 1>::combine(std::move(other)); + DataMap, 1>::combine(std::move(other)); + DataMap, 2>::combine(std::move(other)); + DataMap, 2>::combine(std::move(other)); + return *this; +} + +void DataCVector::add_to_json(json_t &result) { + DataMap, 1>::add_to_json(result); + DataMap, 1>::add_to_json(result); + DataMap, 1>::add_to_json(result); + DataMap, 1>::add_to_json(result); + DataMap, 2>::add_to_json(result); + DataMap, 2>::add_to_json(result); +} + +//------------------------------------------------------------------------------ +} // end namespace AER +//------------------------------------------------------------------------------ +#endif diff --git a/src/framework/results/data/mixins/pybind_data_cmatrix.hpp b/src/framework/results/data/mixins/pybind_data_cmatrix.hpp new file mode 100755 index 0000000000..e503c1de46 --- /dev/null +++ b/src/framework/results/data/mixins/pybind_data_cmatrix.hpp @@ -0,0 +1,63 @@ +/** + * This code is part of Qiskit. + * + * (C) Copyright IBM 2020. + * + * 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. + */ + +#ifndef _aer_framework_result_data_pybind_data_cmatrix_hpp_ +#define _aer_framework_result_data_pybind_data_cmatrix_hpp_ + +#include "framework/results/data/mixins/data_cmatrix.hpp" +#include "framework/results/data/subtypes/pybind_data_map.hpp" + +//------------------------------------------------------------------------------ +// Aer C++ -> Python Conversion +//------------------------------------------------------------------------------ + +namespace AerToPy { + +// Move an DataCMatrix container object to a new Python dict +py::object to_python(AER::DataCMatrix &&data); + +// Move an DataCMatrix container object to an existing new Python dict +void add_to_python(py::dict &pydata, AER::DataCMatrix &&data); + +} //end namespace AerToPy + + +//============================================================================ +// Implementations +//============================================================================ + +py::object AerToPy::to_python(AER::DataCMatrix &&data) { + py::dict pydata; + AerToPy::add_to_python(pydata, std::move(data)); + return std::move(pydata); +} + +void AerToPy::add_to_python(py::dict &pydata, AER::DataCMatrix &&data) { + AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); + AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); + AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); + AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); + AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); + AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); + AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); + AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); + AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); + AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); + AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); + AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); + AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); + AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); +} + +#endif diff --git a/src/framework/results/data/mixins/pybind_data_creg.hpp b/src/framework/results/data/mixins/pybind_data_creg.hpp new file mode 100755 index 0000000000..3e7e6b24bf --- /dev/null +++ b/src/framework/results/data/mixins/pybind_data_creg.hpp @@ -0,0 +1,51 @@ +/** + * This code is part of Qiskit. + * + * (C) Copyright IBM 2020. + * + * 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. + */ + +#ifndef _aer_framework_result_data_pybind_data_creg_hpp_ +#define _aer_framework_result_data_pybind_data_creg_hpp_ + +#include "framework/results/data/mixins/data_creg.hpp" +#include "framework/results/data/subtypes/pybind_data_map.hpp" + +//------------------------------------------------------------------------------ +// Aer C++ -> Python Conversion +//------------------------------------------------------------------------------ + +namespace AerToPy { + +// Move an DataCReg container object to a new Python dict +py::object to_python(AER::DataCReg &&data); + +// Move an DataCReg container object to an existing new Python dict +void add_to_python(py::dict &pydata, AER::DataCReg &&data); + +} //end namespace AerToPy + + +//============================================================================ +// Implementations +//============================================================================ + +py::object AerToPy::to_python(AER::DataCReg &&data) { + py::dict pydata; + AerToPy::add_to_python(pydata, std::move(data)); + return std::move(pydata); +} + +void AerToPy::add_to_python(py::dict &pydata, AER::DataCReg &&data) { + AerToPy::add_to_python(pydata, static_cast&&>(data)); + AerToPy::add_to_python(pydata, static_cast&&>(data)); +} + +#endif diff --git a/src/framework/results/data/mixins/pybind_data_cvector.hpp b/src/framework/results/data/mixins/pybind_data_cvector.hpp new file mode 100755 index 0000000000..ccfe0523f2 --- /dev/null +++ b/src/framework/results/data/mixins/pybind_data_cvector.hpp @@ -0,0 +1,55 @@ +/** + * This code is part of Qiskit. + * + * (C) Copyright IBM 2020. + * + * 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. + */ + +#ifndef _aer_framework_result_data_pybind_data_cvector_hpp_ +#define _aer_framework_result_data_pybind_data_cvector_hpp_ + +#include "framework/results/data/mixins/data_cvector.hpp" +#include "framework/results/data/subtypes/pybind_data_map.hpp" + +//------------------------------------------------------------------------------ +// Aer C++ -> Python Conversion +//------------------------------------------------------------------------------ + +namespace AerToPy { + +// Move an DataCVector container object to a new Python dict +py::object to_python(AER::DataCVector &&data); + +// Move an DataCVector container object to an existing new Python dict +void add_to_python(py::dict &pydata, AER::DataCVector &&data); + +} //end namespace AerToPy + + +//============================================================================ +// Implementations +//============================================================================ + +py::object AerToPy::to_python(AER::DataCVector &&data) { + py::dict pydata; + AerToPy::add_to_python(pydata, std::move(data)); + return std::move(pydata); +} + +void AerToPy::add_to_python(py::dict &pydata, AER::DataCVector &&data) { + AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); + AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); + AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); + AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); + AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); + AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); +} + +#endif diff --git a/src/framework/results/data/pybind_data.hpp b/src/framework/results/data/pybind_data.hpp new file mode 100755 index 0000000000..d6eefab275 --- /dev/null +++ b/src/framework/results/data/pybind_data.hpp @@ -0,0 +1,44 @@ +/** + * This code is part of Qiskit. + * + * (C) Copyright IBM 2020. + * + * 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. + */ + +#ifndef _aer_framework_result_data_pybind_data_hpp_ +#define _aer_framework_result_data_pybind_data_hpp_ + +#include "framework/results/data/data.hpp" +#include "framework/results/data/mixins/pybind_data_creg.hpp" +#include "framework/results/data/mixins/pybind_data_cmatrix.hpp" +#include "framework/results/data/mixins/pybind_data_cvector.hpp" + +namespace AerToPy { + +// Move an ExperimentResult data object to a Python dict +template <> py::object to_python(AER::Data &&data); + +} //end namespace AerToPy + + +//============================================================================ +// Implementations +//============================================================================ + +template <> +py::object AerToPy::to_python(AER::Data &&data) { + py::dict pydata; + AerToPy::add_to_python(pydata, static_cast(data)); + AerToPy::add_to_python(pydata, static_cast(data)); + AerToPy::add_to_python(pydata, static_cast(data)); + return std::move(pydata); +} + +#endif diff --git a/src/framework/results/data/pybind_metadata.hpp b/src/framework/results/data/pybind_metadata.hpp new file mode 100755 index 0000000000..244083d931 --- /dev/null +++ b/src/framework/results/data/pybind_metadata.hpp @@ -0,0 +1,42 @@ +/** + * This code is part of Qiskit. + * + * (C) Copyright IBM 2020. + * + * 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. + */ + +#ifndef _aer_framework_result_data_pybind_metadata_hpp_ +#define _aer_framework_result_data_pybind_metadata_hpp_ + +#include "framework/results/data/metadata.hpp" +#include "framework/results/data/subtypes/pybind_data_map.hpp" + +namespace AerToPy { + +// Move an ExperimentResult metdata object to a Python dict +template <> py::object to_python(AER::Metadata &&metadata); + +} //end namespace AerToPy + + +//============================================================================ +// Implementations +//============================================================================ + +template <> +py::object AerToPy::to_python(AER::Metadata &&metadata) { + py::dict pydata; + add_to_python(pydata, static_cast&&>(metadata)); + add_to_python(pydata, static_cast&&>(metadata)); + add_to_python(pydata, static_cast&&>(metadata)); + return std::move(pydata); +} + +#endif diff --git a/src/framework/results/data/subtypes/accum_data.hpp b/src/framework/results/data/subtypes/accum_data.hpp new file mode 100755 index 0000000000..2e585a79b3 --- /dev/null +++ b/src/framework/results/data/subtypes/accum_data.hpp @@ -0,0 +1,81 @@ +/** + * This code is part of Qiskit. + * + * (C) Copyright IBM 2020. + * + * 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. + */ + +#ifndef _aer_framework_results_data_subtypes_accum_hpp_ +#define _aer_framework_results_data_subtypes_accum_hpp_ + +#include "framework/linalg/linalg.hpp" +#include "framework/results/data/subtypes/single_data.hpp" + +namespace AER { + +template +class AccumData : public SingleData { +using Base = SingleData; +public: + // Add data (copy) + void add(const T& data); + + // Add data (move) + void add(T&& data); + + // Combine data (move) + void combine(AccumData&& other); + + // Clear all stored data + void clear(); + +protected: + bool empty_ = true; +}; + +//------------------------------------------------------------------------------ +// Implementation +//------------------------------------------------------------------------------ + +template +void AccumData::add(const T& data) { + if (empty_) { + Base::data_ = data; + empty_ = false; + } else { + Linalg::iadd(Base::data_, data); + } +} + +template +void AccumData::add(T&& data) { + if (empty_) { + Base::data_ = std::move(data); + empty_ = false; + } else { + Linalg::iadd(Base::data_, std::move(data)); + } +} + +template +void AccumData::combine(AccumData&& other) { + add(std::move(other.data_)); +} + +template +void AccumData::clear() { + Base::clear(); + empty_ = true; +} + +//------------------------------------------------------------------------------ +} // end namespace AER +//------------------------------------------------------------------------------ +#endif diff --git a/src/framework/results/data/subtypes/average_data.hpp b/src/framework/results/data/subtypes/average_data.hpp new file mode 100755 index 0000000000..2b70673e47 --- /dev/null +++ b/src/framework/results/data/subtypes/average_data.hpp @@ -0,0 +1,114 @@ +/** + * This code is part of Qiskit. + * + * (C) Copyright IBM 2020. + * + * 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. + */ + +#ifndef _aer_framework_results_data_subtypes_average_hpp_ +#define _aer_framework_results_data_subtypes_average_hpp_ + +#include "framework/results/data/subtypes/accum_data.hpp" + +namespace AER { + +template +class AverageData : public AccumData { +using Base = AccumData; +public: + // Access data + T& value(); + + // Add data (copy) + void add(const T& data); + + // Add data (move) + void add(T&& data); + + // Add data + void combine(AverageData&& other); + + // Clear all stored data + void clear(); + + // Divide accum by counts to convert to the normalized mean + void normalize(); + + // Multiply accum by counts to convert to the un-normalized mean + void denormalize(); + +protected: + // Number of datum that have been accumulated + size_t count_ = 0; + + // Flag for whether the accumulated data has been divided + // by the count + bool normalized_ = false; +}; + +//------------------------------------------------------------------------------ +// Implementation +//------------------------------------------------------------------------------ + +template +void AverageData::add(const T& data) { + denormalize(); + Base::add(data); + count_ += 1; +} + +template +void AverageData::add(T&& data) { + denormalize(); + Base::add(std::move(data)); + count_ += 1; +} + +template +void AverageData::combine(AverageData&& other) { + denormalize(); + other.denormalize(); + Base::combine(std::move(other)); + count_ += other.count_; +} + +template +void AverageData::clear() { + Base::clear(); + count_ = 0; + normalized_ = false; +} + +template +void AverageData::normalize() { + if (normalized_) + return; + Linalg::idiv(Base::data_, double(count_)); + normalized_ = true; +} + +template +void AverageData::denormalize() { + if (!normalized_) + return; + Linalg::imul(Base::data_, double(count_)); + normalized_ = false; +} + +template +T& AverageData::value() { + normalize(); + return Base::data_; +} + +//------------------------------------------------------------------------------ +} // end namespace AER +//------------------------------------------------------------------------------ +#endif diff --git a/src/framework/results/data/subtypes/data_map.hpp b/src/framework/results/data/subtypes/data_map.hpp new file mode 100755 index 0000000000..c64e8b610b --- /dev/null +++ b/src/framework/results/data/subtypes/data_map.hpp @@ -0,0 +1,220 @@ +/** + * This code is part of Qiskit. + * + * (C) Copyright IBM 2020. + * + * 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. + */ + +#ifndef _aer_framework_results_data_map_hpp_ +#define _aer_framework_results_data_map_hpp_ + +#include "framework/json.hpp" +#include "framework/types.hpp" + +namespace AER { + +// Recursive nested data template class +template