modularize the two qubit model

This commit is contained in:
Valentin Boettcher 2022-03-18 11:25:31 +01:00
parent 0ea031837c
commit 6ecf1e7b0a
3 changed files with 165 additions and 138 deletions

79
model_base.py Normal file
View file

@ -0,0 +1,79 @@
"""A base class for model HOPS configs."""
from utility import JSONEncoder, object_hook
import numpy as np
import json
import copy
import hashlib
class Model:
"""
A base class with some data management functionality.
"""
__version__: int = 1
"""
The version of the model implementation. It is increased for
breaking changes.
"""
def __init__(self, *_, **__):
del _, __
pass
###########################################################################
# Utility #
###########################################################################
def to_json(self):
"""Returns a json representation of the model configuration."""
return json.dumps(
{key: self.__dict__[key] for key in self.__dict__ if key[0] != "_"}
| {"__version__": self.__version__},
cls=JSONEncoder,
ensure_ascii=False,
)
def __hash__(self):
return hashlib.sha256(self.to_json().encode("utf-8")).digest().__hash__()
@classmethod
def from_json(cls, json_str: str):
"""
Tries to instantiate a model config from the json string
``json_str``.
"""
model_dict = json.loads(json_str, object_hook=object_hook)
assert (
model_dict["__version__"] == cls().__version__
), "Incompatible version detected."
del model_dict["__version__"]
return cls(**model_dict)
def __eq__(self, other):
this_keys = list(self.__dict__.keys())
ignored_keys = ["_sigmas"]
for key in this_keys:
if key not in ignored_keys:
this_val, other_val = self.__dict__[key], other.__dict__[key]
same = this_val == other_val
if isinstance(this_val, np.ndarray):
same = same.all()
if not same:
return False
return self.__hash__() == other.__hash__()
def copy(self):
"""Return a deep copy of the model."""
return copy.deepcopy(self)

View file

@ -33,7 +33,7 @@ from dataclasses import dataclass, field
import functools
import itertools
from numpy.typing import NDArray
from typing import Any, Optional, SupportsFloat, Type
from typing import Any, Optional, SupportsFloat
import hops.util.bcf
import hops.util.bcf_fits
import hops.core.hierarchy_parameters as params
@ -45,30 +45,14 @@ from hops.util.truncation_schemes import (
BathMemory,
)
import stocproc as sp
import json
from functools import singledispatchmethod
import hashlib
from beartype import beartype
from utility import StocProcTolerances, operator_norm
from model_base import Model
@beartype
@dataclass
class StocProcTolerances:
"""
An object to hold tolerances for :any:`stocproc.StocProc`
instances.
"""
integration: float = 1e-4
"""Integration tolerance."""
interpolation: float = 1e-4
"""Interpolation tolerance."""
@beartype
@dataclass
class TwoQubitModel:
@dataclass(eq=False)
class TwoQubitModel(Model):
"""
A class to dynamically calculate all the model parameters and
generate the HOPS configuration.
@ -76,12 +60,6 @@ class TwoQubitModel:
All attributes can be changed after initialization.
"""
__version__: int = 1
"""
The version of the model implementation. It is increased for
breaking changes.
"""
ω_2: SupportsFloat = 1.0
"""The second oscilator energy gap."""
@ -408,54 +386,6 @@ class TwoQubitModel:
# Utility #
###########################################################################
def to_json(self):
"""Returns a json representation of the model configuration."""
return json.dumps(
{
key: self.__dict__[key]
for key in self.__dict__
if key[0] != "_" or key == "__version__"
},
cls=JSONEncoder,
ensure_ascii=False,
)
def __hash__(self):
return hashlib.sha256(self.to_json().encode("utf-8")).digest().__hash__()
@classmethod
def from_json(cls, json_str: str):
"""
Tries to instantiate a model config from the json string
``json_str``.
"""
model_dict = json.loads(json_str, object_hook=_object_hook)
assert (
model_dict["__version__"] == cls().__version__
), "Incompatible version detected."
return cls(**model_dict)
def __eq__(self, other):
this_keys = list(self.__dict__.keys())
ignored_keys = ["_sigmas"]
for key in this_keys:
if key not in ignored_keys:
this_val, other_val = self.__dict__[key], other.__dict__[key]
same = this_val == other_val
if isinstance(this_val, np.ndarray):
same = same.all()
if not same:
return False
return self.__hash__() == other.__hash__()
def effective_coupling(self, i: int) -> float:
"""
The effective coupling strength of bath ``i``. The maximum pre-factor times the bcf scale
@ -587,66 +517,3 @@ class TwoQubitModel:
return False
return True
def copy(self):
"""Return a deep copy of the model."""
return copy.deepcopy(self)
class JSONEncoder(json.JSONEncoder):
"""
A custom encoder to serialize objects occuring in
:any:`TwoQubitModel`.
"""
@singledispatchmethod
def default(self, obj: Any):
return super().default(obj)
@default.register
def _(self, arr: np.ndarray):
return {"type": "array", "value": arr.tolist()}
@default.register
def _(self, obj: qt.Qobj):
return {
"type": "Qobj",
"value": obj.full(),
"dims": obj.dims,
"obj_type": obj.type,
}
@default.register
def _(self, obj: complex):
return {"type": "complex", "re": obj.real, "im": obj.imag}
@default.register
def _(self, obj: StocProcTolerances):
return {"type": "StocProcTolerances", "value": dataclasses.asdict(obj)}
def _object_hook(dct: dict[str, Any]):
"""A custom decoder for the types introduced in :any:`JSONEncoder`."""
if "type" in dct:
type = dct["type"]
if type == "array":
return np.array(dct["value"])
if type == "Qobj":
return qt.Qobj(dct["value"], dims=dct["dims"], type=dct["obj_type"])
if type == "complex":
return dct["re"] + 1j * dct["im"]
if type == "StocProcTolerances":
return StocProcTolerances(**dct["value"])
return dct
def operator_norm(obj: qt.Qobj) -> float:
"""Returns the operator norm of ``obj``."""
return np.sqrt(max(np.abs((obj.dag() * obj).eigenenergies())))

81
utility.py Normal file
View file

@ -0,0 +1,81 @@
from functools import singledispatchmethod
import dataclasses
from dataclasses import dataclass
from beartype import beartype
import json
import numpy as np
import qutip as qt
from typing import Any
@beartype
@dataclass
class StocProcTolerances:
"""
An object to hold tolerances for :any:`stocproc.StocProc`
instances.
"""
integration: float = 1e-4
"""Integration tolerance."""
interpolation: float = 1e-4
"""Interpolation tolerance."""
class JSONEncoder(json.JSONEncoder):
"""
A custom encoder to serialize objects occuring in
:any:`TwoQubitModel`.
"""
@singledispatchmethod
def default(self, obj: Any):
return super().default(obj)
@default.register
def _(self, arr: np.ndarray):
return {"type": "array", "value": arr.tolist()}
@default.register
def _(self, obj: qt.Qobj):
return {
"type": "Qobj",
"value": obj.full(),
"dims": obj.dims,
"obj_type": obj.type,
}
@default.register
def _(self, obj: complex):
return {"type": "complex", "re": obj.real, "im": obj.imag}
@default.register
def _(self, obj: StocProcTolerances):
return {"type": "StocProcTolerances", "value": dataclasses.asdict(obj)}
def object_hook(dct: dict[str, Any]):
"""A custom decoder for the types introduced in :any:`JSONEncoder`."""
if "type" in dct:
type = dct["type"]
if type == "array":
return np.array(dct["value"])
if type == "Qobj":
return qt.Qobj(dct["value"], dims=dct["dims"], type=dct["obj_type"])
if type == "complex":
return dct["re"] + 1j * dct["im"]
if type == "StocProcTolerances":
return StocProcTolerances(**dct["value"])
return dct
def operator_norm(obj: qt.Qobj) -> float:
"""Returns the operator norm of ``obj``."""
return np.sqrt(max(np.abs((obj.dag() * obj).eigenenergies())))