Source code for qlauncher.base.base

  1from abc import ABC, abstractmethod
  2from dataclasses import dataclass
  3import pickle
  4from typing import Any, Literal, TypeVar
  5from collections.abc import Callable
  6import logging
  7
  8
  9AVAILABLE_FORMATS = Literal['hamiltonian', 'qubo', 'bqm', 'none', 'fn', 'tabular_ml']
 10
 11
[docs] 12@dataclass 13class Result: 14 best_bitstring: str 15 best_energy: float 16 most_common_bitstring: str 17 most_common_bitstring_energy: float 18 distribution: dict 19 energies: dict 20 num_of_samples: int 21 average_energy: float 22 energy_std: float 23 result: Any 24 25 def __str__(self): 26 return f"Result(bitstring={self.best_bitstring}, energy={self.best_energy})" 27 28 def __repr__(self): 29 return str(self) 30
[docs] 31 def best(self): 32 return self.best_bitstring, self.best_energy
33
[docs] 34 def most_common(self): 35 return self.most_common_bitstring, self.most_common_bitstring_energy
36
[docs] 37 @staticmethod 38 def from_distributions(bitstring_distribution: dict[str, float], energy_distribution: dict[str, float], result: Any = None) -> "Result": 39 """ 40 Constructs the Result object from Dictionary with bitstring to num of occurrences, 41 dictionary mapping bitstring to energy and optional result (rest) 42 """ 43 best_bitstring = min(energy_distribution, key=energy_distribution.get) 44 best_energy = energy_distribution[best_bitstring] 45 most_common_bitstring = max(bitstring_distribution, key=bitstring_distribution.get) 46 most_common_bitstring_energy = energy_distribution[most_common_bitstring] 47 num_of_samples = int(sum(bitstring_distribution.values())) 48 49 mean_value = sum(energy_distribution[bitstring] * occ for bitstring, occ in bitstring_distribution.items()) / num_of_samples 50 std = 0 51 for bitstring, occ in bitstring_distribution.items(): 52 std += occ * ((energy_distribution[bitstring] - mean_value)**2) 53 std = (std/(num_of_samples-1))**0.5 54 return Result( 55 best_bitstring, 56 best_energy, 57 most_common_bitstring, 58 most_common_bitstring_energy, 59 bitstring_distribution, 60 energy_distribution, 61 num_of_samples, 62 mean_value, 63 std, 64 result 65 )
66 67
[docs] 68class Backend: 69 """ 70 Abstract class representing a backend for quantum computing. 71 72 Attributes: 73 name (str): The name of the backend. 74 path (str | None): The path to the backend (optional). 75 parameters (list): A list of parameters for the backend (optional). 76 77 """ 78 79 def __init__(self, name: str, parameters: list | None = None) -> None: 80 self.name: str = name 81 self.is_device = name == 'device' 82 self.path: str | None = None 83 self.parameters = parameters if parameters is not None else [] 84 self.logger: logging.Logger | None = None 85
[docs] 86 def set_logger(self, logger: logging.Logger): 87 self.logger = logger
88 89 def _get_path(self): 90 return f'{self.name}'
91 92
[docs] 93class Problem(ABC): 94 """ 95 Abstract class for defining Problems. 96 97 Attributes: 98 variant (str): The variant of the problem. The default variant is "Optimization". 99 path (str | None): The path to the problem. 100 name (str): The name of the problem. 101 instance_name (str): The name of the instance. 102 instance (any): An instance of the problem. 103 104 """ 105 106 _problem_id = None 107 108 def __init__(self, instance: Any, instance_name: str = 'unnamed') -> None: 109 """ 110 Initializes a Problem instance. 111 112 Params: 113 instance (any): An instance of the problem. 114 instance_name (str | None): The name of the instance. 115 116 Returns: 117 None 118 """ 119 self.instance: Any = instance 120 self.instance_name = instance_name 121 self.variant: str = 'Optimization' 122 self.path: str | None = None 123 self.name = self.__class__.__name__.lower() 124
[docs] 125 @classmethod 126 def from_file(cls: type['Problem'], path: str) -> 'Problem': 127 with open(path, 'rb') as f: 128 instance = pickle.load(f) 129 return cls(instance)
130
[docs] 131 @staticmethod 132 def from_preset(instance_name: str, **kwargs): 133 raise NotImplementedError()
134 135 def __init_subclass__(cls) -> None: 136 if Problem not in cls.__bases__: 137 return 138 cls._problem_id = cls 139
[docs] 140 def read_result(self, exp, log_path): 141 """ 142 Reads a result from a file. 143 144 Args: 145 exp: The experiment. 146 log_path: The path to the log file. 147 148 Returns: 149 The result. 150 """ 151 exp += exp # ?: this is perplexing 152 with open(log_path, 'rb') as file: 153 res = pickle.load(file) 154 return res
155
[docs] 156 def analyze_result(self, result) -> Any: 157 """ 158 Analyzes the result. 159 160 Args: 161 result: The result. 162 163 """ 164 raise NotImplementedError()
165 166
[docs] 167class Algorithm(ABC): 168 """ 169 Abstract class for Algorithms. 170 171 Attributes: 172 name (str): The name of the algorithm, derived from the class name in lowercase. 173 path (str | None): The path to the algorithm, if applicable. 174 parameters (list): A list of parameters for the algorithm. 175 alg_kwargs (dict): Additional keyword arguments for the algorithm. 176 177 Abstract methods: 178 __init__(self, **alg_kwargs): Initializes the Algorithm object. 179 _get_path(self) -> str: Returns the common path for the algorithm. 180 run(self, problem: Problem, backend: Backend): Runs the algorithm on a specific problem using a backend. 181 """ 182 _algorithm_format: AVAILABLE_FORMATS = 'none' 183 184 def __init__(self, **alg_kwargs) -> None: 185 self.name: str = self.__class__.__name__.lower() 186 self.path: str | None = None 187 self.parameters: list = [] 188 self.alg_kwargs = alg_kwargs 189
[docs] 190 def parse_result_to_json(self, o: object) -> dict: 191 """Parses results so that they can be saved as a JSON file. 192 193 Args: 194 o (object): The result object to be parsed. 195 196 Returns: 197 dict: The parsed result as a dictionary. 198 """ 199 print('Algorithm does not have the parse_result_to_json method implemented') 200 return o.__dict__
201
[docs] 202 @abstractmethod 203 def run(self, problem: Problem, backend: Backend, formatter: Callable) -> Result: 204 """Runs the algorithm on a specific problem using a backend. 205 206 Args: 207 problem (Problem): The problem to be solved. 208 backend (Backend): The backend to be used for execution. 209 """