1""" File with templates """
2import json
3import pickle
4from typing import List, Literal, Optional, Union, Callable
5from quantum_launcher.base.adapter_structure import get_formatter, ProblemFormatter
6from quantum_launcher.base import Problem, Algorithm, Backend, Result
7from quantum_launcher.problems import Raw
8import logging
9
10
[docs]
11class QuantumLauncher:
12 """
13 Quantum Launcher class.
14
15 Quantum launcher is used to run quantum algorithms on specific problem instances and backends.
16 It provides methods for binding parameters, preparing the problem, running the algorithm, and processing the results.
17
18 Attributes:
19 problem (Problem): The problem instance to be solved.
20 algorithm (Algorithm): The quantum algorithm to be executed.
21 backend (Backend, optional): The backend to be used for execution. Defaults to None.
22 path (str): The path to save the results. Defaults to 'results/'.
23 binding_params (dict or None): The parameters to be bound to the problem and algorithm. Defaults to None.
24 encoding_type (type): The encoding type to be used changing the class of the problem. Defaults to None.
25
26 Example of usage::
27
28 from templates import QuantumLauncher
29 from problems import MaxCut
30 from qiskit_routines import QAOA, QiskitBackend
31
32 problem = MaxCut(instance_name='default')
33 algorithm = QAOA()
34 backend = QiskitBackend('local_simulator')
35
36 launcher = QuantumLauncher(problem, algorithm, backend)
37 result = launcher.process(save_pickle=True)
38 print(result)
39
40 """
41
42 def __init__(self, problem: Problem, algorithm: Algorithm, backend: Backend = None,
43 logger: Optional[logging.Logger] = None) -> None:
44
45 if not isinstance(problem, Problem):
46 problem = Raw(problem)
47
48 self.problem: Problem = problem
49 self.algorithm: Algorithm = algorithm
50 self.backend: Backend = backend
51
52 if logger is None:
53 logger: logging.Logger = logging.getLogger('QuantumLauncher')
54 self.logger = logger
55
56 # logging.info(f'Found proper formatter, with formatter structure: {self.formatter.get_pipeline()}')
57
58 self.res: dict = {}
59
[docs]
60 def run(self, **kwargs) -> Result:
61 """
62 Finds proper formatter, and runs the algorithm on the problem with given backends.
63
64 Returns:
65 dict: The results of the algorithm execution.
66 """
67
68 formatter: ProblemFormatter = get_formatter(self.problem._problem_id, self.algorithm._algorithm_format)
69 formatter.set_run_params(kwargs)
70
71 self.result = self.algorithm.run(self.problem, self.backend, formatter=formatter)
72 logging.info('Algorithm ended successfully!')
73 return self.result
74
[docs]
75 def save(self, path: str, format: Literal['pickle', 'txt', 'json'] = 'pickle'):
76 logging.info(f'Saving results to file: {path}')
77 if format == 'pickle':
78 with open(path, mode='wb') as f:
79 pickle.dump(self.result, f)
80 elif format == 'json':
81 with open(path, mode='w', encoding='utf-8') as f:
82 json.dump(self.result.__dict__, f, default=fix_json)
83 elif format == 'txt':
84 with open(path, mode='w', encoding='utf-8') as f:
85 f.write(self.result.__str__())
86 else:
87 raise ValueError(
88 f'format: {format} in not supported try: pickle, txt, csv or json')
89
[docs]
90 def process(self, *, file_path: Optional[str] = None, format: Union[Literal['pickle', 'txt', 'json'], List[Literal['pickle', 'txt', 'json']]] = 'pickle', **kwargs) -> dict:
91 """
92 Runs the algorithm, processes the data, and saves the results if specified.
93
94 Args:
95 file_path (Optional[str]): Flag indicating whether to save the results to a file. Defaults to None.
96 format (Union[Literal['pickle', 'txt', 'json'], List[Literal['pickle', 'txt', 'json']]]): Format in which file should be saved. Defaults to 'pickle'
97
98 Returns:
99 dict: The processed results.
100 """
101 results = self.run(**kwargs)
102 energy = results.result['energy']
103 res = {}
104 res['problem_setup'] = self.problem.setup
105 res['algorithm_setup'] = self.algorithm.setup
106 res['algorithm_setup']['variant'] = self.problem.variant
107 res['backend_setup'] = self.backend.setup
108 res['results'] = results
109
110 self._file_name = self.problem.path + '-' + \
111 self.backend.path + '-' \
112 + self.algorithm.path + '-' + str(energy)
113
114 if file_path is not None and isinstance(format, str):
115 self.save(file_path, format)
116 if file_path is not None and isinstance(format, list):
117 for form in format:
118 self.save(file_path, form)
119 return res
120
121
[docs]
122def fix_json(o: object):
123 # if o.__class__.__name__ == 'SamplingVQEResult':
124 # parsed = self.algorithm.parse_samplingVQEResult(o, self._full_path)
125 # return parsed
126 if o.__class__.__name__ == 'complex128':
127 return repr(o)
128 print(
129 f'Name of object {o.__class__} not known, returning None as a json encodable')
130 return None