def test_get_experiment_results_raises_simulation_error_when_no_histogram(
         self):
     api = Mock()
     api.get_jobs_from_project.return_value = [{'id': 42, 'results': '{}'}]
     api.get_result_from_job.return_value = {
         'histogram': [],
         'raw_text': 'Error'
     }
     job = Mock()
     job.job_id.return_value = '42'
     simulator = QuantumInspireBackend(api, Mock())
     with self.assertRaises(QiskitBackendError) as error:
         simulator.get_experiment_results_from_all_jobs(job)
     self.assertEqual(
         ('Result from backend contains no histogram data!\nError', ),
         error.exception.args)
    def test_get_experiment_results_multiple_single_shots(self):
        one_shot_results = {'0x0': 0, '0x1': 0, '0x2': 0, '0x3': 0}
        np.random.seed(2019)
        for i in range(10000):
            number_of_shots = 1
            self._basic_job_dictionary['number_of_shots'] = number_of_shots

            qc = QuantumCircuit(2, 2)
            qc.h(0)
            qc.cx(0, 1)
            qc.measure(1, 1)
            qc.measure(0, 0)

            experiment = self._circuit_to_experiment(qc)
            api = Mock()
            api.get_result_from_job.return_value = {
                'id':
                1,
                'histogram': {
                    '0': 0.2,
                    '1': 0.3,
                    '2': 0.4,
                    '3': 0.1
                },
                'execution_time_in_seconds':
                2.1,
                'number_of_qubits':
                2,
                'raw_data_url':
                'http://saevar-qutech-nginx/api/results/24/raw-data/'
            }
            api.get_raw_data_from_result.return_value = []
            jobs = self._basic_job_dictionary
            measurements = QuantumInspireBackend._collect_measurements(
                experiment)
            user_data = {
                'name': 'name',
                'memory_slots': 2,
                'creg_sizes': [['c1', 2]],
                'measurements': measurements
            }
            jobs['user_data'] = json.dumps(user_data)
            api.get_jobs_from_project.return_value = [jobs]
            job = QIJob('backend', '42', api)
            simulator = QuantumInspireBackend(api, Mock())
            experiment_result = simulator.get_experiment_results_from_all_jobs(
                job)[0]
            # Exactly one value in memory
            self.assertEqual(len(experiment_result.data.memory), 1)
            # The only value in memory is the same as the value in the counts histogram.
            self.assertEqual(
                list(experiment_result.data.counts.keys())[0],
                experiment_result.data.memory[0])
            one_shot_results[experiment_result.data.memory[0]] += 1

        self.assertEqual(one_shot_results['0x0'], 2066)
        self.assertEqual(one_shot_results['0x1'], 2947)
        self.assertEqual(one_shot_results['0x2'], 4003)
        self.assertEqual(one_shot_results['0x3'], 984)
    def test_get_experiment_results_returns_single_shot(self):
        number_of_shots = 1
        self._basic_job_dictionary['number_of_shots'] = number_of_shots

        qc = QuantumCircuit(2, 2)
        qc.h(0)
        qc.cx(0, 1)
        qc.measure(1, 1)
        qc.measure(0, 0)

        experiment = self._circuit_to_experiment(qc)

        api = Mock()
        api.get_result_from_job.return_value = {
            'id': 1,
            'histogram': {
                '0': 0.5,
                '3': 0.5
            },
            'execution_time_in_seconds': 2.1,
            'number_of_qubits': 2,
            'raw_data_url':
            'http://saevar-qutech-nginx/api/results/24/raw-data/'
        }
        api.get_raw_data_from_result.return_value = []
        api.get_backend_type_by_name.return_value = {
            'max_number_of_shots': 4096
        }
        jobs = self._basic_job_dictionary
        measurements = QuantumInspireBackend._collect_measurements(experiment)
        user_data = {
            'name': 'name',
            'memory_slots': 2,
            'creg_sizes': [['c1', 2]],
            'measurements': measurements
        }
        jobs['user_data'] = json.dumps(user_data)
        api.get_jobs_from_project.return_value = [jobs]
        job = QIJob('backend', '42', api)
        simulator = QuantumInspireBackend(api, Mock())
        experiment_result = simulator.get_experiment_results_from_all_jobs(
            job)[0]
        self.assertEqual(experiment_result.data.probabilities['0x0'], 0.5)
        self.assertEqual(experiment_result.data.probabilities['0x3'], 0.5)
        self.assertTrue(hasattr(experiment_result.data, 'memory'))
        # Exactly one value in counts histogram
        self.assertEqual(len(experiment_result.data.counts), 1)
        # The single value in counts histogram has count 1
        self.assertEqual(list(experiment_result.data.counts.values())[0], 1)
        # Exactly one value in memory
        self.assertEqual(len(experiment_result.data.memory), 1)
        # The only value in memory is the same as the value in the counts histogram.
        self.assertEqual(
            list(experiment_result.data.counts.keys())[0],
            experiment_result.data.memory[0])
        self.assertEqual(experiment_result.name, 'circuit0')
        self.assertEqual(experiment_result.shots, number_of_shots)
    def test_get_experiment_results_returns_correct_value_from_project(self):
        qc = QuantumCircuit(2, 2)
        qc.h(0)
        qc.cx(0, 1)
        qc.measure(1, 1)
        qc.measure(0, 0)

        number_of_shots = 100
        experiment = self._circuit_to_experiment(qc)
        api = Mock()
        api.get_result_from_job.return_value = {
            'id': 1,
            'histogram': {
                '1': 0.6,
                '3': 0.4
            },
            'execution_time_in_seconds': 2.1,
            'number_of_qubits': 2,
            'raw_data_url':
            'http://saevar-qutech-nginx/api/results/24/raw-data/'
        }
        api.get_raw_data_from_result.return_value = [1] * 60 + [3] * 40
        jobs = self._basic_job_dictionary
        measurements = QuantumInspireBackend._collect_measurements(experiment)
        user_data = {
            'name': 'name',
            'memory_slots': 2,
            'creg_sizes': [['c1', 2]],
            'measurements': measurements
        }
        jobs['user_data'] = json.dumps(user_data)
        api.get_jobs_from_project.return_value = [jobs]
        job = QIJob('backend', '42', api)
        simulator = QuantumInspireBackend(api, Mock())
        experiment_result = simulator.get_experiment_results_from_all_jobs(
            job)[0]
        self.assertEqual(experiment_result.data.counts['0x1'], 60)
        self.assertEqual(experiment_result.data.counts['0x3'], 40)
        self.assertEqual(experiment_result.data.probabilities['0x1'], 0.6)
        self.assertEqual(experiment_result.data.probabilities['0x3'], 0.4)
        self.assertEqual(len(experiment_result.data.memory), 100)
        self.assertEqual(experiment_result.data.memory.count('0x1'), 60)
        self.assertEqual(experiment_result.data.memory.count('0x3'), 40)
        self.assertEqual(experiment_result.name, 'circuit0')
        self.assertEqual(experiment_result.shots, number_of_shots)
class TestQiSimulatorPyHistogram(unittest.TestCase):
    def setUp(self):
        self.mock_api = ApiMock(spec=QuantumInspireAPI)
        self.mock_provider = Mock(spec=QuantumInspireProvider)
        self.simulator = QuantumInspireBackend(self.mock_api,
                                               self.mock_provider)
        self._basic_job_dictionary = dict([
            ('url', 'http://saevar-qutech-nginx/api/jobs/24/'),
            ('name', 'BLA_BLU'), ('id', 24), ('status', 'COMPLETE'),
            ('input', 'http://saevar-qutech-nginx/api/assets/26/'),
            ('backend', 'http://saevar-qutech-nginx/api/backends/1/'),
            ('backend_type', 'http://saevar-qutech-nginx/api/backendtypes/1/'),
            ('results', 'http://saevar-qutech-nginx/api/jobs/24/result/'),
            ('queued_at', '2018-12-07T09:11:45.976617Z'),
            ('number_of_shots', 1000), ('full_state_projection', True),
            ('user_data', '')
        ])

    def run_histogram_test(self, single_experiment, mock_result1, mock_result2,
                           expected_histogram, expected_histogram_prob,
                           expected_memory):
        self.mock_api.set(mock_result1, mock_result2)
        jobs = self._basic_job_dictionary
        measurements = QuantumInspireBackend._collect_measurements(
            QasmQobjExperiment.from_dict(single_experiment))
        user_data = {
            'name': 'name',
            'memory_slots': 2,
            'creg_sizes': [['c1', 2]],
            'measurements': measurements
        }
        jobs['user_data'] = json.dumps(user_data)
        self.mock_api.get_jobs_from_project.return_value = [jobs]
        job = QIJob('backend', '42', self.mock_api)

        result = self.simulator.get_experiment_results_from_all_jobs(job)
        number_of_shots = jobs['number_of_shots']
        self.assertEqual(1, len(result))
        first_experiment = first_item(result)
        actual = first_experiment.data.counts
        self.assertDictEqual(expected_histogram, actual)
        probabilities = first_experiment.data.probabilities
        self.assertTrue(
            len(expected_histogram_prob.keys() - probabilities.keys()) == 0)
        for key in set(probabilities.keys()) & set(
                expected_histogram_prob.keys()):
            self.assertTrue(
                np.isclose(expected_histogram_prob[key], probabilities[key]))
        self.assertTrue(len(first_experiment.data.memory) == number_of_shots)
        self.assertListEqual(expected_memory, first_experiment.data.memory)

    @staticmethod
    def _instructions_to_experiment(instructions, memory_slots=2):
        experiment_dictionary = {
            'instructions': instructions,
            'header': {
                'n_qubits': 2,
                'memory_slots': memory_slots,
                'name': 'test_circuit',
                'qubit_labels': [['q0', 0], ['q0', 1]],
                'clbit_labels': [['c0', 0], ['c1', 1]]
            }
        }
        return experiment_dictionary

    def test_convert_histogram_normal_measurement(self):
        self.run_histogram_test(
            single_experiment=self._instructions_to_experiment([{
                'name': 'h',
                'qubits': [0]
            }, {
                'name':
                'cx',
                'qubits': [0, 1]
            }, {
                'name': 'measure',
                'qubits': [0],
                'memory': [0]
            }, {
                'name': 'measure',
                'qubits': [1],
                'memory': [1]
            }]),
            mock_result1={
                'id':
                1,
                'histogram': {
                    '0': 0.1,
                    '1': 0.2,
                    '2': 0.3,
                    '3': 0.4
                },
                'execution_time_in_seconds':
                2.1,
                'number_of_qubits':
                2,
                'raw_data_url':
                'http://saevar-qutech-nginx/api/results/24/raw-data/'
            },
            mock_result2=[0] * 100 + [1] * 200 + [2] * 300 + [3] * 400,
            expected_histogram={
                '0x0': 100,
                '0x1': 200,
                '0x2': 300,
                '0x3': 400
            },
            expected_histogram_prob={
                '0x0': 0.1,
                '0x1': 0.2,
                '0x2': 0.3,
                '0x3': 0.4
            },
            expected_memory=['0x0'] * 100 + ['0x1'] * 200 + ['0x2'] * 300 +
            ['0x3'] * 400)

    def test_classical_bits_are_displayed_correctly(self):
        self.run_histogram_test(
            single_experiment=self._instructions_to_experiment(
                [{
                    'name': 'h',
                    'qubits': [0]
                }, {
                    'name': 'cx',
                    'qubits': [0, 1]
                }, {
                    'name': 'measure',
                    'qubits': [0],
                    'memory': [0]
                }, {
                    'name': 'measure',
                    'qubits': [0],
                    'memory': [3]
                }, {
                    'name': 'measure',
                    'qubits': [1],
                    'memory': [4]
                }, {
                    'name': 'measure',
                    'qubits': [1],
                    'memory': [7]
                }],
                memory_slots=8),
            mock_result1={
                'id':
                1,
                'histogram': {
                    '0': 0.1,
                    '1': 0.2,
                    '2': 0.3,
                    '3': 0.4
                },
                'execution_time_in_seconds':
                2.1,
                'number_of_qubits':
                2,
                'raw_data_url':
                'http://saevar-qutech-nginx/api/results/24/raw-data/'
            },
            mock_result2=[0] * 100 + [1] * 200 + [2] * 300 + [3] * 400,
            expected_histogram={
                '0x0': 100,
                '0x9': 200,
                '0x90': 300,
                '0x99': 400
            },
            expected_histogram_prob={
                '0x0': 0.1,
                '0x9': 0.2,
                '0x90': 0.3,
                '0x99': 0.4
            },
            expected_memory=['0x0'] * 100 + ['0x9'] * 200 + ['0x90'] * 300 +
            ['0x99'] * 400)

    def test_convert_histogram_swapped_classical_qubits(self):
        self.run_histogram_test(
            single_experiment=self._instructions_to_experiment([{
                'name': 'h',
                'qubits': [0]
            }, {
                'name':
                'cx',
                'qubits': [0, 1]
            }, {
                'name': 'measure',
                'qubits': [0],
                'memory': [1]
            }, {
                'name': 'measure',
                'qubits': [1],
                'memory': [0]
            }]),
            mock_result1={
                'id':
                1,
                'histogram': {
                    '0': 0.1,
                    '1': 0.2,
                    '2': 0.3,
                    '3': 0.4
                },
                'execution_time_in_seconds':
                2.1,
                'number_of_qubits':
                2,
                'raw_data_url':
                'http://saevar-qutech-nginx/api/results/24/raw-data/'
            },
            mock_result2=[0] * 100 + [1] * 200 + [2] * 300 + [3] * 400,
            expected_histogram={
                '0x0': 100,
                '0x1': 300,
                '0x2': 200,
                '0x3': 400
            },
            expected_histogram_prob={
                '0x0': 0.1,
                '0x1': 0.3,
                '0x2': 0.2,
                '0x3': 0.4
            },
            expected_memory=['0x0'] * 100 + ['0x2'] * 200 + ['0x1'] * 300 +
            ['0x3'] * 400)

    def test_convert_histogram_less_measurements_qubit_one(self):
        self.run_histogram_test(
            single_experiment=self._instructions_to_experiment([{
                'name': 'h',
                'qubits': [0]
            }, {
                'name':
                'cx',
                'qubits': [0, 1]
            }, {
                'name': 'measure',
                'qubits': [0],
                'memory': [0]
            }]),
            mock_result1={
                'id':
                1,
                'histogram': {
                    '0': 0.1,
                    '1': 0.2,
                    '2': 0.3,
                    '3': 0.4
                },
                'execution_time_in_seconds':
                2.1,
                'number_of_qubits':
                2,
                'raw_data_url':
                'http://saevar-qutech-nginx/api/results/24/raw-data/'
            },
            mock_result2=[0] * 100 + [1] * 200 + [2] * 300 + [3] * 400,
            expected_histogram={
                '0x0': 400,
                '0x1': 600
            },
            expected_histogram_prob={
                '0x0': 0.4,
                '0x1': 0.6
            },
            expected_memory=['0x0'] * 100 + ['0x1'] * 200 + ['0x0'] * 300 +
            ['0x1'] * 400)

    def test_convert_histogram_less_measurements_qubit_two(self):
        self.run_histogram_test(
            single_experiment=self._instructions_to_experiment([{
                'name': 'h',
                'qubits': [0]
            }, {
                'name':
                'cx',
                'qubits': [0, 1]
            }, {
                'name': 'measure',
                'qubits': [1],
                'memory': [1]
            }]),
            mock_result1={
                'id':
                1,
                'histogram': {
                    '0': 0.1,
                    '1': 0.2,
                    '2': 0.3,
                    '3': 0.4
                },
                'execution_time_in_seconds':
                2.1,
                'number_of_qubits':
                2,
                'raw_data_url':
                'http://saevar-qutech-nginx/api/results/24/raw-data/'
            },
            mock_result2=[0] * 100 + [1] * 200 + [2] * 300 + [3] * 400,
            expected_histogram={
                '0x0': 300,
                '0x2': 700
            },
            expected_histogram_prob={
                '0x0': 0.3,
                '0x2': 0.7
            },
            expected_memory=['0x0'] * 300 + ['0x2'] * 700)

    def test_convert_histogram_classical_bits_measure_same_qubits(self):
        self.run_histogram_test(
            single_experiment={
                'instructions': [{
                    'name': 'h',
                    'qubits': [0]
                }, {
                    'name': 'cx',
                    'qubits': [0, 1]
                }, {
                    'name': 'measure',
                    'qubits': [0],
                    'memory': [0]
                }, {
                    'name': 'measure',
                    'qubits': [1],
                    'memory': [0]
                }],
                'header': {
                    'n_qubits': 2,
                    'memory_slots': 2,
                    'name': 'test',
                    'qubit_labels': [['q0', 0], ['q0', 1]],
                    'clbit_labels': [['c0', 0], ['c1', 1]]
                }
            },
            mock_result1={
                'id':
                1,
                'histogram': {
                    '0': 0.1,
                    '1': 0.2,
                    '2': 0.3,
                    '3': 0.4
                },
                'execution_time_in_seconds':
                2.1,
                'number_of_qubits':
                2,
                'raw_data_url':
                'http://saevar-qutech-nginx/api/results/24/raw-data/'
            },
            mock_result2=[0] * 100 + [1] * 200 + [2] * 300 + [3] * 400,
            expected_histogram={
                '0x0': 300,
                '0x1': 700
            },
            expected_histogram_prob={
                '0x0': 0.3,
                '0x1': 0.7
            },
            expected_memory=['0x0'] * 300 + ['0x1'] * 700)

    def test_empty_histogram(self):
        with self.assertRaises(QiskitBackendError) as error:
            self.run_histogram_test(
                single_experiment=self._instructions_to_experiment([{
                    'name':
                    'h',
                    'qubits': [0]
                }, {
                    'name':
                    'cx',
                    'qubits': [0, 1]
                }, {
                    'name':
                    'measure',
                    'qubits': [1],
                    'memory': [1]
                }]),
                mock_result1={
                    'id':
                    1,
                    'histogram': {},
                    'execution_time_in_seconds':
                    2.1,
                    'number_of_qubits':
                    2,
                    'raw_text':
                    'oopsy daisy',
                    'raw_data_url':
                    'http://saevar-qutech-nginx/api/results/24/raw-data/'
                },
                mock_result2=[],
                expected_histogram={},
                expected_histogram_prob={},
                expected_memory=[])
        self.assertEqual(
            ('Result from backend contains no histogram data!\noopsy daisy', ),
            error.exception.args)