mirror of
https://github.com/vale981/two_qubit_model
synced 2025-03-05 17:51:40 -05:00
modularize the two qubit model
This commit is contained in:
parent
0ea031837c
commit
6ecf1e7b0a
3 changed files with 165 additions and 138 deletions
79
model_base.py
Normal file
79
model_base.py
Normal 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)
|
|
@ -33,7 +33,7 @@ from dataclasses import dataclass, field
|
||||||
import functools
|
import functools
|
||||||
import itertools
|
import itertools
|
||||||
from numpy.typing import NDArray
|
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
|
||||||
import hops.util.bcf_fits
|
import hops.util.bcf_fits
|
||||||
import hops.core.hierarchy_parameters as params
|
import hops.core.hierarchy_parameters as params
|
||||||
|
@ -45,30 +45,14 @@ from hops.util.truncation_schemes import (
|
||||||
BathMemory,
|
BathMemory,
|
||||||
)
|
)
|
||||||
import stocproc as sp
|
import stocproc as sp
|
||||||
import json
|
|
||||||
from functools import singledispatchmethod
|
|
||||||
import hashlib
|
|
||||||
from beartype import beartype
|
from beartype import beartype
|
||||||
|
from utility import StocProcTolerances, operator_norm
|
||||||
|
from model_base import Model
|
||||||
|
|
||||||
|
|
||||||
@beartype
|
@beartype
|
||||||
@dataclass
|
@dataclass(eq=False)
|
||||||
class StocProcTolerances:
|
class TwoQubitModel(Model):
|
||||||
"""
|
|
||||||
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:
|
|
||||||
"""
|
"""
|
||||||
A class to dynamically calculate all the model parameters and
|
A class to dynamically calculate all the model parameters and
|
||||||
generate the HOPS configuration.
|
generate the HOPS configuration.
|
||||||
|
@ -76,12 +60,6 @@ class TwoQubitModel:
|
||||||
All attributes can be changed after initialization.
|
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
|
ω_2: SupportsFloat = 1.0
|
||||||
"""The second oscilator energy gap."""
|
"""The second oscilator energy gap."""
|
||||||
|
|
||||||
|
@ -408,54 +386,6 @@ class TwoQubitModel:
|
||||||
# Utility #
|
# 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:
|
def effective_coupling(self, i: int) -> float:
|
||||||
"""
|
"""
|
||||||
The effective coupling strength of bath ``i``. The maximum pre-factor times the bcf scale
|
The effective coupling strength of bath ``i``. The maximum pre-factor times the bcf scale
|
||||||
|
@ -587,66 +517,3 @@ class TwoQubitModel:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
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
81
utility.py
Normal 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())))
|
Loading…
Add table
Reference in a new issue