simcats 1.0.0__py3-none-any.whl → 1.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
simcats/__init__.py CHANGED
@@ -1,5 +1,4 @@
1
- """
2
- SimCATS is a python framework for simulating charge stability diagrams (CSDs) typically measured during the tuning
1
+ """SimCATS is a python framework for simulating charge stability diagrams (CSDs) typically measured during the tuning
3
2
  process of qubits.
4
3
  """
5
4
 
@@ -7,4 +6,4 @@ from ._simulation import Simulation
7
6
  from ._default_configs import default_configs
8
7
 
9
8
  __all__ = ["Simulation", "default_configs"]
10
- __version__ = "1.0.0"
9
+ __version__ = "1.2.0"
@@ -156,11 +156,16 @@ class OccupationDotJumps(OccupationDistortionInterface):
156
156
  numpy array with the axis mapping to the CSD axis.
157
157
 
158
158
  """
159
- if not bool(self.rng.binomial(1, self.ratio)):
160
- self.__activated = False
159
+ if freeze and not self.__activated:
161
160
  return occupations, lead_transitions
162
- else:
163
- self.__activated = True
161
+
162
+ # only resample activation if not frozen
163
+ if not freeze:
164
+ if not bool(self.rng.binomial(1, self.ratio)):
165
+ self.__activated = False
166
+ return occupations, lead_transitions
167
+ else:
168
+ self.__activated = True
164
169
 
165
170
  resolution = occupations.shape[0:2]
166
171
  if freeze:
@@ -467,8 +472,8 @@ class OccupationDotJumps(OccupationDistortionInterface):
467
472
  volt_limits_g2=volt_limits_g2,
468
473
  resolution=(max_jump, occupation.shape[0]) if max_jump > 1 else (occupation.shape[0]),
469
474
  )
470
- left_occupation = np.reshape(left_occupation, (occupation.shape[1], max_jump, 2))
471
- left_charge_transitions = np.reshape(left_charge_transitions, (occupation.shape[1], max_jump))
475
+ left_occupation = np.reshape(left_occupation, (occupation.shape[0], max_jump, 2))
476
+ left_charge_transitions = np.reshape(left_charge_transitions, (occupation.shape[0], max_jump))
472
477
  occupation_stacked = np.hstack((left_occupation, occupation))
473
478
  if lead_transitions is not None:
474
479
  total_charge_transitions_stacked = np.hstack((left_charge_transitions, lead_transitions))
@@ -3,6 +3,6 @@ SimCATS subpackage containing all functionalities related to the simulation of i
3
3
  """
4
4
 
5
5
  from simcats.ideal_csd._ideal_csd_interface import IdealCSDInterface
6
- from simcats.ideal_csd.geometric._ideal_csd_geometric import IdealCSDGeometric
6
+ from simcats.ideal_csd.geometric._ideal_csd_geometric_class import IdealCSDGeometric
7
7
 
8
8
  __all__ = ["IdealCSDInterface", "IdealCSDGeometric"]
@@ -8,7 +8,6 @@ from typing import List, Tuple, Union
8
8
 
9
9
  import numpy as np
10
10
 
11
- from simcats.ideal_csd import IdealCSDInterface
12
11
  from simcats.ideal_csd.geometric import (
13
12
  calculate_all_bezier_anchors,
14
13
  generate_lead_transition_mask_1d,
@@ -20,150 +19,6 @@ from simcats.ideal_csd.geometric import initialize_tct_functions
20
19
  __all__ = []
21
20
 
22
21
 
23
- class IdealCSDGeometric(IdealCSDInterface):
24
- """Geometric simulation approach implementation of the IdealCSDInterface."""
25
-
26
- def __init__(
27
- self,
28
- tct_params: List[np.ndarray],
29
- rotation: float = -np.pi / 4,
30
- lut_entries: Union[int, None] = None,
31
- cdf_type: str = "sigmoid",
32
- cdf_gamma_factor: Union[float, None] = None,
33
- ) -> None:
34
- """Initializes an object of the class for the geometric simulation approach which is based on total charge
35
- transitions (TCTs).
36
-
37
- Args:
38
- tct_params (List[np.ndarray]): List containing a numpy array with parameters for every TCT in the CSD.
39
- Each array contains all required parameters to describe the TCT form. \n
40
- The parameters for a TCT are: \n
41
- [0] = length left (in x-/voltage-space, not number of points) \n
42
- [1] = length right (in x-/voltage-space, not number of points) \n
43
- [2] = gradient left (in voltages) \n
44
- [3] = gradient right (in voltages) \n
45
- [4] = start position x (bezier curve leftmost point) (in x-/voltage-space, not number of points) \n
46
- [5] = start position y (bezier curve leftmost point) (in x-/voltage-space, not number of points) \n
47
- [6] = end position x (bezier curve rightmost point) (in x-/voltage-space, not number of points) \n
48
- [7] = end position y (bezier curve rightmost point) (in x-/voltage-space, not number of points)
49
- rotation (float): Float value defining the rotation to be applied to the TCT (which is usually represented
50
- with the tct_params rotated by 45 degrees). Default is -np.pi/4.
51
- lut_entries (Union[int, None]): Number of samples for the lookup-table for bezier curves. If this is not None, a
52
- lookup-table will be used to evaluate the points on the bezier curves, else they are solved explicitly.
53
- Using a lookup-table speeds up the calculation at the possible cost of accuracy. Default is None.
54
- cdf_type (str): Name of the type of cumulative distribution function (CDF) to be used. Can be either
55
- "cauchy" or "sigmoid". Default is "sigmoid".
56
- cdf_gamma_factor (Union[float, None]): The factor used for the calculation of the gamma values of the CDF. If set to None
57
- (=default) the default values for the selected cdf_type are used (2.2 for sigmoid, 6.15 for cauchy).
58
- Default is None. \n
59
- Gamma is calculated as follows: \n
60
- gamma = width_bezier_curve / cdf_gamma_factor
61
- """
62
- self.tct_params = tct_params
63
- self.rotation = rotation
64
- self.lut_entries = lut_entries
65
- self.cdf_type = cdf_type
66
- self.cdf_gamma_factor = cdf_gamma_factor
67
-
68
- @property
69
- def tct_params(self) -> List[np.ndarray]:
70
- """List containing a numpy array with parameters for every TCT in the CSD. Each array contains all required
71
- parameters to describe the TCT form.
72
- """
73
- return self.__tct_params
74
-
75
- @tct_params.setter
76
- def tct_params(self, wave_params: list):
77
- self.__tct_params = wave_params
78
-
79
- @property
80
- def rotation(self) -> float:
81
- """Float value defining the rotation to be applied to the TCT (which is usually represented with the tct_params
82
- rotated by 45 degrees).
83
- """
84
- return self.__rotation
85
-
86
- @rotation.setter
87
- def rotation(self, rotation: float) -> None:
88
- self.__rotation = rotation
89
-
90
- @property
91
- def lut_entries(self) -> Union[int, None]:
92
- """Number of samples for the lookup-table for bezier curves. If this is not None, a lookup-table will be used to
93
- evaluate the points on the bezier curves, else they are solved explicitly.
94
- """
95
- return self.__lut_entries
96
-
97
- @lut_entries.setter
98
- def lut_entries(self, lut_entries: Union[int, None]):
99
- self.__lut_entries = lut_entries
100
-
101
- @property
102
- def cdf_type(self) -> str:
103
- """Name of the type of cumulative distribution function (CDF) to be used."""
104
- return self.__cdf_type
105
-
106
- @cdf_type.setter
107
- def cdf_type(self, cdf_type: str) -> None:
108
- self.__cdf_type = cdf_type
109
-
110
- @property
111
- def cdf_gamma_factor(self) -> Union[float, None]:
112
- """The factor used for the calculation of the gamma values of the CDF. If set to None (=default) the default values
113
- for the selected cdf_type are used (2.2 for sigmoid, 6.15 for cauchy).
114
- """
115
- return self.__cdf_gamma_factor
116
-
117
- @cdf_gamma_factor.setter
118
- def cdf_gamma_factor(self, cdf_gamma_factor: Union[float, None]):
119
- self.__cdf_gamma_factor = cdf_gamma_factor
120
-
121
- def get_csd_data(
122
- self,
123
- volt_limits_g1: np.ndarray,
124
- volt_limits_g2: np.ndarray,
125
- resolution: Union[int, np.ndarray] = np.array([100, 100]),
126
- ) -> Tuple[np.ndarray, np.ndarray]:
127
- """Retrieve ideal data (occupation numbers and a lead transition mask) for given gate voltages.
128
-
129
- Args:
130
- volt_limits_g1 (np.ndarray): Voltage sweep range of (plunger) gate 1 (second-/x-axis). \n
131
- Example: \n
132
- [min_V1, max_V1]
133
- volt_limits_g2 (np.ndarray): Voltage sweep range of (plunger) gate 2 (first-/y-axis). \n
134
- Example: \n
135
- [min_V2, max_V2]
136
- resolution (np.ndarray): Desired resolution (in pixels) for the gates. If only one value is supplied, a 1D
137
- sweep is performed. Then, both gates are swept simultaneously. Default is np.array([100, 100]). \n
138
- Example: \n
139
- [res_g1, res_g2]
140
-
141
- Returns:
142
- Tuple[np.ndarray, np.ndarray]: Occupation numbers and lead transition mask (in our case: total charge
143
- transitions). The occupation numbers are stored in a 3-dimensional numpy array. The first two dimensions map
144
- to the axis of the CSD, while the third dimension indicates the dot of the corresponding occupation value.
145
- The label mask for the lead-to-dot transitions is stored in a 2-dimensional numpy array with the axis
146
- mapping to the CSD axis.
147
-
148
- """
149
- return ideal_csd_geometric(
150
- tct_params=self.__tct_params,
151
- volt_limits_g1=volt_limits_g1,
152
- volt_limits_g2=volt_limits_g2,
153
- resolution=resolution,
154
- rotation=self.__rotation,
155
- lut_entries=self.__lut_entries,
156
- cdf_type=self.__cdf_type,
157
- cdf_gamma_factor=self.__cdf_gamma_factor,
158
- )
159
-
160
- def __repr__(self):
161
- return (
162
- self.__class__.__name__
163
- + f"(tct_params={self.__tct_params}, rotation={self.__rotation}, lut_entries={self.__lut_entries}, cdf_type='{self.__cdf_type}', cdf_gamma_factor={self.__cdf_gamma_factor})"
164
- )
165
-
166
-
167
22
  def ideal_csd_geometric(
168
23
  tct_params: List[np.ndarray],
169
24
  volt_limits_g1: np.ndarray,
@@ -0,0 +1,158 @@
1
+ """This module contains the required functionalities to generate ideal CSD data using supplied total charge
2
+ transitions (TCTs), voltage ranges and a desired resolution. It also implements the IdealCSDInterface.
3
+
4
+ @author: f.hader
5
+ """
6
+
7
+ from typing import List, Tuple, Union
8
+
9
+ import numpy as np
10
+
11
+ from simcats.ideal_csd import IdealCSDInterface
12
+ from simcats.ideal_csd.geometric import ideal_csd_geometric
13
+
14
+ __all__ = []
15
+
16
+
17
+ class IdealCSDGeometric(IdealCSDInterface):
18
+ """Geometric simulation approach implementation of the IdealCSDInterface."""
19
+
20
+ def __init__(
21
+ self,
22
+ tct_params: List[np.ndarray],
23
+ rotation: float = -np.pi / 4,
24
+ lut_entries: Union[int, None] = None,
25
+ cdf_type: str = "sigmoid",
26
+ cdf_gamma_factor: Union[float, None] = None,
27
+ ) -> None:
28
+ """Initializes an object of the class for the geometric simulation approach which is based on total charge
29
+ transitions (TCTs).
30
+
31
+ Args:
32
+ tct_params (List[np.ndarray]): List containing a numpy array with parameters for every TCT in the CSD.
33
+ Each array contains all required parameters to describe the TCT form. \n
34
+ The parameters for a TCT are: \n
35
+ [0] = length left (in x-/voltage-space, not number of points) \n
36
+ [1] = length right (in x-/voltage-space, not number of points) \n
37
+ [2] = gradient left (in voltages) \n
38
+ [3] = gradient right (in voltages) \n
39
+ [4] = start position x (bezier curve leftmost point) (in x-/voltage-space, not number of points) \n
40
+ [5] = start position y (bezier curve leftmost point) (in x-/voltage-space, not number of points) \n
41
+ [6] = end position x (bezier curve rightmost point) (in x-/voltage-space, not number of points) \n
42
+ [7] = end position y (bezier curve rightmost point) (in x-/voltage-space, not number of points)
43
+ rotation (float): Float value defining the rotation to be applied to the TCT (which is usually represented
44
+ with the tct_params rotated by 45 degrees). Default is -np.pi/4.
45
+ lut_entries (Union[int, None]): Number of samples for the lookup-table for bezier curves. If this is not None, a
46
+ lookup-table will be used to evaluate the points on the bezier curves, else they are solved explicitly.
47
+ Using a lookup-table speeds up the calculation at the possible cost of accuracy. Default is None.
48
+ cdf_type (str): Name of the type of cumulative distribution function (CDF) to be used. Can be either
49
+ "cauchy" or "sigmoid". Default is "sigmoid".
50
+ cdf_gamma_factor (Union[float, None]): The factor used for the calculation of the gamma values of the CDF. If set to None
51
+ (=default) the default values for the selected cdf_type are used (2.2 for sigmoid, 6.15 for cauchy).
52
+ Default is None. \n
53
+ Gamma is calculated as follows: \n
54
+ gamma = width_bezier_curve / cdf_gamma_factor
55
+ """
56
+ self.tct_params = tct_params
57
+ self.rotation = rotation
58
+ self.lut_entries = lut_entries
59
+ self.cdf_type = cdf_type
60
+ self.cdf_gamma_factor = cdf_gamma_factor
61
+
62
+ @property
63
+ def tct_params(self) -> List[np.ndarray]:
64
+ """List containing a numpy array with parameters for every TCT in the CSD. Each array contains all required
65
+ parameters to describe the TCT form.
66
+ """
67
+ return self.__tct_params
68
+
69
+ @tct_params.setter
70
+ def tct_params(self, tct_params: list):
71
+ self.__tct_params = tct_params
72
+
73
+ @property
74
+ def rotation(self) -> float:
75
+ """Float value defining the rotation to be applied to the TCT (which is usually represented with the tct_params
76
+ rotated by 45 degrees).
77
+ """
78
+ return self.__rotation
79
+
80
+ @rotation.setter
81
+ def rotation(self, rotation: float) -> None:
82
+ self.__rotation = rotation
83
+
84
+ @property
85
+ def lut_entries(self) -> Union[int, None]:
86
+ """Number of samples for the lookup-table for bezier curves. If this is not None, a lookup-table will be used to
87
+ evaluate the points on the bezier curves, else they are solved explicitly.
88
+ """
89
+ return self.__lut_entries
90
+
91
+ @lut_entries.setter
92
+ def lut_entries(self, lut_entries: Union[int, None]):
93
+ self.__lut_entries = lut_entries
94
+
95
+ @property
96
+ def cdf_type(self) -> str:
97
+ """Name of the type of cumulative distribution function (CDF) to be used."""
98
+ return self.__cdf_type
99
+
100
+ @cdf_type.setter
101
+ def cdf_type(self, cdf_type: str) -> None:
102
+ self.__cdf_type = cdf_type
103
+
104
+ @property
105
+ def cdf_gamma_factor(self) -> Union[float, None]:
106
+ """The factor used for the calculation of the gamma values of the CDF. If set to None (=default) the default values
107
+ for the selected cdf_type are used (2.2 for sigmoid, 6.15 for cauchy).
108
+ """
109
+ return self.__cdf_gamma_factor
110
+
111
+ @cdf_gamma_factor.setter
112
+ def cdf_gamma_factor(self, cdf_gamma_factor: Union[float, None]):
113
+ self.__cdf_gamma_factor = cdf_gamma_factor
114
+
115
+ def get_csd_data(
116
+ self,
117
+ volt_limits_g1: np.ndarray,
118
+ volt_limits_g2: np.ndarray,
119
+ resolution: Union[int, np.ndarray] = np.array([100, 100]),
120
+ ) -> Tuple[np.ndarray, np.ndarray]:
121
+ """Retrieve ideal data (occupation numbers and a lead transition mask) for given gate voltages.
122
+
123
+ Args:
124
+ volt_limits_g1 (np.ndarray): Voltage sweep range of (plunger) gate 1 (second-/x-axis). \n
125
+ Example: \n
126
+ [min_V1, max_V1]
127
+ volt_limits_g2 (np.ndarray): Voltage sweep range of (plunger) gate 2 (first-/y-axis). \n
128
+ Example: \n
129
+ [min_V2, max_V2]
130
+ resolution (np.ndarray): Desired resolution (in pixels) for the gates. If only one value is supplied, a 1D
131
+ sweep is performed. Then, both gates are swept simultaneously. Default is np.array([100, 100]). \n
132
+ Example: \n
133
+ [res_g1, res_g2]
134
+
135
+ Returns:
136
+ Tuple[np.ndarray, np.ndarray]: Occupation numbers and lead transition mask (in our case: total charge
137
+ transitions). The occupation numbers are stored in a 3-dimensional numpy array. The first two dimensions map
138
+ to the axis of the CSD, while the third dimension indicates the dot of the corresponding occupation value.
139
+ The label mask for the lead-to-dot transitions is stored in a 2-dimensional numpy array with the axis
140
+ mapping to the CSD axis.
141
+
142
+ """
143
+ return ideal_csd_geometric(
144
+ tct_params=self.__tct_params,
145
+ volt_limits_g1=volt_limits_g1,
146
+ volt_limits_g2=volt_limits_g2,
147
+ resolution=resolution,
148
+ rotation=self.__rotation,
149
+ lut_entries=self.__lut_entries,
150
+ cdf_type=self.__cdf_type,
151
+ cdf_gamma_factor=self.__cdf_gamma_factor,
152
+ )
153
+
154
+ def __repr__(self):
155
+ return (
156
+ self.__class__.__name__
157
+ + f"(tct_params={self.__tct_params}, rotation={self.__rotation}, lut_entries={self.__lut_entries}, cdf_type='{self.__cdf_type}', cdf_gamma_factor={self.__cdf_gamma_factor})"
158
+ )
@@ -84,12 +84,14 @@ def tct_bezier(
84
84
 
85
85
  # initialize bezier curve
86
86
  bezier_curve = bezier.Curve.from_nodes(nodes)
87
- xb, yb = sympy.symbols("x y")
88
- bezier_implicit = bezier_curve.implicitize()
89
87
  # retrieve a lookup-table if the given lut_entries value is not None
90
88
  if lut_entries:
91
89
  t = np.linspace(0, 1, lut_entries)
92
90
  bezier_lut = bezier_curve.evaluate_multi(t)
91
+ else:
92
+ xb, yb = sympy.symbols("x y")
93
+ bezier_implicit = bezier_curve.implicitize()
94
+ bezier_implicit_solved = sympy.solve(bezier_implicit, yb)
93
95
 
94
96
  # retrieve length of bezier curve & period length. Both are required to calculate the region
95
97
  # where the x-values to be evaluated are located
@@ -116,7 +118,12 @@ def tct_bezier(
116
118
  # all other ids are simulated as linear parts
117
119
  # lowest value = left bezier anchor
118
120
  # highest value = right bezier anchor + #additional_peaks * period length
119
- x_range_wave = np.array([tct_params[4], (tct_params[6] + (max_peaks - 1) * (tct_params[0] + tct_params[1]))])
121
+ x_range_wave = np.array(
122
+ [
123
+ tct_params[4],
124
+ (tct_params[6] + (max_peaks - 1) * (tct_params[0] + tct_params[1])),
125
+ ]
126
+ )
120
127
  ids_wave = np.where((x_eval + offset_x >= x_range_wave[0]) & (x_eval + offset_x <= x_range_wave[1]))[0]
121
128
  else:
122
129
  x_range_wave = [x_eval[0], x_eval[-1]]
@@ -138,7 +145,10 @@ def tct_bezier(
138
145
  y_res[x_id] = bezier_lut[1, np.argmin(np.abs(bezier_lut[0, :] - (x_mod_per + offset_x)))]
139
146
  else:
140
147
  # use sympy to solve symbolic expression for x, because s is not linearly mapped to x
141
- temp_y = sympy.solve(bezier_implicit.subs({xb: x_mod_per + offset_x}), yb)
148
+ temp_y = [
149
+ bezier_implicit_solution.subs({xb: x_mod_per + offset_x})
150
+ for bezier_implicit_solution in bezier_implicit_solved
151
+ ]
142
152
  # might get two solutions because implicit function might be quadratic. If so, the second solution
143
153
  # is the positive one and selected therefore, as we assume to have only positive y-values after
144
154
  # rotating a signal with only positive x- & y-values by 45 degree
@@ -168,9 +178,10 @@ def tct_bezier(
168
178
  )
169
179
  else:
170
180
  # use sympy to solve symbolic expression for x, because s is not linearly mapped to x
171
- temp_y = sympy.solve(
172
- bezier_implicit.subs({xb: 2 * bezier_length + right_lin_length - x_mod_per + offset_x}), yb
173
- )
181
+ temp_y = [
182
+ bezier_implicit_solution.subs({xb: 2 * bezier_length + right_lin_length - x_mod_per + offset_x})
183
+ for bezier_implicit_solution in bezier_implicit_solved
184
+ ]
174
185
  # might get two solutions because implicit function might be quadratic. If so, the second solution
175
186
  # is the positive one and selected therefore, as we assume to have only positive y-values after
176
187
  # rotating a signal with only positive x- & y-values by 45 degree
@@ -3,7 +3,7 @@ SimCATS subpackage with support functions that are not assigned to any specific
3
3
  """
4
4
 
5
5
  from simcats.support_functions._parameter_sampling import ParameterSamplingInterface, NormalSamplingRange, \
6
- UniformSamplingRange
6
+ LogNormalSamplingRange, UniformSamplingRange, ExponentialSamplingRange
7
7
  from simcats.support_functions._fermi_filter1d import fermi_filter1d, fermi_dirac_derivative
8
8
  from simcats.support_functions._cumulative_distribution_functions import cauchy_cdf, multi_cauchy_cdf, sigmoid_cdf, \
9
9
  multi_sigmoid_cdf
@@ -11,6 +11,6 @@ from simcats.support_functions._signed_dist_points_line import signed_dist_point
11
11
  from simcats.support_functions._rotate_points import rotate_points
12
12
  from simcats.support_functions._plotting import plot_csd
13
13
 
14
- __all__ = ["ParameterSamplingInterface", "NormalSamplingRange", "UniformSamplingRange", "fermi_filter1d",
15
- "fermi_dirac_derivative", "cauchy_cdf", "multi_cauchy_cdf", "sigmoid_cdf", "multi_sigmoid_cdf",
16
- "signed_dist_points_line", "rotate_points", "plot_csd"]
14
+ __all__ = ["ParameterSamplingInterface", "NormalSamplingRange", "LogNormalSamplingRange", "UniformSamplingRange",
15
+ "ExponentialSamplingRange", "fermi_filter1d", "fermi_dirac_derivative", "cauchy_cdf", "multi_cauchy_cdf",
16
+ "sigmoid_cdf", "multi_sigmoid_cdf", "signed_dist_points_line", "rotate_points", "plot_csd"]
@@ -2,7 +2,7 @@
2
2
 
3
3
  The contained functions can be used for example for the parameter sampling in the distortions module.
4
4
 
5
- @author: s.fleitmann
5
+ @author: s.fleitmann, f.fuchs
6
6
  """
7
7
 
8
8
  import warnings
@@ -42,12 +42,14 @@ class ParameterSamplingInterface(ABC):
42
42
 
43
43
 
44
44
  class NormalSamplingRange(ParameterSamplingInterface):
45
+ """Normal sampling range implementation of ParameterSamplingInterface."""
45
46
  def __init__(
46
47
  self,
47
48
  total_range: Tuple,
48
49
  std: float,
50
+ mean: Union[float, None] = None,
49
51
  sampling_range: Union[float, None] = None,
50
- rng: np.random.Generator = np.random.default_rng(),
52
+ rng: Union[np.random.Generator, None] = None,
51
53
  ) -> None:
52
54
  """This class can be used to generate randomly normal sampled parameters within a given range.
53
55
 
@@ -55,22 +57,30 @@ class NormalSamplingRange(ParameterSamplingInterface):
55
57
 
56
58
  Args:
57
59
  total_range (Tuple): The total range in which the parameters can be sampled. This can be narrowed down
58
- randomly with the help of sampling_range.
60
+ randomly with the help of sampling_range. If the normal distribution generates a sample outside this
61
+ range, a new sample is drawn until a sample inside the sampling_range/total_range was generated,
62
+ leading to a truncated normal distribution.
59
63
  std (float): The standard deviation of the sampled elements, which is used in the normal distribution.
64
+ mean (Union[float, None]): The mean to be used for the normal distribution. If None, the center of the
65
+ total range will be used. Defaults to None.
60
66
  sampling_range (Union[float, None]): The maximum range in which the parameter is allowed to change during
61
67
  the simulation. The explicit range is set up during the initialization, narrowing down the
62
68
  supplied total_range. Default is None, which leads to no narrowing of the given total_range.
63
- rng (np.random.Generator): random number generator used for the sampling of random numbers. Default is the
64
- default generator of numpy (np.random.default_rng())
69
+ rng (np.random.Generator): random number generator used for the sampling of random numbers. If None, the
70
+ default generator of numpy (np.random.default_rng()) is used. Default is None.
65
71
  """
66
- self.__rng = rng
72
+ if rng:
73
+ self.__rng = rng
74
+ else:
75
+ self.__rng = np.random.default_rng()
67
76
  if sampling_range is None:
68
77
  self.__range = total_range
69
78
  else:
70
79
  if np.greater_equal(sampling_range, total_range[1] - total_range[0]):
71
80
  warnings.warn(
72
81
  "The given reduced sampling range is equal or larger than the given total range. As "
73
- "default the given total sampling range is taken."
82
+ "default the given total sampling range is taken.",
83
+ stacklevel=2,
74
84
  )
75
85
  self.__range = total_range
76
86
  else:
@@ -79,11 +89,17 @@ class NormalSamplingRange(ParameterSamplingInterface):
79
89
  )
80
90
  self.__range = (sampled - 0.5 * sampling_range, sampled + 0.5 * sampling_range)
81
91
  self.__std = std
92
+ if mean is not None:
93
+ self.__mean = mean
94
+ else:
95
+ self.__mean = np.mean(self.__range)
82
96
  self.__last_sample = None
83
97
 
84
98
  def sample_parameter(self):
85
- sampled = self.__rng.normal(loc=np.mean(self.__range), scale=self.__std)
86
- sampled = np.maximum(self.__range[0], np.minimum(self.__range[1], sampled))
99
+ sampled = self.__rng.normal(loc=self.__mean, scale=self.__std)
100
+ # repeat sampling until the sampled value is in self.__range
101
+ while sampled < self.__range[0] or sampled > self.__range[1]:
102
+ sampled = self.__rng.normal(loc=self.__mean, scale=self.__std)
87
103
  self.__last_sample = sampled
88
104
  return sampled
89
105
 
@@ -93,16 +109,17 @@ class NormalSamplingRange(ParameterSamplingInterface):
93
109
  def __repr__(self) -> str:
94
110
  return (
95
111
  self.__class__.__name__
96
- + f"(last_sample={self.last_sample()}, range={self.__range}, std={self.__std}, rng={self.__rng})"
112
+ + f"(last_sample={self.last_sample()}, range={self.__range}, mean={self.__mean}, std={self.__std}, rng={self.__rng})"
97
113
  )
98
114
 
99
115
 
100
116
  class UniformSamplingRange(ParameterSamplingInterface):
117
+ """Uniform sampling range implementation of ParameterSamplingInterface."""
101
118
  def __init__(
102
119
  self,
103
120
  total_range: Tuple,
104
121
  sampling_range: Union[float, None] = None,
105
- rng: np.random.Generator = np.random.default_rng(),
122
+ rng: Union[np.random.Generator, None] = None,
106
123
  ) -> None:
107
124
  """This class can be used to generate randomly uniform sampled parameters within a given range.
108
125
 
@@ -114,17 +131,21 @@ class UniformSamplingRange(ParameterSamplingInterface):
114
131
  sampling_range (Union[float, None]): The maximum range in which the parameter is allowed to change during
115
132
  the simulation. The explicit range is set up during the initialization, narrowing down the supplied
116
133
  total_range. Default is None, which leads to no narrowing of the given total_range.
117
- rng (np.random.Generator): random number generator used for the sampling of random numbers. Default is the
118
- default generator of numpy (np.random.default_rng())
134
+ rng (np.random.Generator): random number generator used for the sampling of random numbers. If None, the
135
+ default generator of numpy (np.random.default_rng()) is used. Default is None.
119
136
  """
120
- self.__rng = rng
137
+ if rng:
138
+ self.__rng = rng
139
+ else:
140
+ self.__rng = np.random.default_rng()
121
141
  if sampling_range is None:
122
142
  self.__range = total_range
123
143
  else:
124
144
  if np.greater_equal(sampling_range, total_range[1] - total_range[0]):
125
145
  warnings.warn(
126
146
  "The given reduced sampling range is equal or larger than the given total range. As "
127
- "default the given total sampling range is taken."
147
+ "default the given total sampling range is taken.",
148
+ stacklevel=2,
128
149
  )
129
150
  self.__range = total_range
130
151
  else:
@@ -144,3 +165,160 @@ class UniformSamplingRange(ParameterSamplingInterface):
144
165
 
145
166
  def __repr__(self) -> str:
146
167
  return self.__class__.__name__ + f"(last_sample={self.last_sample()}, range={self.__range}, rng={self.__rng})"
168
+
169
+
170
+ class LogNormalSamplingRange(ParameterSamplingInterface):
171
+ """Logarithmic normal sampling range implementation of ParameterSamplingInterface."""
172
+ def __init__(
173
+ self,
174
+ total_range: Tuple,
175
+ sampling_range: Union[float, None] = None,
176
+ rng: Union[np.random.Generator, None] = None,
177
+ mean: float = 0,
178
+ sigma: float = 1,
179
+ ) -> None:
180
+ """This class can be used to generate randomly log-normal sampled parameters within a given range.
181
+
182
+ For example, for the distortions used in the simulation of CSDs.
183
+
184
+ Args:
185
+ total_range (Tuple): The total range in which the parameters can be sampled. This can be narrowed down
186
+ randomly with the help of sampling_range. If the log-normal distribution generates a sample outside this
187
+ range, a new sample is drawn until a sample inside the sampling_range/total_range was generated, leading
188
+ toa truncated log-normal distribution.
189
+ sampling_range (Union[float, None]): The maximum range in which the parameter is allowed to change during
190
+ the simulation. The explicit range is set up during the initialization, narrowing down the supplied
191
+ total_range. Default is None, which leads to no narrowing of the given total_range.
192
+ rng (np.random.Generator): random number generator used for the sampling of random numbers. If None, the
193
+ default generator of numpy (np.random.default_rng()) is used. Default is None.
194
+ mean (float): Mean value of the underlying normal distribution. Default is 0.
195
+ sigma (float): Standard deviation of the underlying normal distribution. Must be non-negative. Default is 1.
196
+ """
197
+ if rng:
198
+ self.__rng = rng
199
+ else:
200
+ self.__rng = np.random.default_rng()
201
+ self.__mean: float = mean
202
+ self.__sigma: float = sigma
203
+ if sampling_range is None:
204
+ self.__range = total_range
205
+ else:
206
+ if np.greater_equal(sampling_range, total_range[1] - total_range[0]):
207
+ warnings.warn(
208
+ "The given reduced sampling range is equal or larger than the given total range. As "
209
+ "default the given total sampling range is taken.",
210
+ stacklevel=2,
211
+ )
212
+ self.__range = total_range
213
+ else:
214
+ sampled = self.__rng.uniform(
215
+ total_range[0] + 0.5 * sampling_range,
216
+ total_range[1] - 0.5 * sampling_range,
217
+ )
218
+ self.__range = (
219
+ sampled - 0.5 * sampling_range,
220
+ sampled + 0.5 * sampling_range,
221
+ )
222
+ self.__last_sample = None
223
+
224
+ def sample_parameter(self):
225
+ sampled = self.__rng.lognormal(mean=self.__mean, sigma=self.__sigma)
226
+ # repeat sampling until the sampled value is in self.__range
227
+ while sampled < self.__range[0] or sampled > self.__range[1]:
228
+ sampled = self.__rng.lognormal(mean=self.__mean, sigma=self.__sigma)
229
+ self.__last_sample = sampled
230
+ return sampled
231
+
232
+ def last_sample(self):
233
+ return self.__last_sample
234
+
235
+ def __repr__(self) -> str:
236
+ return (
237
+ self.__class__.__name__
238
+ + f"(last_sample={self.last_sample()}, range={self.__range}, mean={self.__mean}, sigma={self.__sigma}"
239
+ + f", rng={self.__rng})"
240
+ )
241
+
242
+
243
+ class ExponentialSamplingRange(ParameterSamplingInterface):
244
+ """Exponential distribution sampling range implementation of ParameterSamplingInterface."""
245
+
246
+ def __init__(
247
+ self,
248
+ total_range: Tuple,
249
+ scale: float,
250
+ sampling_range: Union[float, None] = None,
251
+ rng: Union[np.random.Generator, None] = None,
252
+ ) -> None:
253
+ """This class can be used to generate randomly sampled parameters from an exponential distribution within a given range.
254
+
255
+ The samples are calculated as follows:\n
256
+ min(sampling_range) + exponential_distribution_sample * (max(sampling_range) - min(Sampling_range))
257
+
258
+ To select the correct scale factor (1 / λ), take the following into consideration:\n
259
+ To have the p percent quantile at position q, the following must be valid:\n
260
+ q = ln( 1 / (1-p) ) / λ \n
261
+ with 1 / λ = scale \n
262
+ So in general the scale is calculated as: \n
263
+ scale = q / ln( 1 / (1-p) ) \n
264
+ For example: If it is desired to have 90% of the values in 50% of the sampling range, we get:\n
265
+ scale = 0.5 / ln( 1 / (1-0.9) ) = 0.21715
266
+
267
+ Further reading: https://en.wikipedia.org/wiki/Exponential_distribution#properties
268
+
269
+ Used for example for the distortions during the simulation of CSDs.
270
+
271
+ Args:
272
+ total_range (Tuple): The total range in which the parameters can be sampled. This can be narrowed down
273
+ randomly with the help of the parameter sampling_range. If the exponential distribution generates a
274
+ sample outside this range, a new sample is drawn until a sample inside the sampling_range/total_range
275
+ was generated, leading to a truncated exponential distribution.
276
+ scale (float): The scale of the exponential distribution. See __init__ docstring for more detailed
277
+ information.
278
+ sampling_range (Union[float, None]): The maximum range in which the parameter is allowed to change during
279
+ the simulation. The explicit range is set up during the initialization, narrowing down the
280
+ supplied total_range. Default is None, which leads to no narrowing of the given total_range.
281
+ rng (np.random.Generator): random number generator used for the sampling of random numbers. If None, the
282
+ default generator of numpy (np.random.default_rng()) is used. Default is None.
283
+ """
284
+ if rng:
285
+ self.__rng = rng
286
+ else:
287
+ self.__rng = np.random.default_rng()
288
+ if sampling_range is None:
289
+ self.__range = total_range
290
+ else:
291
+ if np.greater_equal(sampling_range, np.max(total_range) - np.min(total_range)):
292
+ warnings.warn(
293
+ "The given reduced sampling range is equal or larger than the given total range. As "
294
+ "default the given total sampling range is taken.",
295
+ stacklevel=2,
296
+ )
297
+ self.__range = total_range
298
+ else:
299
+ sampled = self.__rng.uniform(
300
+ np.min(total_range) + 0.5 * sampling_range, np.max(total_range) - 0.5 * sampling_range
301
+ )
302
+ if total_range[0] < total_range[1]:
303
+ self.__range = (sampled - 0.5 * sampling_range, sampled + 0.5 * sampling_range)
304
+ else:
305
+ self.__range = (sampled + 0.5 * sampling_range, sampled - 0.5 * sampling_range)
306
+ self.__scale = scale
307
+ self.__last_sample = None
308
+
309
+ def sample_parameter(self):
310
+ sampled = self.__range[0] + self.__rng.exponential(scale=self.__scale) * (self.__range[1] - self.__range[0])
311
+ # repeat sampling until the sampled value is in self.__range
312
+ while sampled < np.min(self.__range) or sampled > np.max(self.__range):
313
+ sampled = self.__range[0] + self.__rng.exponential(scale=self.__scale) * (self.__range[1] - self.__range[0])
314
+ self.__last_sample = sampled
315
+ return sampled
316
+
317
+ def last_sample(self):
318
+ return self.__last_sample
319
+
320
+ def __repr__(self) -> str:
321
+ return (
322
+ self.__class__.__name__
323
+ + f"(last_sample={self.last_sample()}, range={self.__range}, scale={self.__scale}, rng={self.__rng})"
324
+ )
@@ -0,0 +1,218 @@
1
+ Metadata-Version: 2.1
2
+ Name: simcats
3
+ Version: 1.2.0
4
+ Summary: SimCATS is a python framework for simulating charge stability diagrams (CSDs) typically measured during the tuning process of qubits.
5
+ Author-email: Fabian Hader <f.hader@fz-juelich.de>, Sarah Fleitmann <s.fleitmann@fz-juelich.de>, Fabian Fuchs <f.fuchs@fz-juelich.de>
6
+ License: CC BY-NC-SA 4.0
7
+ Project-URL: homepage, https://github.com/f-hader/SimCATS
8
+ Project-URL: documentation, https://simcats.readthedocs.io
9
+ Project-URL: source, https://github.com/f-hader/SimCATS
10
+ Project-URL: tracker, https://github.com/f-hader/SimCATS/issues
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Programming Language :: Python
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.7
16
+ Classifier: Programming Language :: Python :: 3.8
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Topic :: Scientific/Engineering
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.7
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: bezier
26
+ Requires-Dist: colorednoise
27
+ Requires-Dist: diplib
28
+ Requires-Dist: matplotlib
29
+ Requires-Dist: numpy
30
+ Requires-Dist: opencv-python
31
+ Requires-Dist: scipy
32
+ Requires-Dist: sympy
33
+
34
+ <h1 align="center">
35
+ <img src="https://raw.githubusercontent.com/f-hader/SimCATS/main/SimCATS_symbol.svg" alt="SimCATS logo">
36
+ <br>
37
+ </h1>
38
+
39
+ <div align="center">
40
+ <a href="https://github.com/f-hader/SimCATS/blob/main/LICENSE">
41
+ <img src="https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-lightgrey.svg" alt="License: CC BY-NC-SA 4.0"/>
42
+ </a>
43
+ <a href="https://pypi.org/project/simcats/">
44
+ <img src="https://img.shields.io/pypi/v/simcats.svg" alt="PyPi Latest Release"/>
45
+ </a>
46
+ <a href="https://simcats.readthedocs.io/en/latest/">
47
+ <img src="https://img.shields.io/readthedocs/simcats" alt="Read the Docs"/>
48
+ </a>
49
+ <a href="https://doi.org/10.1109/TQE.2024.3445967">
50
+ <img src="https://img.shields.io/badge/DOI-10.1109/TQE.2024.3445967-007ec6.svg" alt="DOI Publication"/>
51
+ </a>
52
+ </div>
53
+
54
+ # SimCATS
55
+
56
+ Simulation of CSDs for Automated Tuning Solutions (`SimCATS`) is a Python framework for simulating charge stability
57
+ diagrams (CSDs) typically measured during the tuning process of qubits.
58
+
59
+ ## Installation
60
+
61
+ The framework supports Python versions 3.7 - 3.11 and installs via pip:
62
+ ```
63
+ pip install simcats
64
+ ```
65
+
66
+ Alternatively, the `SimCATS` package can be installed by cloning the GitHub repository, navigating to the folder
67
+ containing the `setup.py` file and executing
68
+
69
+ ```
70
+ pip install .
71
+ ```
72
+
73
+ For the installation in development/editable mode, use the option `-e`.
74
+
75
+ ## Examples / Tutorials
76
+ After installing the package, a good starting point is a look into the Jupyter Notebook
77
+ `example_SimCATS_simulation_class.ipynb`, which provides an overview of the usage of the simulation class offered by
78
+ the framework.
79
+ For more detailed examples and explanations of the geometric ideal CSD simulation using Total Charge Transitions (TCTs), look at the Jupyter Notebook `example_SimCATS_IdealCSDGeometric.ipynb`. This notebook also includes a hint
80
+ regarding the generation of required labels for training algorithms that might need line labels defined as start and
81
+ end points or require semantic information about particular transitions.
82
+
83
+ ## Tests
84
+
85
+ The tests are written for the `PyTest` framework but should also work with the `unittest` framework.
86
+
87
+ To run the tests, install the packages `pytest`, `pytest-cov`, and `pytest-xdist` with
88
+
89
+ ```
90
+ pip install pytest pytest-cov pytest-xdist
91
+ ```
92
+
93
+ and run the following command:
94
+
95
+ ```
96
+ pytest --cov=simcats -n auto --dist loadfile .\tests\
97
+ ```
98
+
99
+ The argument
100
+ - `--cov=simcats` enables a coverage summary of the `SimCATS` package,
101
+ - `-n auto` enables the test to run with multiple threads (auto will choose as many threads as possible, but can be replaced with a specific number of threads to use), and
102
+ - `--dist loadfile` specifies that each file should be executed only by one thread.
103
+
104
+ <!-- start sec:documentation -->
105
+ ## Documentation
106
+
107
+ The official documentation is hosted on [ReadtheDocs](https://simcats.readthedocs.io), but can also be built locally.
108
+ To do this, first install the packages `sphinx`, `sphinx-rtd-theme`, `sphinx-autoapi`, `myst-nb `, and `jupytext` with
109
+
110
+ ```
111
+ pip install sphinx sphinx-rtd-theme sphinx-autoapi myst-nb jupytext
112
+ ```
113
+
114
+ and then, in the `docs` folder, execute the following command:
115
+
116
+ ```
117
+ .\make html
118
+ ```
119
+
120
+ To view the generated HTML documentation, open the file `docs\build\html\index.html`.
121
+ <!-- end sec:documentation -->
122
+
123
+ ## Structure of SimCATS
124
+
125
+ The primary user interface for `SimCATS` is the class `Simulation`, which combines all the necessary functionalities to
126
+ measure (simulate) a CSD and adjust the parameters for the simulated measurement. The class `Simulation` and default
127
+ configurations for the simulation (`default_configs`) can be imported directly from `simcats`. Aside from that,
128
+ `SimCATS` contains the subpackages `ideal_csd`, `sensor`, `distortions`, and `support_functions`, described in
129
+ the following sections.
130
+
131
+ ### Module `simulation`
132
+
133
+ An instance of the simulation class requires
134
+
135
+ - an implementation of the `IdealCSDInterface` for the simulation of ideal CSD data,
136
+ - an implementation of the `SensorInterface` for the simulation of the sensor (dot) reaction based on the ideal CSD
137
+ data, and
138
+ - (optionally) implementations of the desired types of distortions, which can be implementations from `OccupationDistortionInterface`, `SensorPotentialDistortionInterface`, or `SensorResponseDistortionInterface`.
139
+
140
+ With an initialized instance of the `Simulation` class, it is possible to run simulations using the `measure` function
141
+ (see `example_SimCATS_simulation_class.ipynb`).
142
+
143
+ ### Subpackage `ideal_csd`
144
+
145
+ This subpackage contains the `IdealCSDInterface` used by the `Simulation` class and an implementation of
146
+ the `IdealCSDInterface` (`IdealCSDGeometric`) based on our geometric simulation approach.
147
+ Additionally, it contains in the subpackage `geometric` the functions used by `IdealCSDGeometric`, including the
148
+ implementation of the total charge transition (TCT) definition and functions for calculating the occupations using TCTs.
149
+
150
+ ### Subpackage `distortions`
151
+
152
+ The distortions subpackage contains the `DistortionInterface` from which the `OccupationDistortionInterface`, the
153
+ `SensorPotentialDistortionInterface`, and the `SensorResponseDistortionInterface` are derived. Distortion functions used
154
+ in the `Simulation` class have to implement these specific interfaces. Implemented distortions included in the
155
+ subpackage are:
156
+
157
+ - white noise, generated by sampling from a normal distribution,
158
+ - pink noise, generated using the package colorednoise ([https://github.com/felixpatzelt/colorednoise](https://github.com/felixpatzelt/colorednoise)),
159
+ - random telegraph noise (RTN), generated using the algorithm described in ["Toward Robust Autotuning of Noisy Quantum Dot Devices" by Ziegler et al.](https://doi.org/10.1103/PhysRevApplied.17.024069) (RTN is called sensor jumps there),
160
+ - dot jumps, simulated using the algorithm described in ["Toward Robust Autotuning of Noisy Quantum Dot Devices" by Ziegler et al.](https://doi.org/10.1103/PhysRevApplied.17.024069) (In the `Simulation` class, this is applied to a whole block of rows or columns, but there is also a function for applying it linewise.), and
161
+ - lead transition blurring, simulated using Gaussian or Fermi-Dirac blurring.
162
+
163
+ The implementations also offer the option to set ratios (parameter `ratio`) for the occurrence of the distortion (e.g. dot jumps may only happen sometimes and not in every measurement). Moreover, it is also possible to sample the
164
+ noise parameters from a given sampling range using an object of type `ParameterSamplingInterface`.
165
+ Classes for randomly sampling from a normal distribution or a uniform distribution within a given range are available in
166
+ the subpackage `support_functions`.
167
+ In this case, the strength is randomly chosen from the given range for every measurement.
168
+ Additionally, it is possible to specify that this range should be a smaller subrange of the provided range.
169
+ This allows restricting distortion fluctuations during a simulation while enabling a large variety of different strengths
170
+ for the initialization of the objects. <br>
171
+ RTN, dot jumps, and lead transition blurring are applied in the pixel domain. However, the jump length or the blurring strength should be consistent in the voltage domain even if the resolution changes. Therefore, the parameters
172
+ are given in the voltage domain and adjusted according to the resolution in terms of pixel per voltage. <br>
173
+ For a simulated measurement with a continuous voltage sweep involving an averaging for each pixel, the noise strength of the
174
+ white and pink noise should be adjusted if the resolution (volt per pixel) changes, due to smoothing out the noise. This smoothing depends on the type of averaging used and is not incorporated in the default implementation.
175
+
176
+ ### Subpackage `sensor`
177
+
178
+ This subpackage contains the `SensorInterface` that defines how a sensor simulation must be implemented to be used by the `Simulation` class. The `SensorPeakInterface` provides the desired representation for the definition of the Coulomb peaks the sensor uses. `SensorGeneric` implements the `SensorInterface` and offers functions for simulating the sensor response and potential. It offers the possibility to simulate with a single peak or multiple sensor peaks. Current implementations of the `SensorPeakInterface` are `SensorPeakGaussian` and `SensorPeakLorentzian`.
179
+
180
+ ### Subpackage `support_functions`
181
+
182
+ This subpackage contains support functions, which are used by the end user and by different functions of the framework.
183
+ - `fermi_filter1d` is an implementation of a one-dimensional Fermi-Dirac filter.
184
+ - `plot_csd` plots one and two-dimensional CSDs. The function can also plot ground truth data (see `example_SimCATS_simulation_class.ipynb` for examples).
185
+ - `rotate_points` simply rotates coordinates (stored in a (n, 2) shaped array) by a given angle. It is especially used during the generation of the ideal data.
186
+ - `ParameterSamplingInterface` defines an interface for randomly sampled (fluctuated) strengths of distortions.
187
+ - `NormalSamplingRange` and `UniformSamplingRange` are implementations of the `ParameterSamplingInterface`.
188
+
189
+ ## Citations
190
+
191
+ ```bibtex
192
+ @article{hader2024simcats,
193
+ author={Hader, Fabian and Fleitmann, Sarah and Vogelbruch, Jan and Geck, Lotte and Waasen, Stefan van},
194
+ journal={IEEE Transactions on Quantum Engineering},
195
+ title={Simulation of Charge Stability Diagrams for Automated Tuning Solutions (SimCATS)},
196
+ year={2024},
197
+ volume={5},
198
+ pages={1-14},
199
+ doi={10.1109/TQE.2024.3445967}
200
+ }
201
+ ```
202
+
203
+ ## License, CLA, and Copyright
204
+
205
+ [![CC BY-NC-SA 4.0][cc-by-nc-sa-shield]][cc-by-nc-sa]
206
+
207
+ This work is licensed under a
208
+ [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License][cc-by-nc-sa].
209
+
210
+ [![CC BY-NC-SA 4.0][cc-by-nc-sa-image]][cc-by-nc-sa]
211
+
212
+ [cc-by-nc-sa]: http://creativecommons.org/licenses/by-nc-sa/4.0/
213
+ [cc-by-nc-sa-image]: https://licensebuttons.net/l/by-nc-sa/4.0/88x31.png
214
+ [cc-by-nc-sa-shield]: https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-lightgrey.svg
215
+
216
+ Contributions must follow the Contributor License Agreement. For more information, see the CONTRIBUTING.md file at the top of the GitHub repository.
217
+
218
+ Copyright © 2024 Forschungszentrum Jülich GmbH - Central Institute of Engineering, Electronics and Analytics (ZEA) - Electronic Systems (ZEA-2)
@@ -1,36 +1,37 @@
1
- simcats/__init__.py,sha256=h98g7mCms0R2D4fupAVJ6N3jYksIUQs3jnQiqxBE1lo,300
1
+ simcats/__init__.py,sha256=pnTS1t8IQKm2SpadtblS8VKUFKm0OfBkiT7rQGzj8Ws,300
2
2
  simcats/_default_configs.py,sha256=wHWa4wyTVtZf9J37WdcMlvM7XeI_OZhl8NB7lrBi-yI,6980
3
3
  simcats/_simulation.py,sha256=xvKLnOzwc8uGGLfXvBZPaLYYPHBaXcwwtlYmJ3zTkUU,24795
4
4
  simcats/distortions/__init__.py,sha256=3oXqKm1rkznDKhWeitZxYJyb1wFMdan6CBfBw673J7A,1368
5
5
  simcats/distortions/_distortion_interfaces.py,sha256=8twWE8FX8fqiLlxrcSOBaMZCc3boDbE6n_b4587-ra4,6717
6
- simcats/distortions/_dot_jumps.py,sha256=ER-HOVRHLS7Uvivm9YYxNNmm9-mcsugDc_oOUftddyk,37971
6
+ simcats/distortions/_dot_jumps.py,sha256=6segzH8VWaUlRPMcWjkDacwyCcN8bPhfWyrYQD8UaoA,38162
7
7
  simcats/distortions/_pink_noise.py,sha256=2-ZvNAvtsypNHqLXN_FfGR-iWnAGgXWZxTS7LKk73pQ,5233
8
8
  simcats/distortions/_random_telegraph_noise.py,sha256=psRV-tosDXHC0xBSZyrKZAgRBMQoxSeeDTRIpUsJ9hg,16785
9
9
  simcats/distortions/_transition_blurring.py,sha256=3kryfx3VEnJpAgPfoJF-Z4leoSFrzGUwf-5mb8bXD3o,13631
10
10
  simcats/distortions/_white_noise.py,sha256=toxal_V2aPxxqoxpsJz3-lH7rtNjzsz5aoTbgNhiWxU,4413
11
- simcats/ideal_csd/__init__.py,sha256=cC6IQre0RyoqH0yZ6AxvOKPQCcdb2D_gb0hMQBYYl6o,310
11
+ simcats/ideal_csd/__init__.py,sha256=jxQkBf_z1xIclUcqeur6OVzrFJhd9eAXFF9PJdb091I,316
12
12
  simcats/ideal_csd/_ideal_csd_interface.py,sha256=3PjLgv_MjIlN2YqbpLwrJysukntftZSBCrBBPwe0HSA,2334
13
13
  simcats/ideal_csd/geometric/__init__.py,sha256=uXqR4qGbBcTQ8WdIO56ZxHWXqbn85yvuVlm5zJV7iVc,927
14
14
  simcats/ideal_csd/geometric/_calculate_all_bezier_anchors.py,sha256=AvSsOsiu5H3HKoJwwZ1797T3yHoRc6Rj2YT-JJujaIY,6491
15
15
  simcats/ideal_csd/geometric/_generate_lead_transition_mask.py,sha256=QOYSNSy5IHiNefmC37KsuM3484xJfsl8yNeo4o5Xdws,6316
16
16
  simcats/ideal_csd/geometric/_get_electron_occupation.py,sha256=rEW9guTxM4pTGy9vtQ34NP4zxRaMNk-LQstfCkq4OEw,13461
17
- simcats/ideal_csd/geometric/_ideal_csd_geometric.py,sha256=xgQG668sJAFPM9VDUULPhgqpK4XpY-m09Rt27WJBgEE,17180
17
+ simcats/ideal_csd/geometric/_ideal_csd_geometric.py,sha256=gpYVgRx_rRB46FyaKntg9CWIpGSP4uroJGeyeufmoKE,10077
18
+ simcats/ideal_csd/geometric/_ideal_csd_geometric_class.py,sha256=Qx1IQy4NX4gtkFQGBaQRxjW46urv95mMQI_enWRUl4M,7481
18
19
  simcats/ideal_csd/geometric/_initialize_tct_functions.py,sha256=z1rCkKLM68e97xQkdwnUq5DGuCkHiOADRfwiDb2I3kE,3161
19
- simcats/ideal_csd/geometric/_tct_bezier.py,sha256=R7MiaUHosB0CJjGtPnz6GO50rj6lcYpVD2-_RExCDj0,11711
20
+ simcats/ideal_csd/geometric/_tct_bezier.py,sha256=xDBlEylwYvnX-xOdUt-N7P7k9i0yzTce9b3dXZa_Zx4,12067
20
21
  simcats/sensor/__init__.py,sha256=v9aG6_WGYF5Dq_OFHHn2NQxZx2X2HGg0nkglz5wSoHw,611
21
22
  simcats/sensor/_gaussian_sensor_peak.py,sha256=7xrSfl505MygBJ7Nu3V3RJpNq8q-mjukVDcrL-ezEuA,4039
22
23
  simcats/sensor/_generic_sensor.py,sha256=88E6xP3r5GZCBKaR7TKtqrWovR4XW-mm6YUwL96L_AQ,10441
23
24
  simcats/sensor/_lorentzian_sensor_peak.py,sha256=Rj3Tpk6dksZGfOAHhdSGQR-wJo3ehdmXnumXyGuaNC4,3952
24
25
  simcats/sensor/_sensor_interface.py,sha256=mn5L9WbAIMun_ou0AHgOV6XiBeykYPugndLAeufadTo,5064
25
- simcats/support_functions/__init__.py,sha256=xkd9-ko2AW26m0_Ae4O4irdclym6fY0qP9Ku3-RZrVo,982
26
+ simcats/support_functions/__init__.py,sha256=6aXPXtvcaL4bcOADy1yWhhyehT6BDs3Yt_3uOFbBE50,1086
26
27
  simcats/support_functions/_cumulative_distribution_functions.py,sha256=pE01RoSL2VwtkBP7xYivd-vcd6krSJrb4xb8MCfyRBA,3366
27
28
  simcats/support_functions/_fermi_filter1d.py,sha256=F4GrdLt0bOXidRdg0P-163Op-bxKvgHte3ENI39qYAk,3706
28
- simcats/support_functions/_parameter_sampling.py,sha256=APtgokKp-WIFKBrJeZy7fLJ-OiUkhXIeXTn9kPEVyYE,6157
29
+ simcats/support_functions/_parameter_sampling.py,sha256=xEd4V0bUqpkE5DpZA0i1YNe8G86IZP1LB2dmkFTg3l0,15331
29
30
  simcats/support_functions/_plotting.py,sha256=xc050m4W6RZm8XdOdqruc-6IYyhzW9UFvNlJEgkJRi8,9070
30
31
  simcats/support_functions/_rotate_points.py,sha256=4tgzE4a4uykBVw2pSK55DzGe-5n9N38nsBYhfA38Qgs,778
31
32
  simcats/support_functions/_signed_dist_points_line.py,sha256=dMnDoBARY7C48xCHFp8mNFNCkPk7YUiaWaRqAsindsE,908
32
- simcats-1.0.0.dist-info/LICENSE,sha256=aZs_e2FTt6geKaC1hd9FpoxERpb5YHhxJ608urp4nig,21294
33
- simcats-1.0.0.dist-info/METADATA,sha256=VflEB_fpiX0r0eC1OrCMEluhFI1s_j_1ONKvU5_sW44,10999
34
- simcats-1.0.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
35
- simcats-1.0.0.dist-info/top_level.txt,sha256=M-ExkkJ_NLsuuJiDo3iM2qPPPsEX29E2MQUmegBZ8Wk,8
36
- simcats-1.0.0.dist-info/RECORD,,
33
+ simcats-1.2.0.dist-info/LICENSE,sha256=aZs_e2FTt6geKaC1hd9FpoxERpb5YHhxJ608urp4nig,21294
34
+ simcats-1.2.0.dist-info/METADATA,sha256=QFMyj-AF9-K0_0u5mnPbCO1AXlB7l0gJqTDuIdT3ixg,11918
35
+ simcats-1.2.0.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
36
+ simcats-1.2.0.dist-info/top_level.txt,sha256=M-ExkkJ_NLsuuJiDo3iM2qPPPsEX29E2MQUmegBZ8Wk,8
37
+ simcats-1.2.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.42.0)
2
+ Generator: setuptools (75.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,187 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: simcats
3
- Version: 1.0.0
4
- Summary: SimCATS is a python framework for simulating charge stability diagrams (CSDs) typically measured during the tuning process of qubits.
5
- Author-email: Fabian Hader <f.hader@fz-juelich.de>, Sarah Fleitmann <s.fleitmann@fz-juelich.de>, Fabian Fuchs <f.fuchs@fz-juelich.de>
6
- License: CC BY-NC-SA 4.0
7
- Project-URL: homepage, https://github.com/f-hader/SimCATS
8
- Project-URL: documentation, https://simcats.readthedocs.io
9
- Project-URL: source, https://github.com/f-hader/SimCATS
10
- Project-URL: tracker, https://github.com/f-hader/SimCATS/issues
11
- Classifier: Development Status :: 5 - Production/Stable
12
- Classifier: Intended Audience :: Science/Research
13
- Classifier: Programming Language :: Python
14
- Classifier: Programming Language :: Python :: 3
15
- Classifier: Programming Language :: Python :: 3.7
16
- Classifier: Programming Language :: Python :: 3.8
17
- Classifier: Programming Language :: Python :: 3.9
18
- Classifier: Programming Language :: Python :: 3.10
19
- Classifier: Programming Language :: Python :: 3.11
20
- Classifier: Topic :: Scientific/Engineering
21
- Classifier: Typing :: Typed
22
- Requires-Python: >=3.7
23
- Description-Content-Type: text/markdown
24
- License-File: LICENSE
25
- Requires-Dist: bezier
26
- Requires-Dist: colorednoise
27
- Requires-Dist: diplib
28
- Requires-Dist: matplotlib
29
- Requires-Dist: numpy
30
- Requires-Dist: opencv-python
31
- Requires-Dist: scipy
32
- Requires-Dist: sympy
33
-
34
- # SimCATS
35
-
36
- Simulation of CSDs for Automated Tuning Solutions (`SimCATS`) is a python framework for simulating charge stability
37
- diagrams (CSDs) typically measured during the tuning process of qubits.
38
-
39
- ## Installation
40
-
41
- The framework supports python versions 3.7 - 3.11 and can be installed with pip:
42
- ```
43
- pip install simcats
44
- ```
45
-
46
- Alternatively, the `SimCATS` package can be installed by cloning the GitHub repository, navigating to the folder
47
- containing the `setup.py` file and executing
48
-
49
- ```
50
- pip install .
51
- ```
52
-
53
- For installation in development/editable mode use the option `-e`.
54
-
55
- ## Examples / Tutorials
56
- After the package is installed, a good starting point is a look into the Jupyter Notebook
57
- `example_SimCATS_simulation_class.ipynb`, which provides an overview for the usage of the simulation class offered by
58
- the framework.
59
- For more detailed examples and explanations of the geometric ideal CSD simulation using Total Charge Transitions (TCTs),
60
- have a look at the Jupyter Notebook `example_SimCATS_IdealCSDGeometric.ipynb`. This notebook also includes a hint
61
- regarding the generation of required labels for training algorithms, that might need line labels defined as start and
62
- end points or require semantic information about particular transitions.
63
-
64
- ## Tests
65
-
66
- The test are written for the `PyTest` framework but should also work with the `unittest` framework.
67
-
68
- To run the tests install the packages `pytest`, `pytest-cov` and `pytest-xdist` with
69
-
70
- ```
71
- pip install pytest pytest-cov pytest-xdist
72
- ```
73
-
74
- and then simply run following command in the terminal of your choice:
75
-
76
- ```
77
- pytest --cov=simcats -n auto --dist loadfile .\tests\
78
- ```
79
-
80
- The argument `--cov=simcats` enables a coverage summary of the `SimCATS` package, the argument `-n auto` enables the
81
- test to run with multiple threads (auto will choose as many threads as possible, but can be replaced with a specific
82
- number of threads to use) and the argument `--dist loadfile` specifies that each file should be executed only by one
83
- thread.
84
-
85
- <!-- start sec:documentation -->
86
- ## Documentation
87
-
88
- The official documentation is hosted on [ReadtheDocs](https://simcats.readthedocs.io), but can also be build locally.
89
- To do this, first install the packages `sphinx`, `sphinx-rtd-theme`, `sphinx-autoapi`,`myst-nb ` and `jupytext` with
90
-
91
- ```
92
- pip install sphinx sphinx-rtd-theme sphinx-autoapi myst-nb jupytext
93
- ```
94
-
95
- and then, in the `docs` folder, execute the following command in a terminal of your choice:
96
-
97
- ```
98
- .\make html
99
- ```
100
-
101
- To view the generated HTML documentation open the file `docs\build\html\index.html` with a browser of your choice.
102
- <!-- end sec:documentation -->
103
-
104
- ## Structure of SimCATS
105
-
106
- The main user interface for `SimCATS` is the class `Simulation`, which combines all the necessary functionalities to
107
- measure (simulate) a CSD and to adjust the parameters for the simulated measurement. The class `Simulation` and default
108
- configurations for the simulation (`default_configs`) can be imported directly from `simcats`. Asides from that,
109
- `SimCATS` contains the subpackages `ideal_csd`, `sensor`, `distortions`, and `support_functions`. These are described in
110
- the following sections.
111
-
112
- ### Module `simulation`
113
-
114
- An instance of the simulation class requires
115
-
116
- - an implementation of the `IdealCSDInterface` for the simulation of ideal CSD data,
117
- - an implementation of the `SensorInterface` for the simulation of the sensor (dot) reaction based on the ideal CSD
118
- data, and
119
- - (optionally) implementations of the desired types of distortions, which can be implementations from either
120
- `OccupationDistortionInterface`, `SensorPotentialDistortionInterface`, or `SensorResponseDistortionInterface`.
121
-
122
- With an initialized instance of the `Simulation` class it is possible to run simulations using the `measure` function
123
- (see `example_SimCATS_simulation_class.ipynb`).
124
-
125
- ### Subpackage `ideal_csd`
126
-
127
- This subpackage contains the `IdealCSDInterface`, that is used by the `Simulation` class for the generation of ideal CSD
128
- data, and an implementation of the `IdealCSDInterface` (`IdealCSDGeometric`) based on our geometric simulation approach.
129
- Additionally, in the subpackage `geometric`, it contains the functions used by `IdealCSDGeometric`, including the
130
- implementation of the total charge transition (TCT) definition and functions for calculating the occupations using TCTs.
131
-
132
- ### Subpackage `distortions`
133
-
134
- The distortions subpackage contains the `DistortionInterface` from which the `OccupationDistortionInterface`, the
135
- `SensorPotentialDistortionInterface`, and the `SensorResponseDistortionInterface` are derived. Distortion functions used
136
- in the `Simulation` class have to implement these specific interfaces. Implemented distortions included in the
137
- subpackage are:
138
-
139
- - white noise, generated by sampling from a normal distribution,
140
- - pink noise, generated using the package colorednoise ([https://github.com/felixpatzelt/colorednoise](https://github.com/felixpatzelt/colorednoise)),
141
- - random telegraph noise (RTN), generated using the algorithm described in ["Toward Robust Autotuning of Noisy Quantum Dot Devices" by Ziegler et al.](https://doi.org/10.1103/PhysRevApplied.17.024069) (RTN is called sensor jumps there),
142
- - dot jumps, simulated using the algorithm described in ["Toward Robust Autotuning of Noisy Quantum Dot Devices" by Ziegler et al.](https://doi.org/10.1103/PhysRevApplied.17.024069) (In the `Simulation` class this is applied to a whole block of rows or columns, but there is also a function for applying it linewise.), and
143
- - lead transition blurring, simulated using gaussian blurring.
144
-
145
- The implementations also offer the option to set ratios (parameter `ratio`), for how often the distortion is active
146
- (f.e. dot jumps may only happen sometimes and not in every measurement). Moreover, it is also possible to sample the
147
- noise parameters from a given sampling range. This can be done by using an object of type `ParameterSamplingInterface`.
148
- Classes for randomly sampling from a normal distribution or a uniform distribution within a given range are available in
149
- the subpackage `support_functions`.
150
- In this case the strength is randomly chosen from the given range for every measurement.
151
- Additionally, it is possible to specify, that this range should be a smaller subrange of the provided range.
152
- This allows to restrict distortion fluctuations during a simulation while allowing a large variety of different strengths
153
- for the initialization of the objects. <br>
154
- RTN, dot jumps and lead transition blurring are applied in the pixel domain. However, the length of jumps or the strength
155
- of the blurring should be consistent in the voltage domain even if the resolution changes. Therefore, the parameters
156
- are given in the voltage domain and adjusted according to the resolution in terms of pixel per voltage. <br>
157
- If a measurement with a continuous voltage sweep and averaging for each pixel is simulated, the noise strength of the white and pink noise should be adjusted if the resolution (volt per pixel) changes, as some of the noise is smoothed out. This smoothing depends on the type of averaging that is used and is not incorporated in the default implementation.
158
-
159
- ### Subpackage `sensor`
160
-
161
- This subpackage contains the `SensorInterface` that defines how a sensor simulation must be implemented to be used by the `Simulation` class. The `SensorPeakInterface` provides the desired representation for the definition of the Coulomb peaks used by the sensor. `SensorGeneric` implements the `SensorInterface` and offers functions for simulating the sensor response and the sensor potential. It offers the possibility to simulate with a single or multiple sensor peaks. Current implementations of the `SensorPeakInterface` are `SensorPeakGaussian` and `SensorPeakLorentzian`.
162
-
163
- ### Subpackage `support_functions`
164
-
165
- This subpackage contains support functions, which are used by the end user as well as from different functions of the framework.
166
- - `fermi_filter1d` is an implementation of a one dimensional Fermi-Dirac filter.
167
- - `plot_csd` is a function for plotting one and two-dimensional CSDs. The function can also be used to plot ground truth data (see `example_SimCATS_simulation_class.ipynb` for examples).
168
- - `rotate_points` is a function for simply rotating coordinates (stored in a (n, 2) shaped array) by a given angle. This is especially used during the generation of the ideal data.
169
- - `ParameterSamplingInterface` defines an interface that can be implemented for randomly sampling (fluctuating) strengths of distortions.
170
- - `NormalSamplingRange` and `UniformSamplingRange` are implementations of the `ParameterSamplingInterface`.
171
-
172
- ## License, CLA, and Copyright
173
-
174
- [![CC BY-NC-SA 4.0][cc-by-nc-sa-shield]][cc-by-nc-sa]
175
-
176
- This work is licensed under a
177
- [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License][cc-by-nc-sa].
178
-
179
- [![CC BY-NC-SA 4.0][cc-by-nc-sa-image]][cc-by-nc-sa]
180
-
181
- [cc-by-nc-sa]: http://creativecommons.org/licenses/by-nc-sa/4.0/
182
- [cc-by-nc-sa-image]: https://licensebuttons.net/l/by-nc-sa/4.0/88x31.png
183
- [cc-by-nc-sa-shield]: https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-lightgrey.svg
184
-
185
- Contributions must follow the Contributor License Agreement. For more information see the CONTRIBUTING.md file at the top level of the GitHub repository.
186
-
187
- Copyright © 2023 Forschungszentrum Jülich GmbH - Central Institute of Engineering, Electronics and Analytics (ZEA) - Electronic Systems (ZEA-2)