def setUp(self): experiment_result_data = ExperimentResultData.from_dict( {'counts': { '0x0': 42 }}) experiment_result_data_2 = ExperimentResultData.from_dict( {'counts': { '0x1': 42 }}) header_1 = Obj.from_dict({'name': 'Test1'}) header_2 = Obj.from_dict({'name': 'Test2'}) self.experiment_result_dictionary_1 = { 'name': 'Test1', 'shots': 42, 'data': experiment_result_data, 'status': 'DONE', 'success': True, 'time_taken': 0.42, 'header': header_1 } self.experiment_result_dictionary_2 = { 'name': 'Test2', 'shots': 23, 'data': experiment_result_data_2, 'status': 'DONE', 'success': True, 'time_taken': 0.12, 'header': header_2 } self.experiment_result_1 = ExperimentResult( **self.experiment_result_dictionary_1) self.experiment_result_2 = ExperimentResult( **self.experiment_result_dictionary_2)
def __convert_histogram(result: Dict[str, Any], measurements: Dict[str, Any]) -> Obj: """ The quantum inspire backend always uses full state projection. The SDK user can measure not all qubits and change the combined classical bits. This function converts the result to a histogram output that represents the probabilities measured with the classical bits. Args: result: The result output from the quantum inspire backend with full- state projection histogram output. measurements: The dictionary contains a measured qubits/classical bits map (list) and the number of classical bits (int). Returns: The resulting full state histogram with probabilities. """ output_histogram_probabilities: Dict[str, float] = defaultdict(lambda: 0) number_of_qubits = result['number_of_qubits'] state_probability: Dict[str, float] = result['histogram'] for qubit_register, probability in state_probability.items(): classical_state_hex = QuantumInspireBackend.__qubit_to_classical_hex( qubit_register, measurements, number_of_qubits) output_histogram_probabilities[classical_state_hex] += probability sorted_histogram_probabilities: List[Tuple[str, float]] = sorted( output_histogram_probabilities.items(), key=lambda kv: int(kv[0], 16)) full_state_histogram_obj = OrderedDict(sorted_histogram_probabilities) return Obj.from_dict(full_state_histogram_obj)
def get_experiment_results(self, qi_job: QIJob) -> List[ExperimentResult]: """ Get results from experiments from the Quantum-inspire platform. Args: qi_job: A job that has already been submitted and which execution is completed. Raises: QisKitBackendError: If an error occurred during execution by the backend. Returns: A list of experiment results; containing the data, execution time, status, etc. """ jobs = self.__api.get_jobs_from_project(int(qi_job.job_id())) results = [self.__api.get_result_from_job(job['id']) for job in jobs] experiment_results = [] for result, job in zip(results, jobs): if not result.get('histogram', {}): raise QisKitBackendError( 'Result from backend contains no histogram data!\n{}'.format(result.get('raw_text'))) user_data = json.loads(str(job.get('user_data'))) measurements = user_data.pop('measurements') histogram_obj, memory_data = self.__convert_result_data(result, measurements) full_state_histogram_obj = self.__convert_histogram(result, measurements) experiment_result_data = ExperimentResultData(counts=histogram_obj, probabilities=full_state_histogram_obj, memory=memory_data) header = Obj.from_dict(user_data) experiment_result_dictionary = {'name': job.get('name'), 'seed': 42, 'shots': job.get('number_of_shots'), 'data': experiment_result_data, 'status': 'DONE', 'success': True, 'time_taken': result.get('execution_time_in_seconds'), 'header': header} experiment_results.append(ExperimentResult(**experiment_result_dictionary)) return experiment_results
def __convert_result_data( self, result: Dict[str, Any], measurements: Dict[str, Any]) -> Tuple[Obj, List[str]]: """ The quantum inspire backend returns the single shot values as raw data. This function converts this list of single shot values to hexadecimal memory data according the Qiskit spec. From this memory data the counts histogram is constructed by counting the single shot values. Note: When shots = 1, the backend returns an empty list as raw_data. This is a special case. In this case the resulting memory data consists of 1 value and the count histogram consists of 1 instance of this value. To determine this value a random float is generated in the range [0, 1). With this random number the value from this probabilities histogram is taken where the added probabilities is greater this random number. Example: probability histogram is {[0x0, 0.2], [0x3, 0.4], [0x5, 0.1], [0x6, 0.3]}. When random is in the range [0, 0.2) the first value of the probability histogram is taken (0x0). When random is in the range [0.2, 0.6) the second value of the probability histogram is taken (0x3). When random is in the range [0.6, 0.7) the third value of the probability histogram is taken (0x5). When random is in the range [0.7, 1) the last value of the probability histogram is taken (0x6). Args: result: The result output from the quantum inspire backend with full- state projection histogram output. measurements: The dictionary contains a measured qubits/classical bits map (list) and the number of classical bits (int). Returns: The result consists of two formats for the result. The first result is the histogram with count data, the second result is a list with converted hexadecimal memory values for each shot. """ memory_data = [] histogram_data: Dict[str, int] = defaultdict(lambda: 0) number_of_qubits: int = result['number_of_qubits'] raw_data = self.__api.get_raw_data_from_result(result['id']) if raw_data: for raw_qubit_register in raw_data: classical_state_hex = QuantumInspireBackend.__qubit_to_classical_hex( str(raw_qubit_register), measurements, number_of_qubits) memory_data.append(classical_state_hex) histogram_data = { elem: count for elem, count in Counter(memory_data).items() } else: state_probabilities = result['histogram'] random_probability = np.random.rand() sum_probability = 0.0 for qubit_register, probability in state_probabilities.items(): sum_probability += probability if random_probability < sum_probability: classical_state_hex = QuantumInspireBackend.__qubit_to_classical_hex( qubit_register, measurements, number_of_qubits) memory_data.append(classical_state_hex) histogram_data[classical_state_hex] = 1 break sorted_histogram_data: List[Tuple[str, int]] = sorted( histogram_data.items(), key=lambda kv: int(kv[0], 16)) histogram_obj = OrderedDict(sorted_histogram_data) return Obj.from_dict(histogram_obj), memory_data
def _generate_experiment_result(qlm_result, head): """ Generates a Qiskit experiment result. Args: qlm_result: qat.core.wrappers.Result object which data is aggregated head: Header of the experiment Returns: An ExperimentResult structure. """ samples = [hex(s.state.state) for s in qlm_result.raw_data] counts = dict(Counter(samples)) data = ExperimentResultData.from_dict({"counts": counts}) return ExperimentResult( shots=len(qlm_result.raw_data), success=True, data=data, header=Obj.from_dict(head), )
def apply(self, raw_data: Result) -> Result: """ Create a new result from the raw_data by converting level 1 data to level 2 data. Args: raw_data: list of qiskit.Result or qiskit.Result. Returns: A list of qiskit.Result or qiskit.Result. """ new_results = deepcopy(raw_data) to_be_discriminated = [] # Extract all the meas level 1 data from the Result. shots_per_experiment_result = [] for result in new_results.results: if result.meas_level == 1: shots_per_experiment_result.append(result.shots) to_be_discriminated.append(result) new_results.results = to_be_discriminated x_data = self.discriminator.get_xdata(new_results, 2) y_data = self.discriminator.discriminate(x_data) start = 0 for idx, n_shots in enumerate(shots_per_experiment_result): memory = y_data[start:(start + n_shots)] counts = Obj.from_dict(self.count(memory)) new_results.results[idx].data = ExperimentResultData(counts=counts, memory=memory) start += n_shots for result in new_results.results: result.meas_level = 2 return new_results