spin-pulse 1.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.
spin_pulse/__init__.py ADDED
@@ -0,0 +1,41 @@
1
+ # --------------------------------------------------------------------------------------
2
+ # This code is part of SpinPulse.
3
+ #
4
+ # (C) Copyright Quobly 2025.
5
+ #
6
+ # This code is licensed under the Apache License, Version 2.0. You may
7
+ # obtain a copy of this license in the LICENSE.txt file in the root directory
8
+ # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
9
+ #
10
+ # Any modifications or derivative works of this code must retain this
11
+ # copyright notice, and modified files need to carry a notice indicating
12
+ # that they have been altered from the originals.
13
+ # --------------------------------------------------------------------------------------
14
+ """
15
+ :mod:`SpinPulse` is an open-source python package for simulating silicon based spin qubits at the pulse-level.
16
+
17
+ Modules
18
+ ----------------
19
+ :mod:`spin_pulse.transpilation`
20
+ The `transpilation` module provides a set of classes that enable the simulation of quantum circuits defined in `Qiskit` on silicon-based spin-qubit hardware models.
21
+
22
+ :mod:`spin_pulse.environment`
23
+ The `environment` module provides a set of classes for defining and configuring a quantum experimental environment tailored to spin-qubit systems.
24
+
25
+ :mod:`spin_pulse.characterization`
26
+ The `characterization` module provides a set of functions for characterizing spin-qubit control operations and quantifying noise strength.
27
+
28
+ """
29
+
30
+ from .environment.experimental_environment import ExperimentalEnvironment
31
+ from .transpilation.dynamical_decoupling import DynamicalDecoupling
32
+ from .transpilation.hardware_specs import HardwareSpecs, Shape
33
+ from .transpilation.pulse_circuit import PulseCircuit
34
+
35
+ __all__ = [
36
+ "DynamicalDecoupling",
37
+ "ExperimentalEnvironment",
38
+ "HardwareSpecs",
39
+ "PulseCircuit",
40
+ "Shape",
41
+ ]
@@ -0,0 +1,16 @@
1
+ # --------------------------------------------------------------------------------------
2
+ # This code is part of SpinPulse.
3
+ #
4
+ # (C) Copyright Quobly 2025.
5
+ #
6
+ # This code is licensed under the Apache License, Version 2.0. You may
7
+ # obtain a copy of this license in the LICENSE.txt file in the root directory
8
+ # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
9
+ #
10
+ # Any modifications or derivative works of this code must retain this
11
+ # copyright notice, and modified files need to carry a notice indicating
12
+ # that they have been altered from the originals.
13
+ # --------------------------------------------------------------------------------------
14
+ """This module provides a set of functions for characterizing spin-qubit control operations and quantifying noise intensity.
15
+ It includes methods for performing Ramsey experiments, comparing quantum circuits, and computing average quantum channels.
16
+ """
@@ -0,0 +1,219 @@
1
+ # --------------------------------------------------------------------------------------
2
+ # This code is part of SpinPulse.
3
+ #
4
+ # (C) Copyright Quobly 2025.
5
+ #
6
+ # This code is licensed under the Apache License, Version 2.0. You may
7
+ # obtain a copy of this license in the LICENSE.txt file in the root directory
8
+ # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
9
+ #
10
+ # Any modifications or derivative works of this code must retain this
11
+ # copyright notice, and modified files need to carry a notice indicating
12
+ # that they have been altered from the originals.
13
+ # --------------------------------------------------------------------------------------
14
+ """
15
+ Utilities to analyze and visualize quantum super-Operators.
16
+ """
17
+
18
+ import itertools
19
+
20
+ import matplotlib as mpl
21
+ import matplotlib.pyplot as plt
22
+ import numpy as np
23
+ import qiskit as qi
24
+ from qiskit.quantum_info import (
25
+ Chi,
26
+ Operator,
27
+ Pauli,
28
+ SuperOp,
29
+ )
30
+
31
+
32
+ def compare_circuits(circ1: qi.QuantumCircuit, circ2: qi.QuantumCircuit):
33
+ """
34
+ Compare two quantum circuits by plotting the matrix elements of their
35
+ corresponding unitary operators.
36
+
37
+ This function converts both circuits into unitary matrices using
38
+ qiskit.quantum_info.Operator.
39
+ The global phase is removed before comparison. Three scatter plots are
40
+ generated: real parts, imaginary parts, and absolute values of the matrix
41
+ elements. A diagonal reference line is shown, and the squared distance
42
+ between the two matrices is displayed.
43
+
44
+ Parameters:
45
+ circ1 (qiskit.QuantumCircuit): First circuit to compare.
46
+ circ2 (qiskit.QuantumCircuit): Second circuit to compare.
47
+
48
+ Notes:
49
+ The global phase is aligned using the matrix element with maximum magnitude.
50
+ This function is useful to visually validate the equivalence of two circuits
51
+ after transformations such as transpilation or pulse compilation.
52
+
53
+ """
54
+ data1 = (Operator.from_circuit(circ1).data).flatten()
55
+ data2 = (Operator.from_circuit(circ2).data).flatten()
56
+ i_phase = np.argmax(abs(data1))
57
+ phase1 = np.angle(data1[i_phase])
58
+ data1 *= np.exp(-1j * phase1)
59
+ phase2 = np.angle(data2[i_phase])
60
+ data2 *= np.exp(-1j * phase2)
61
+ plt.plot(np.real(data1), np.real(data2), "o", label="real")
62
+ plt.plot(np.imag(data1), np.imag(data2), "x", label="imag")
63
+ plt.plot(np.abs(data1), np.abs(data2), "*", label="abs")
64
+
65
+ a = np.max(abs(data1))
66
+ plt.plot([-a, a], [-a, a], "--k")
67
+ plt.text(-a, a, f"distance {np.sum(np.abs(data1 - data2) ** 2)}")
68
+ plt.xlabel("circ 1 matrix elements")
69
+ plt.ylabel("circ 2 matrix elements")
70
+ plt.legend(loc=0)
71
+
72
+
73
+ def plot_chi_matrix(superop: dict[str, SuperOp], threshold=None) -> plt.Figure:
74
+ """Plot the chi-matrix elements for one or multiple quantum superop.
75
+
76
+ The chi-matrix is computed for each channel and plotted as bar plots
77
+ (real and imaginary parts). If a threshold is provided, only elements
78
+ with absolute value greater than the threshold (from the first channel)
79
+ are shown.
80
+
81
+ Channels whose key contains the substring ``"analytical"`` are plotted
82
+ with transparent bars and line styles, while the others are plotted as
83
+ semi-transparent filled bars.
84
+
85
+ Parameters:
86
+ superop (dict[str, qiskit.quantum_info.SuperOp or qiskit.quantum_info.Channel]):
87
+ Dictionary mapping labels to quantum super-Operator. Each value must
88
+ be compatible with ``qiskit.quantum_info.Choi``/``Chi`` so that
89
+ ``Chi(superop[key]).data`` returns the chi-matrix.
90
+ threshold (float | None): If not ``None``, only chi-matrix elements with
91
+ absolute value greater than ``threshold`` (as determined from the
92
+ first channel in ``superop``) are included in the plot.
93
+
94
+ Returns:
95
+ matplotlib.figure.Figure: The figure object containing the chi-matrix plot.
96
+
97
+ """
98
+ n_qb = int(np.log2(next(iter(superop.values())).data.shape[0]) / 2)
99
+ mpl.rcParams["font.size"] = 22
100
+ fig = plt.figure(figsize=(10, 5))
101
+ # Generate Pauli basis labels
102
+ paulis = ["I", "X", "Y", "Z"]
103
+ pauli_labels = ["".join(p) for p in itertools.product(paulis, repeat=n_qb)]
104
+ full_labels = [f"${p1}.{p2}$" for p1 in pauli_labels for p2 in pauli_labels]
105
+
106
+ counter = 0
107
+ lines_style = ["-", "--", ":", "-."]
108
+
109
+ x = np.arange(len(full_labels))
110
+
111
+ for index, key in enumerate(superop.keys()):
112
+ chi_matrix = Chi(superop[key]).data
113
+
114
+ # Flatten matrix into list of values and labels
115
+ values = chi_matrix.flatten()
116
+
117
+ if threshold is not None and index == 0:
118
+ indices = [i for i in range(len(values)) if np.abs(values[i]) > threshold]
119
+ x = np.array(range(len(indices)))
120
+ full_labels = [full_labels[i] for i in indices]
121
+ if threshold is not None:
122
+ values = values[indices]
123
+
124
+ if "analytical" in key:
125
+ plt.bar(
126
+ x,
127
+ np.real(values),
128
+ tick_label=full_labels,
129
+ label=f"{key}" + " (real)",
130
+ facecolor="none",
131
+ edgecolor="tab:blue",
132
+ linestyle=lines_style[counter % len(lines_style)],
133
+ linewidth=1.0,
134
+ )
135
+ plt.bar(
136
+ x,
137
+ np.imag(values),
138
+ tick_label=full_labels,
139
+ label=f"{key}" + " (imag)",
140
+ facecolor="none",
141
+ edgecolor="tab:orange",
142
+ linestyle=lines_style[counter % len(lines_style)],
143
+ linewidth=1.0,
144
+ )
145
+ counter += 1
146
+
147
+ else:
148
+ plt.bar(
149
+ x,
150
+ np.real(values),
151
+ alpha=0.3,
152
+ tick_label=full_labels,
153
+ label=f"{key}" + " (real)",
154
+ )
155
+ plt.bar(
156
+ x,
157
+ np.imag(values),
158
+ alpha=0.3,
159
+ tick_label=full_labels,
160
+ label=f"{key}" + " (imag)",
161
+ )
162
+
163
+ plt.xticks(rotation=90)
164
+ plt.ylabel(r"$\chi$")
165
+ plt.legend()
166
+ plt.grid(True, axis="y", linestyle="--", alpha=0.5)
167
+ plt.tight_layout()
168
+ return fig
169
+
170
+
171
+ def get_superop_from_paulidict(pauli_dict: dict[str, complex]) -> SuperOp:
172
+ r"""Return the SuperOp corresponding to a Pauli decomposition given as
173
+ a dictionary.
174
+
175
+ The input is a mapping from tensor-product Pauli labels (e.g., "IXZ",
176
+ "ZZ", "I") to complex coefficients. For an n-qubit system, each label
177
+ must be a string of length n, with characters drawn from
178
+ ``{"I", "X", "Y", "Z"}``.
179
+
180
+ The function builds the operator
181
+
182
+ .. math::
183
+
184
+ O = \sum_{P} c_P P,
185
+
186
+ where :math:`P` runs over Pauli strings and :math:`c_P` are the provided
187
+ coefficients, and then wraps it as a ``qiskit.quantum_info.SuperOp``.
188
+
189
+ Parameters:
190
+ pauli_dict (dict[str, complex]): Dictionary mapping Pauli labels
191
+ (e.g., "IX", "ZZI") to complex coefficients.
192
+
193
+ Returns:
194
+ qiskit.quantum_info.SuperOp: The resulting quantum channel represented
195
+ as a ``SuperOp`` acting on the corresponding Hilbert space dimension.
196
+
197
+ """
198
+ keys = list(pauli_dict.keys())
199
+
200
+ # Validate that all keys are even in Pauli matrices
201
+ for i in range(len(keys)):
202
+ if len(keys[i]) % 2 != 0:
203
+ raise ValueError(
204
+ "All Pauli keys must have an even number of single-qubit Pauli matrices "
205
+ f"(got {len(keys[i])})."
206
+ )
207
+ # Validate that all keys have the same length
208
+ for i in range(1, len(keys)):
209
+ if len(keys[i - 1]) != len(keys[i]):
210
+ raise ValueError(
211
+ "All keys must have the same length "
212
+ f"(got {len(keys[i - 1])} and {len(keys[i])})."
213
+ )
214
+
215
+ super_ops = []
216
+ for label, coeff in pauli_dict.items():
217
+ P = Pauli(label)
218
+ super_ops.append(coeff * SuperOp(P.to_matrix()))
219
+ return sum(super_ops)
@@ -0,0 +1,120 @@
1
+ # --------------------------------------------------------------------------------------
2
+ # This code is part of SpinPulse.
3
+ #
4
+ # (C) Copyright Quobly 2025.
5
+ #
6
+ # This code is licensed under the Apache License, Version 2.0. You may
7
+ # obtain a copy of this license in the LICENSE.txt file in the root directory
8
+ # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
9
+ #
10
+ # Any modifications or derivative works of this code must retain this
11
+ # copyright notice, and modified files need to carry a notice indicating
12
+ # that they have been altered from the originals.
13
+ # --------------------------------------------------------------------------------------
14
+ """Helper functions to carry out Ramsey experiments."""
15
+
16
+ import numpy as np
17
+ import qiskit as qi
18
+ from qiskit.quantum_info import Operator
19
+ from tqdm import tqdm
20
+
21
+ from ..environment.experimental_environment import ExperimentalEnvironment
22
+ from ..transpilation.hardware_specs import HardwareSpecs
23
+ from ..transpilation.pulse_circuit import PulseCircuit
24
+
25
+
26
+ def get_ramsey_circuit(
27
+ duration: int,
28
+ hardware_specs: HardwareSpecs,
29
+ exp_env: ExperimentalEnvironment | None = None,
30
+ ):
31
+ """Construct a pulse-level Ramsey experiment.
32
+
33
+ This function builds a single-qubit Ramsey sequence consisting of a
34
+ Hadamard gate, an idle period of a specified duration, and a second
35
+ Hadamard gate. The circuit is transpiled into the hardware native gate
36
+ set and converted into a PulseCircuit. If an experimental environment is
37
+ provided, noise time traces are attached to the resulting pulse-level
38
+ circuit.
39
+
40
+ Parameters:
41
+ duration (int): Duration of the free-evolution period (in the discrete
42
+ time unit used by the hardware model).
43
+ hardware_specs (HardwareSpecs): Hardware configuration used to
44
+ transpile the logical Ramsey sequence into native instructions, and
45
+ to generate the pulse sequences of the PulseCircuit.
46
+ exp_env (ExperimentalEnvironment | None): Optional noise environment
47
+ from which time traces are created and attached to the PulseCircuit.
48
+
49
+ Returns:
50
+ PulseCircuit: Pulse-level representation of the Ramsey experiment,
51
+ optionally including noise time traces.
52
+
53
+ """
54
+ qreg = qi.QuantumRegister(1)
55
+ circ = qi.QuantumCircuit(qreg)
56
+ circ.h(0)
57
+ circ.delay(int(duration))
58
+
59
+ circ.h(0)
60
+ isa_circ = hardware_specs.gate_transpile(circ)
61
+ pulse_circuit = PulseCircuit.from_circuit(isa_circ, hardware_specs, exp_env=exp_env)
62
+ return pulse_circuit
63
+
64
+
65
+ def get_contrast(pulse_circuit: PulseCircuit) -> float:
66
+ """Compute the population contrast of a Ramsey experiment.
67
+
68
+ The pulse-level circuit is converted back to a unitary qiskit.QuantumCircuit,
69
+ and the resulting unitary matrix is applied to the input state 0.
70
+ The contrast is defined as the population difference between state 0
71
+ and state 1, that is: C = P0 - P1
72
+
73
+ Parameters:
74
+ pulse_circuit (PulseCircuit): Pulse-level Ramsey circuit.
75
+
76
+ Returns:
77
+ float: Population contrast.
78
+
79
+ """
80
+
81
+ circ = pulse_circuit.to_circuit()
82
+ unitary = Operator(circ).to_matrix()
83
+ statevector = unitary[:, 0]
84
+ return np.abs(statevector[0]) ** 2 - np.abs(statevector[1]) ** 2
85
+
86
+
87
+ def get_average_ramsey_contrast(
88
+ hardware_specs: HardwareSpecs,
89
+ exp_env: ExperimentalEnvironment,
90
+ durations: list[int],
91
+ ):
92
+ """Compute the average Ramsey contrast over multiple noise realizations.
93
+
94
+ For each free-evolution duration given, a Ramsey pulse circuit is constructed
95
+ and its population contrast is computed by averaging over multiple noise
96
+ realizations drawn from the experimental environment. After each duration,
97
+ the environment time traces are regenerated to ensure independence
98
+ between samples.
99
+
100
+ Parameters:
101
+ hardware_specs (HardwareSpecs): Hardware configuration used to
102
+ construct pulse-level Ramsey circuits.
103
+ exp_env (ExperimentalEnvironment): Noise environment providing time
104
+ traces for each sample.
105
+ durations (list[int]): List of free-evolution durations for which the
106
+ Ramsey contrast is evaluated.
107
+
108
+ Returns:
109
+ np.ndarray: Array containing the average Ramsey contrast for each
110
+ duration in ``durations``.
111
+
112
+ """
113
+ nbp = len(durations)
114
+ average_contrast = np.zeros(nbp)
115
+ for j in tqdm(range(nbp)):
116
+ ramsey_circ = get_ramsey_circuit(durations[j], hardware_specs)
117
+ average_contrast[j] = ramsey_circ.averaging_over_samples(get_contrast, exp_env)
118
+ # regenerate new time traces for the next duration
119
+ exp_env.generate_time_traces()
120
+ return average_contrast
@@ -0,0 +1,23 @@
1
+ # --------------------------------------------------------------------------------------
2
+ # This code is part of SpinPulse.
3
+ #
4
+ # (C) Copyright Quobly 2025.
5
+ #
6
+ # This code is licensed under the Apache License, Version 2.0. You may
7
+ # obtain a copy of this license in the LICENSE.txt file in the root directory
8
+ # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
9
+ #
10
+ # Any modifications or derivative works of this code must retain this
11
+ # copyright notice, and modified files need to carry a notice indicating
12
+ # that they have been altered from the originals.
13
+ # --------------------------------------------------------------------------------------
14
+ """
15
+ The `environment` module provides a set of classes for defining and configuring a quantum experimental environment tailored to spin-qubit systems.
16
+
17
+ - :mod:`spin_pulse.environment.experimental_environment`, defines the `Environment` class that contains a quantum experimental environment with configurable noise models.
18
+
19
+ The submodule :mod:`spin_pulse.environment.noise` provides a set of noise classes for simulating different noise processes:
20
+ - QUASISTATIC: Quasistatic noise generated by `QuasistaticNoiseTimeTrace`.
21
+ - PINK: Pink (1/f) noise generated by `PinkNoiseTimeTrace`.
22
+ - WHITE: White Gaussian noise generated by `WhiteNoiseTimeTrace`.
23
+ """
@@ -0,0 +1,158 @@
1
+ # --------------------------------------------------------------------------------------
2
+ # This code is part of SpinPulse.
3
+ #
4
+ # (C) Copyright Quobly 2025.
5
+ #
6
+ # This code is licensed under the Apache License, Version 2.0. You may
7
+ # obtain a copy of this license in the LICENSE.txt file in the root directory
8
+ # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
9
+ #
10
+ # Any modifications or derivative works of this code must retain this
11
+ # copyright notice, and modified files need to carry a notice indicating
12
+ # that they have been altered from the originals.
13
+ # --------------------------------------------------------------------------------------
14
+ """Description of the noisy environment associated to a hardware."""
15
+
16
+ from ..transpilation.hardware_specs import HardwareSpecs
17
+ from .noise import (
18
+ NoiseType,
19
+ PinkNoiseTimeTrace,
20
+ QuasistaticNoiseTimeTrace,
21
+ WhiteNoiseTimeTrace,
22
+ )
23
+
24
+
25
+ class ExperimentalEnvironment:
26
+ """
27
+ Contain a quantum experimental environment with configurable noise models.
28
+
29
+ Attributes:
30
+ - hardware_specs (class): HardwareSpecs class, that defines the hardware settings.
31
+ - noise_type (NoiseType): Type of noise to simulate. Must be "pink", "white", or "quasistatic".
32
+ - T2S (float): Characteristic time of individual qubits.
33
+ - TJS (float or None): Characteristic time of coupled two-qubit system at maximal J coupling without noise on the qubit's frequency.
34
+ - duration (int): Total duration of the simulation.
35
+ - segment_duration (int): Duration of each noise segment; used to partition the time trace.
36
+ - only_idle (bool): Flag to apply noise only to idle qubits.
37
+ - time_traces (list[float]): List of time traces for each qubit.
38
+ - time_traces_coupling (list[float]): List of time traces for coupling noise for each pair of qubits (if TJS is set).
39
+ - seed (int or None): seed integer for random number generation. If not specified, no seed used.
40
+
41
+ """
42
+
43
+ # noise_generator (class): Noise generator class based on noise_type. :no-index:
44
+
45
+ noise_generator: (
46
+ type[WhiteNoiseTimeTrace]
47
+ | type[QuasistaticNoiseTimeTrace]
48
+ | type[PinkNoiseTimeTrace]
49
+ )
50
+
51
+ def __init__(
52
+ self,
53
+ hardware_specs: HardwareSpecs,
54
+ noise_type: NoiseType = NoiseType.PINK,
55
+ T2S: float = 100.0,
56
+ TJS: float | None = None,
57
+ duration: int = 2**10,
58
+ only_idle: bool = False,
59
+ segment_duration: int = 2**10,
60
+ seed: int | None = None,
61
+ ):
62
+ """
63
+ Initialize the ExperimentalEnvironment with specified noise characteristics and simulation parameters.
64
+
65
+ Parameters:
66
+ hardware_specs (class): HardwareSpecs class, that defines the hardware settings.
67
+ noise_type (NoiseType): Type of noise to simulate. Must be "pink", "white", or "quasistatic".
68
+ T2S (float): Characteristic time of individual qubits.
69
+ TJS (float or None): Characteristic time of coupled two-qubit system at maximal J coupling with no noise on the qubit's frequency.
70
+ duration (int): Total duration of the simulation.
71
+ only_idle (bool): Flag to apply noise only to idle qubits.
72
+ segment_duration (int): Duration of each noise segment; used to partition the time trace.
73
+ seed (int or None): seed integer for random number generation. If not specified, no seed used.
74
+ Raises:
75
+ ValueError: If an invalid noise_type is provided.
76
+
77
+ """
78
+
79
+ self.hardware_specs: HardwareSpecs = hardware_specs
80
+ self.noise_type: NoiseType = noise_type
81
+ self.T2S: float = T2S
82
+ self.TJS: float | None = TJS
83
+ self.duration: int = duration
84
+ self.segment_duration: int = segment_duration
85
+ self.seed: int | None = seed
86
+ match noise_type:
87
+ case NoiseType.PINK:
88
+ self.noise_generator = PinkNoiseTimeTrace
89
+ case NoiseType.WHITE:
90
+ self.noise_generator = WhiteNoiseTimeTrace
91
+ case NoiseType.QUASISTATIC:
92
+ self.noise_generator = QuasistaticNoiseTimeTrace
93
+ case _:
94
+ raise ValueError("unknown noise type")
95
+
96
+ self.only_idle = only_idle
97
+ self.generate_time_traces()
98
+
99
+ def generate_time_traces(self):
100
+ """
101
+ Generate noise time traces for each qubit's frequency and J coupling to each pair of qubits if TJS is defined.
102
+
103
+ Behavior:
104
+ For each qubit, instantiate a noise generator using the selected noise_type.
105
+ The generator uses T2S, duration, and segment_duration to produce a time trace.
106
+ If TJS is provided, generate additional time traces for J coupling noise for each pair of qubits.
107
+
108
+ Effects:
109
+ Populate self.time_traces with one noise trace per qubit.
110
+ If TJS is set, populate self.time_traces_coupling with one trace per pair of qubits (n-1 traces for n qubits).
111
+ """
112
+ self.time_traces = []
113
+ for _ in range(self.hardware_specs.num_qubits):
114
+ time_trace = self.noise_generator(
115
+ self.T2S, self.duration, self.segment_duration, seed=self.seed
116
+ )
117
+ self.time_traces.append(time_trace)
118
+
119
+ if self.TJS is not None:
120
+ self.time_traces_coupling = []
121
+ for _ in range(self.hardware_specs.num_qubits - 1):
122
+ time_trace = self.noise_generator(
123
+ self.TJS, self.duration, self.segment_duration, seed=self.seed
124
+ )
125
+ self.time_traces_coupling.append(time_trace)
126
+
127
+ def __str__(self):
128
+ """
129
+ Return a string representation of the ExperimentalEnvironment instance.
130
+
131
+ Includes:
132
+ Number of qubits
133
+ Noise type
134
+ T2S and TJS values
135
+ Duration and segment duration
136
+ Whether noise is only appplied to idle qubits
137
+ The J coupling value set in HardwareSpecs
138
+ The total number of generated time traces
139
+ The total number of generated coupling time traces if there exists some
140
+ """
141
+ summary = [
142
+ "ExperimentalEnvironment:",
143
+ f" Qubits: {self.hardware_specs.num_qubits}",
144
+ f" Noise Type: {self.noise_type}",
145
+ f" T2S (qubit dephasing): {self.T2S}",
146
+ f" TJS (coupling dephasing): {self.TJS if self.TJS is not None else 'None'}",
147
+ f" Duration: {self.duration}",
148
+ f" Segment Duration: {self.segment_duration}",
149
+ f" Only Idle: {self.only_idle}",
150
+ f" J Coupling: {self.hardware_specs.J_coupling if self.hardware_specs.J_coupling is not None else 'None'}",
151
+ f" Time Traces Generated: {len(self.time_traces)}",
152
+ f" Seed: {self.seed}",
153
+ ]
154
+ if hasattr(self, "time_traces_coupling"):
155
+ summary.append(
156
+ f" Coupling Time Traces Generated: {len(self.time_traces_coupling)}"
157
+ )
158
+ return "\n".join(summary)
@@ -0,0 +1,32 @@
1
+ # --------------------------------------------------------------------------------------
2
+ # This code is part of SpinPulse.
3
+ #
4
+ # (C) Copyright Quobly 2025.
5
+ #
6
+ # This code is licensed under the Apache License, Version 2.0. You may
7
+ # obtain a copy of this license in the LICENSE.txt file in the root directory
8
+ # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
9
+ #
10
+ # Any modifications or derivative works of this code must retain this
11
+ # copyright notice, and modified files need to carry a notice indicating
12
+ # that they have been altered from the originals.
13
+ # --------------------------------------------------------------------------------------
14
+ """
15
+ This modules provides a set of noise classes for simulating different noise processes:
16
+ - QUASISTATIC: Quasistatic noise generated by `QuasistaticNoiseTimeTrace` from :mod:`spin_pulse.environment.noise.quasistatic`.
17
+ - PINK: Pink (1/f) noise generated by `PinkNoiseTimeTrace` from :mod:`spin_pulse.environment.noise.pink`.
18
+ - WHITE: White Gaussian noise generated by `WhiteNoiseTimeTrace` from :mod:`spin_pulse.environment.noise.white`.
19
+ """
20
+
21
+ from .noise_time_trace import NoiseTimeTrace, NoiseType
22
+ from .pink import PinkNoiseTimeTrace
23
+ from .quasistatic import QuasistaticNoiseTimeTrace
24
+ from .white import WhiteNoiseTimeTrace
25
+
26
+ __all__ = [
27
+ "NoiseTimeTrace",
28
+ "NoiseType",
29
+ "PinkNoiseTimeTrace",
30
+ "QuasistaticNoiseTimeTrace",
31
+ "WhiteNoiseTimeTrace",
32
+ ]