Source code for eqc_direct.utils
- """
- Utilities for running server sim and client
- """
- from dataclasses import dataclass
- from typing import List, Tuple, TypedDict
- import numpy as np
- PREC_MIN_RECOMMENDED_LEVELS = 200
- PREC_MAX_LEVELS = 10000
- [docs]
- class SystemInfoOptional(TypedDict, total=False):
- """Python binding to SystemInfo->VersionOutput proto spec optional fields."""
- device_id: str
- [docs]
- class SystemInfo(SystemInfoOptional):
- """Python binding to SystemInfo->VersionOutput proto spec."""
- server_version: str
- device_type: str
- [docs]
- @dataclass
- class SysStatus:
- """
- Status codes for system paired with their descriptions.
- """
- IDLE = {"status_code": 0, "status_desc": "IDLE"}
- JOB_RUNNING = {"status_code": 1, "status_desc": "JOB_RUNNING"}
- CALIBRATION = {"status_code": 2, "status_desc": "CALIBRATION"}
- HEALTH_CHECK = {"status_code": 3, "status_desc": "HEALTH_CHECK"}
- HARDWARE_FAILURE = {"status_code": [4, 5], "status_desc": "HARDWARE_FAILURE"}
- [docs]
- @dataclass
- class LockCheckStatus:
- """
- Statuses codes for checking lock status paired with their descriptions
- """
- AVAILABLE = {"status_code": 0, "status_desc": "Lock available"}
- USER_LOCKED = {
- "status_code": 1,
- "status_desc": "lock_id matches current server lock_id",
- }
- UNAVAILABLE = {
- "status_code": 2,
- "status_desc": "Execution lock is in use by another user",
- }
- [docs]
- @dataclass
- class LockManageStatus:
- """
- Statuses and descriptions for acquiring and releasing lock
- """
- SUCCESS = {"status_code": 0, "status_desc": "Success"}
- MISMATCH = {
- "status_code": 1,
- "status_desc": "lock_id does not match current device lock_id",
- }
- BUSY = {
- "status_code": 2,
- "status_desc": "Lock currently in use unable to perform operation",
- }
- [docs]
- @dataclass
- class JobCodes:
- """
- Job codes for errors paired with their descriptions
- """
- NORMAL = {"err_code": 0, "err_desc": "Success"}
- INDEX_OUT_OF_RANGE = {
- "err_code": 1,
- "err_desc": (
- "Index in submitted data is out of range for specified "
- "number of variables"
- ),
- }
- COEF_INDEX_MISMATCH = {
- "err_code": 2,
- "err_desc": (
- "Polynomial indices do not match required length for "
- "specified coefficient length"
- ),
- }
- DEVICE_BUSY = {
- "err_code": 3,
- "err_desc": "Device currently processing other request",
- }
- LOCK_MISMATCH = {
- "err_code": 4,
- "err_desc": "lock_id doesn't match current device lock",
- }
- HARDWARE_FAILURE = {
- "err_code": 5,
- "err_desc": "Device failed during execution",
- }
- INVALID_SUM_CONSTRAINT = {
- "err_code": 6,
- "err_desc": (
- "Sum constraint must be greater than or equal to 1 and "
- "less than or equal to 10000"
- ),
- }
- INVALID_RELAXATION_SCHEDULE = {
- "err_code": 7,
- "err_desc": "Parameter relaxation_schedule must be in set {1,2,3,4}",
- }
- USER_INTERRUPT = {
- "err_code": 8,
- "err_desc": "User sent stop signal before result was returned",
- }
- EXCEEDS_MAX_SIZE = {
- "err_code": 9,
- "err_desc": "Exceeds max problem size for device",
- }
- DECREASING_INDEX = {
- "err_code": 10,
- "err_desc": (
- "One of specified polynomial indices is not specified in "
- "non-decreasing order"
- ),
- }
- INVALID_PRECISION = {
- "err_code": 11,
- "err_desc": "The input precision exceeds maximum allowed precision for device",
- }
- NUM_SAMPLES_POSITIVE = {
- "err_code": 12,
- "err_desc": "Input num_samples must be positive.",
- }
- PRECISION_CONSTRAINT_MISMATCH = {
- "err_code": 13,
- "err_desc": "Sum constraint must be divisible by solution_precision",
- }
- PRECISION_NONNEGATIVE = {
- "err_code": 14,
- "err_desc": "Input solution precision cannot be negative",
- }
- DEGREE_POSITIVE = {
- "err_code": 15,
- "err_desc": "Input degree must be greater than 0",
- }
- NUM_VARIABLES_POSITIVE = {
- "err_code": 16,
- "err_desc": "Input num_variables must be greater than 0",
- }
- NUM_LEVELS_NUM_VARS_MISMATCH = {
- "err_code": 17,
- "err_desc": "Length of `num_levels` input must be equal to num_variables",
- }
- NUM_LEVELS_GT_ONE = {
- "err_code": 18,
- "err_desc": "All elements of input `num_levels` must be greater than 1",
- }
- TOTAL_INTEGER_LEVELS = {
- "err_code": 19,
- "err_desc": "Total number of integer levels from input variables exceeds limit",
- }
- INVALID_MEAN_PHOTON_NUMBER = {
- "err_code": 20,
- "err_desc": "Mean photon number if specified must be in range [0.0000667, 0.0066666]",
- }
- INVALID_QUANTUM_FLUCTUATION_COEFFICIENT = {
- "err_code": 21,
- "err_desc": "Quantum fluctuation coefficient if specified must be in range [1, 100]",
- }
- [docs]
- def message_to_dict(grpc_message) -> dict:
- """Convert a gRPC message to a dictionary."""
- result = {}
- for descriptor in grpc_message.DESCRIPTOR.fields:
- field = getattr(grpc_message, descriptor.name)
- if descriptor.type == descriptor.TYPE_MESSAGE:
-
- if descriptor.label == descriptor.LABEL_REPEATED:
- if descriptor.message_type and any(
- subfield.label == subfield.LABEL_REPEATED
- for subfield in descriptor.message_type.fields
- ):
-
- result[descriptor.name] = (
- [list(item.values) for item in field] if field else []
- )
- else:
-
- result[descriptor.name] = (
- [message_to_dict(item) for item in field] if field else []
- )
- else:
-
- result[descriptor.name] = message_to_dict(field) if field else {}
- else:
-
- if descriptor.label == descriptor.LABEL_REPEATED:
- result[descriptor.name] = list(field) if field else []
- else:
- result[descriptor.name] = field
- return result
- [docs]
- def get_decimal_places(float_num: float) -> int:
- """
- Helper function which gets the number of decimal places for a float,
- excluding trailing zeros.
- :param float_num: float input for which decimal places will be found
- :return: a non-negative integer representing the number of decimal places
- """
- try:
-
- _, fractional_part = str(float_num).split(".")
-
- fractional_part = fractional_part.rstrip("0")
- decimal_places = len(fractional_part)
- except ValueError:
-
- decimal_places = 0
- return decimal_places