Source code for quantumthreattracker.lifespan_estimator.hardware_roadmap

"""Class for hardware roadmaps."""

import json
from pathlib import Path
from typing import Self

from qsharp.estimator import EstimatorParams


[docs] class HardwareRoadmap: """Class for representing quantum computing hardware roadmaps.""" def __init__(self, hardware_roadmap: list | None = None): if hardware_roadmap is None: self._hardware_roadmap = [] else: self._hardware_roadmap = hardware_roadmap
[docs] def as_list(self) -> list: """Get the hardware roadmap as a list. Returns ------- list Hardware roadmap. """ return self._hardware_roadmap
[docs] @classmethod def from_file(cls, file_path: str) -> Self: """Import a hardware roadmap from a file. Parameters ---------- file_path : str File path. Returns ------- Self Hardware roadmap. """ with open(file_path, "rb") as file: return cls(json.load(file))
[docs] def add( self, timestamp: int, estimator_params: EstimatorParams | dict | list, ) -> None: """Add a quantum computer to the hardware roadmap. Parameters ---------- timestamp : int Unix timestamp. estimator_params : EstimatorParams | dict | list Parameters characterising the quantum computer. Raises ------ TypeError If the estimator parameters are not given as an EstimatorParams instance or a dictionary. """ if isinstance(estimator_params, list): estimator_params_list = estimator_params else: estimator_params_list = [estimator_params] for estimator_params_entry in estimator_params_list: if isinstance(estimator_params_entry, EstimatorParams): estimator_params_dict = estimator_params_entry.as_dict() elif isinstance(estimator_params_entry, dict): estimator_params_dict = estimator_params_entry else: raise TypeError( f"{type(estimator_params_entry)} is the wrong type for estimator parameters. " + "It must be given as either an EstimatorParams instance or a dictionary." ) new_milestone = { "timestamp": timestamp, "hardwareList": [{"estimatorParams": estimator_params_dict}], } # This slightly messy chunk of code is for adding the new quantum computer # to the existing hardware roadmap as a new entry in the list, or combining # it with an existing entry if another entry with the same timestamp already # exists. inserted = False for index in range(len(self._hardware_roadmap)): if timestamp < self._hardware_roadmap[index]["timestamp"]: self._hardware_roadmap.insert(index, new_milestone) inserted = True break if timestamp == self._hardware_roadmap[index]["timestamp"]: self._hardware_roadmap[index]["hardwareList"].append( new_milestone["hardwareList"][0] ) inserted = True break if not inserted: self._hardware_roadmap.append(new_milestone)
[docs] def remove(self, timestamp: int, qc_index: int | None = None) -> None: """Remove an entry from the hardware roadmap. Parameters ---------- timestamp : int Unix timestamp. qc_index : int, optional Index for removing a specific quantum computer for a given timestamp. If unspecified, all entries with the specified timestamp will be removed. """ for milestone_index in range(len(self._hardware_roadmap)): if self._hardware_roadmap[milestone_index]["timestamp"] == timestamp: if qc_index is None: self._hardware_roadmap.pop(milestone_index) else: self._hardware_roadmap[milestone_index]["hardwareList"].pop( qc_index ) if ( len(self._hardware_roadmap[milestone_index]["hardwareList"]) == 0 ): self._hardware_roadmap.pop(milestone_index) return
[docs] def save_roadmap(self, file_name: str, file_path: Path | None = None) -> None: """Save the hardware roadmap as a JSON file. Parameters ---------- file_name : str File name. file_path : str, optional File path. If unspecified, the file will be saved to the current working directory. Raises ------ AttributeError If the hardware roadmap has not yet been generated. """ if file_path is None: file_path = str(Path.cwd()) try: with Path.open(file_path + "/" + file_name + ".json", "w") as fp: json.dump(self._hardware_roadmap, fp, indent=4) except AttributeError: raise AttributeError( "The hardware roadmap has not been generated and thus cannot be saved." )