From c4a981765b903d9dc4a21daa9a5ef31b176606d7 Mon Sep 17 00:00:00 2001 From: Nicolas Wittler Date: Wed, 8 Jun 2022 17:21:10 +0000 Subject: [PATCH 01/14] Removed model controllability switch --- c3/libraries/propagation.py | 35 +++++++++++------------------------ 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/c3/libraries/propagation.py b/c3/libraries/propagation.py index e711788a..244c6d33 100644 --- a/c3/libraries/propagation.py +++ b/c3/libraries/propagation.py @@ -243,30 +243,17 @@ def pwc(model: Model, gen: Generator, instr: Instruction, folding_stack: list) - signal = gen.generate_signals(instr) # Why do I get 0.0 if I print gen.resolution here?! FR ts = [] - if model.controllability: - h0, hctrls = model.get_Hamiltonians() - signals = [] - hks = [] - for key in signal: - signals.append(signal[key]["values"]) - ts = signal[key]["ts"] - hks.append(hctrls[key]) - signals = tf.cast(signals, tf.complex128) - hks = tf.cast(hks, tf.complex128) - else: - h0 = model.get_Hamiltonian(signal) - ts_list = [sig["ts"][1:] for sig in signal.values()] - ts = tf.constant(tf.math.reduce_mean(ts_list, axis=0)) - hks = None - signals = None - if not np.all( - tf.math.reduce_variance(ts_list, axis=0) < 1e-5 * (ts[1] - ts[0]) - ): - raise Exception("C3Error:Something with the times happend.") - if not np.all( - tf.math.reduce_variance(ts[1:] - ts[:-1]) < 1e-5 * (ts[1] - ts[0]) # type: ignore - ): - raise Exception("C3Error:Something with the times happend.") + h0 = model.get_Hamiltonian(signal) + ts_list = [sig["ts"][1:] for sig in signal.values()] + ts = tf.constant(tf.math.reduce_mean(ts_list, axis=0)) + hks = None + signals = None + if not np.all(tf.math.reduce_variance(ts_list, axis=0) < 1e-5 * (ts[1] - ts[0])): + raise Exception("C3Error:Something with the times happend.") + if not np.all( + tf.math.reduce_variance(ts[1:] - ts[:-1]) < 1e-5 * (ts[1] - ts[0]) # type: ignore + ): + raise Exception("C3Error:Something with the times happend.") dt = ts[1] - ts[0] From 445c6e03c12237dfc2cbe72e17063294d5168fad Mon Sep 17 00:00:00 2001 From: Nicolas Wittler Date: Wed, 8 Jun 2022 17:21:43 +0000 Subject: [PATCH 02/14] Initial interaction picture support. --- c3/model.py | 81 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 65 insertions(+), 16 deletions(-) diff --git a/c3/model.py b/c3/model.py index 432bc2b8..9c4d6abf 100755 --- a/c3/model.py +++ b/c3/model.py @@ -10,7 +10,7 @@ from c3.c3objs import hjson_encode, hjson_decode from c3.libraries.chip import device_lib, Drive, Coupling from c3.libraries.tasks import task_lib -from typing import Dict, List, Tuple, Union +from typing import Dict, List, Tuple class Model: @@ -40,24 +40,33 @@ class Model: """ - def __init__(self, subsystems=None, couplings=None, tasks=None, max_excitations=0): + def __init__( + self, + subsystems=None, + couplings=None, + drives=None, + tasks=None, + max_excitations=0, + ): self.dressed = True self.lindbladian = False - self.use_FR = True + self.use_FR = False self.dephasing_strength = 0.0 self.params = {} self.subsystems: dict = dict() - self.couplings: Dict[str, Union[Drive, Coupling]] = {} + self.couplings: Dict[str, Coupling] = {} + self.drives: Dict[str, Drive] = {} self.tasks: dict = dict() self.drift_ham = None self.dressed_drift_ham = None self.__hamiltonians = None self.__dressed_hamiltonians = None if subsystems: - self.set_components(subsystems, couplings, max_excitations) + self.set_components(subsystems, couplings, drives, max_excitations) if tasks: self.set_tasks(tasks) - self.controllability = True + self.controllability = False + self.get_Hamiltonian = self._get_interaction_Hamiltonian def get_ground_state(self) -> tf.constant: gs = [[0] * self.tot_dim] @@ -84,16 +93,21 @@ def __check_drive_connect(self, comp): f" to non-existent device {self.subsystems[connect].name}." ) - def set_components(self, subsystems, couplings=None, max_excitations=0) -> None: + def set_components( + self, subsystems, couplings=None, drives=None, max_excitations=0 + ) -> None: for comp in subsystems: self.subsystems[comp.name] = comp for comp in couplings: self.couplings[comp.name] = comp + if len(set(comp.connected) - set(self.subsystems.keys())) > 0: + raise Exception("Tried to couple non-existent devices.") + for comp in drives: + self.drives[comp.name] = comp # Check that the target of a drive exists and is store the info in the target. - if isinstance(comp, Drive): - self.__check_drive_connect(comp) + self.__check_drive_connect(comp) if len(set(comp.connected) - set(self.subsystems.keys())) > 0: - raise Exception("Tried to connect non-existent devices.") + raise Exception("Tried to drive non-existent devices.") if len(set(self.couplings.keys()).intersection(self.subsystems.keys())) > 0: raise KeyError("Do not use same name for multiple devices") @@ -161,6 +175,18 @@ def __create_matrix_representations(self) -> None: ) from ve opers_list.append(self.ann_opers[indx]) line.init_Hs(opers_list) + for drive in self.drives.values(): + conn = drive.connected + opers_list = [] + for sub in conn: + try: + indx = self.names.index(sub) + except ValueError as ve: + raise Exception( + f"C3:ERROR: Trying to couple to unkown subcomponent: {sub}" + ) from ve + opers_list.append(self.ann_opers[indx]) + drive.init_Hs(opers_list) self.update_model() def set_max_excitations(self, max_excitations) -> None: @@ -228,6 +254,13 @@ def fromdict(self, cfg: dict) -> None: this_dev = device_lib[dev_type](**props) couplings.append(this_dev) + drives = [] + for name, props in cfg["Drives"].items(): + props.update({"name": name}) + dev_type = props.pop("c3type") + this_dev = device_lib[dev_type](**props) + drives.append(this_dev) + if "Tasks" in cfg: tasks = [] for name, props in cfg["Tasks"].items(): @@ -239,7 +272,7 @@ def fromdict(self, cfg: dict) -> None: if "use_dressed_basis" in cfg: self.dressed = cfg["use_dressed_basis"] - self.set_components(subsystems, couplings) + self.set_components(subsystems, couplings, drives) self.__create_labels() self.__create_annihilators() self.__create_matrix_representations() @@ -338,7 +371,7 @@ def get_sparse_Hamiltonians(self): sparse_controls = tf.vectorized_map(self.blowup_excitations, controls) return sparse_drift, sparse_controls - def get_Hamiltonian(self, signal=None): + def _get_Hamiltonian(self, signal=None): """Get a hamiltonian with an optional signal. This will return an hamiltonian over time. Can be used e.g. for tuning the frequency of a transmon, where the control hamiltonian is not easily accessible. If max.excitation is non-zero the resulting Hamiltonian is cut accordingly""" @@ -378,6 +411,23 @@ def get_Hamiltonian(self, signal=None): return signal_hamiltonian + def _get_interaction_Hamiltonian(self, signal: Dict = {}) -> tf.Tensor: + drift = tf.expand_dims(self.drift_ham, 0) # create batch dimension + ts = tf.expand_dims( + tf.expand_dims(signal["d1"]["ts"], -1), -1 + ) # ts as batch dimension + hamiltonians = [] + transform = tf.linalg.expm(-1j * drift * tf_utils.tf_complexify(ts)) + for key, sig in signal.items(): + h_of_t = self.drives[key].get_Hamiltonian(sig) + hamiltonians.append(tf.linalg.adjoint(transform) @ h_of_t @ transform) + signal_hamiltonian = tf.reduce_sum(hamiltonians, axis=0) + + if self.max_excitations: + signal_hamiltonian = self.cut_excitations(signal_hamiltonian) + + return signal_hamiltonian + def get_sparse_Hamiltonian(self, signal=None): return self.blowup_excitations(self.get_Hamiltonian(signal)) @@ -401,10 +451,9 @@ def update_Hamiltonians(self): for key, sub in self.subsystems.items(): hamiltonians[key] = sub.get_Hamiltonian() for key, line in self.couplings.items(): - if isinstance(line, Coupling): - hamiltonians[key] = line.get_Hamiltonian() - if isinstance(line, Drive): - control_hams[key] = line.get_Hamiltonian(signal=True) + hamiltonians[key] = line.get_Hamiltonian() + for key, line in self.drives.items(): + control_hams[key] = line.get_Hamiltonian(signal=True) self.drift_ham = sum(hamiltonians.values()) self.control_hams = control_hams From c73984dd13971e111040b555329df6f65044a53d Mon Sep 17 00:00:00 2001 From: Nicolas Wittler Date: Fri, 10 Jun 2022 15:43:26 +0000 Subject: [PATCH 03/14] Converted configs --- test/c2_blackbox_exp.hjson | 186 ++++++++++++---------- test/noise_exp_1.hjson | 49 +++--- test/noise_exp_2.hjson | 65 ++++---- test/one_qubit.hjson | 153 ++++++++++-------- test/test_model.cfg | 157 +++++++++++-------- test/test_model_breaking.cfg | 269 +++++++++++++++++++------------- test/test_model_spam.cfg | 293 ++++++++++++++++++++--------------- 7 files changed, 668 insertions(+), 504 deletions(-) diff --git a/test/c2_blackbox_exp.hjson b/test/c2_blackbox_exp.hjson index d1cdc3ce..d0d44281 100644 --- a/test/c2_blackbox_exp.hjson +++ b/test/c2_blackbox_exp.hjson @@ -16,41 +16,41 @@ { amp: { - value: 1.0 - min_val: -1.0 + value: 1 + min_val: -1 max_val: 1.5 unit: V symbol: \alpha } delta: { - value: 0.0 - min_val: -5.0 - max_val: 5.0 + value: 0 + min_val: -5 + max_val: 5 unit: V symbol: \alpha } freq_offset: { - value: 0.0 - min_val: -1.0 - max_val: 1.0 + value: 0 + min_val: -1 + max_val: 1 unit: Hz 2pi symbol: \alpha } xy_angle: { - value: 0.0 - min_val: -1.0 - max_val: 1.0 + value: 0 + min_val: -1 + max_val: 1 unit: rad symbol: \alpha } sigma: { value: 4.999999969612645e-09 - min_val: -2.0 - max_val: 2.0 + min_val: -2 + max_val: 2 unit: s symbol: \alpha } @@ -71,9 +71,9 @@ { freq: { - value: 5050000000.0 - min_val: 4500000000.0 - max_val: 6000000000.0 + value: 5050000000 + min_val: 4500000000 + max_val: 6000000000 unit: Hz 2pi symbol: \alpha } @@ -113,17 +113,17 @@ } delta: { - value: -1.0 - min_val: -5.0 - max_val: 3.0 + value: -1 + min_val: -5 + max_val: 3 unit: "" symbol: \alpha } freq_offset: { value: -50500000.00000001 - min_val: -60000000.0 - max_val: -40000000.0 + min_val: -60000000 + max_val: -40000000 unit: Hz 2pi symbol: \alpha } @@ -160,15 +160,15 @@ { freq: { - value: 5050000000.0 - min_val: 4500000000.0 - max_val: 6000000000.0 + value: 5050000000 + min_val: 4500000000 + max_val: 6000000000 unit: Hz 2pi symbol: \alpha } framechange: { - value: 0.0 + value: 0 min_val: -3.141592653589793 max_val: 9.42477796076938 unit: rad @@ -202,17 +202,17 @@ } delta: { - value: -1.0 - min_val: -5.0 - max_val: 3.0 + value: -1 + min_val: -5 + max_val: 3 unit: "" symbol: \alpha } freq_offset: { value: -50500000.00000001 - min_val: -60000000.0 - max_val: -40000000.0 + min_val: -60000000 + max_val: -40000000 unit: Hz 2pi symbol: \alpha } @@ -249,15 +249,15 @@ { freq: { - value: 5050000000.0 - min_val: 4500000000.0 - max_val: 6000000000.0 + value: 5050000000 + min_val: 4500000000 + max_val: 6000000000 unit: Hz 2pi symbol: \alpha } framechange: { - value: 0.0 + value: 0 min_val: -3.141592653589793 max_val: 9.42477796076938 unit: rad @@ -291,17 +291,17 @@ } delta: { - value: -1.0 - min_val: -5.0 - max_val: 3.0 + value: -1 + min_val: -5 + max_val: 3 unit: "" symbol: \alpha } freq_offset: { value: -50500000.00000001 - min_val: -60000000.0 - max_val: -40000000.0 + min_val: -60000000 + max_val: -40000000 unit: Hz 2pi symbol: \alpha } @@ -338,15 +338,15 @@ { freq: { - value: 5050000000.0 - min_val: 4500000000.0 - max_val: 6000000000.0 + value: 5050000000 + min_val: 4500000000 + max_val: 6000000000 unit: Hz 2pi symbol: \alpha } framechange: { - value: 0.0 + value: 0 min_val: -3.141592653589793 max_val: 9.42477796076938 unit: rad @@ -380,17 +380,17 @@ } delta: { - value: -1.0 - min_val: -5.0 - max_val: 3.0 + value: -1 + min_val: -5 + max_val: 3 unit: "" symbol: \alpha } freq_offset: { value: -50500000.00000001 - min_val: -60000000.0 - max_val: -40000000.0 + min_val: -60000000 + max_val: -40000000 unit: Hz 2pi symbol: \alpha } @@ -427,15 +427,15 @@ { freq: { - value: 5050000000.0 - min_val: 4500000000.0 - max_val: 6000000000.0 + value: 5050000000 + min_val: 4500000000 + max_val: 6000000000 unit: Hz 2pi symbol: \alpha } framechange: { - value: 0.0 + value: 0 min_val: -3.141592653589793 max_val: 9.42477796076938 unit: rad @@ -458,24 +458,24 @@ { freq: { - value: 5000100000.0 - min_val: 4995000000.0 - max_val: 5005000000.0 + value: 5000100000 + min_val: 4995000000 + max_val: 5005000000 unit: Hz 2pi symbol: \alpha } anhar: { - value: -210001000.0 - min_val: -380000000.0 + value: -210001000 + min_val: -380000000 max_val: -120000000.00000003 unit: Hz 2pi symbol: \alpha } temp: { - value: 0.0 - min_val: 0.0 + value: 0 + min_val: 0 max_val: 0.12 unit: K symbol: \alpha @@ -484,7 +484,26 @@ hilbert_dim: 3 } } - Couplings: + Couplings: {} + Tasks: + { + init_ground: + { + c3type: InitialiseGround + params: + { + init_temp: + { + value: 0 + min_val: -0.001 + max_val: 0.22 + unit: K + symbol: \alpha + } + } + } + } + Drives: { d1: { @@ -497,24 +516,6 @@ ] } } - Tasks: - { - init_ground: - { - c3type: InitialiseGround - params: - { - init_temp: - { - value: 0 - min_val: -0.001 - max_val: 0.22 - unit: K - symbol: \alpha - } - } - } - } } generator: { @@ -534,7 +535,7 @@ inputs: 0 outputs: 1 params: {} - resolution: 2000000000.0 + resolution: 2000000000 } DigitalToAnalog: { @@ -579,9 +580,9 @@ { V_to_Hz: { - value: 1000000000.0 - min_val: 900000000.0 - max_val: 1100000000.0 + value: 1000000000 + min_val: 900000000 + max_val: 1100000000 unit: Hz/V symbol: \alpha } @@ -595,10 +596,23 @@ { LO: [] AWG: [] - DigitalToAnalog: ["AWG"] - Response: ["DigitalToAnalog"] - Mixer: ["LO", "Response"] - VoltsToHertz: ["Mixer"] + DigitalToAnalog: + [ + AWG + ] + Response: + [ + DigitalToAnalog + ] + Mixer: + [ + LO + Response + ] + VoltsToHertz: + [ + Mixer + ] } } } diff --git a/test/noise_exp_1.hjson b/test/noise_exp_1.hjson index 113eeab0..e8c12023 100644 --- a/test/noise_exp_1.hjson +++ b/test/noise_exp_1.hjson @@ -62,17 +62,17 @@ } delta: { - value: -1.0 - min_val: -5.0 - max_val: 3.0 + value: -1 + min_val: -5 + max_val: 3 unit: "" symbol: \alpha } freq_offset: { - value: -53000000.0 - min_val: -56000000.0 - max_val: -52000000.0 + value: -53000000 + min_val: -56000000 + max_val: -52000000 unit: Hz 2pi symbol: \alpha } @@ -109,15 +109,15 @@ { freq: { - value: 5050000000.0 - min_val: 4500000000.0 - max_val: 6000000000.0 + value: 5050000000 + min_val: 4500000000 + max_val: 6000000000 unit: Hz 2pi symbol: \alpha } framechange: { - value: 0.0 + value: 0 min_val: -3.141592653589793 max_val: 9.42477796076938 unit: rad @@ -141,16 +141,16 @@ { freq: { - value: 5000000000.0 - min_val: 4995000000.0 - max_val: 5005000000.0 + value: 5000000000 + min_val: 4995000000 + max_val: 5005000000 unit: Hz 2pi symbol: \alpha } anhar: { - value: -210000000.0 - min_val: -380000000.0 + value: -210000000 + min_val: -380000000 max_val: -120000000.00000003 unit: Hz 2pi symbol: \alpha @@ -174,7 +174,7 @@ temp: { value: 0.05 - min_val: 0.0 + min_val: 0 max_val: 0.12 unit: K symbol: \alpha @@ -183,7 +183,10 @@ hilbert_dim: 3 } } - Couplings: + Couplings: {} + Tasks: {} + max_excitations: 0 + Drives: { d1: { @@ -196,8 +199,6 @@ ] } } - Tasks: {} - max_excitations: 0 } generator: { @@ -219,7 +220,7 @@ inputs: 0 outputs: 1 params: {} - resolution: 2000000000.0 + resolution: 2000000000 } DigitalToAnalog: { @@ -268,7 +269,7 @@ { offset_amp: { - value: 0.0 + value: 0 min_val: -0.2 max_val: 0.2 unit: V @@ -287,9 +288,9 @@ { V_to_Hz: { - value: 1000000000.0 - min_val: 900000000.0 - max_val: 1100000000.0 + value: 1000000000 + min_val: 900000000 + max_val: 1100000000 unit: Hz/V symbol: \alpha } diff --git a/test/noise_exp_2.hjson b/test/noise_exp_2.hjson index ce3c235f..1a20b2a9 100644 --- a/test/noise_exp_2.hjson +++ b/test/noise_exp_2.hjson @@ -62,17 +62,17 @@ } delta: { - value: -1.0 - min_val: -5.0 - max_val: 3.0 + value: -1 + min_val: -5 + max_val: 3 unit: "" symbol: \alpha } freq_offset: { - value: -53000000.0 - min_val: -56000000.0 - max_val: -52000000.0 + value: -53000000 + min_val: -56000000 + max_val: -52000000 unit: Hz 2pi symbol: \alpha } @@ -109,15 +109,15 @@ { freq: { - value: 5050000000.0 - min_val: 4500000000.0 - max_val: 6000000000.0 + value: 5050000000 + min_val: 4500000000 + max_val: 6000000000 unit: Hz 2pi symbol: \alpha } framechange: { - value: 0.0 + value: 0 min_val: -3.141592653589793 max_val: 9.42477796076938 unit: rad @@ -141,16 +141,16 @@ { freq: { - value: 5000000000.0 - min_val: 4995000000.0 - max_val: 5005000000.0 + value: 5000000000 + min_val: 4995000000 + max_val: 5005000000 unit: Hz 2pi symbol: \alpha } anhar: { - value: -210000000.0 - min_val: -380000000.0 + value: -210000000 + min_val: -380000000 max_val: -120000000.00000003 unit: Hz 2pi symbol: \alpha @@ -174,7 +174,7 @@ temp: { value: 0.05 - min_val: 0.0 + min_val: 0 max_val: 0.12 unit: K symbol: \alpha @@ -183,7 +183,10 @@ hilbert_dim: 3 } } - Couplings: + Couplings: {} + Tasks: {} + max_excitations: 0 + Drives: { d1: { @@ -196,8 +199,6 @@ ] } } - Tasks: {} - max_excitations: 0 } generator: { @@ -219,7 +220,7 @@ inputs: 0 outputs: 1 params: {} - resolution: 2000000000.0 + resolution: 2000000000 } DigitalToAnalog: { @@ -268,7 +269,7 @@ { offset_amp: { - value: 0.0 + value: 0 min_val: -0.2 max_val: 0.2 unit: V @@ -316,7 +317,7 @@ { value: 8.673617379884035e-18 min_val: -0.01 - max_val: 1.0 + max_val: 1 unit: Phi0 symbol: \alpha } @@ -333,9 +334,9 @@ { noise_amp: { - value: 0.0 - min_val: 0.0 - max_val: 1.0 + value: 0 + min_val: 0 + max_val: 1 unit: V symbol: \alpha } @@ -352,15 +353,15 @@ { noise_amp: { - value: 0.0 - min_val: 0.0 - max_val: 1.0 + value: 0 + min_val: 0 + max_val: 1 unit: V symbol: \alpha } bfl_num: { - value: 15.0 + value: 15 min_val: 13.5 max_val: 16.5 unit: undefined @@ -379,9 +380,9 @@ { V_to_Hz: { - value: 1000000000.0 - min_val: 900000000.0 - max_val: 1100000000.0 + value: 1000000000 + min_val: 900000000 + max_val: 1100000000 unit: Hz/V symbol: \alpha } diff --git a/test/one_qubit.hjson b/test/one_qubit.hjson index 45049d17..81274a2d 100644 --- a/test/one_qubit.hjson +++ b/test/one_qubit.hjson @@ -1,51 +1,66 @@ { instructions: { - "rx90p":{ - name: "rx90p", - targets: [0], - gate_length: 8e-9, - drive_channels:{ - d1:{ - cosine:{ + rx90p: + { + name: rx90p + targets: + [ + 0 + ] + gate_length: 8e-09 + drive_channels: + { + d1: + { + cosine: + { c3type: Envelope shape: cosine - params: { - amp: { - value:0.05, - min_val:0.01, - max_val:0.6, - unit:V - }, - delta: { - value:0, - min_val:-0.1, - max_val:0.6, - unit:"" - }, - freq_offset:{ - value : 0e6, - unit : "Hz 2pi", - min_val : -50e6, - max_val : 50e6 + params: + { + amp: + { + value: 0.05 + min_val: 0.01 + max_val: 0.6 + unit: V + } + delta: + { + value: 0 + min_val: -0.1 + max_val: 0.6 + unit: "" + } + freq_offset: + { + value: 0 + unit: Hz 2pi + min_val: -50000000 + max_val: 50000000 } - t_final:{ - value : 8e-9, - unit : s, - min_val : 1e-9, - max_val : 10e-9 + t_final: + { + value: 8e-09 + unit: s, + min_val: 1e-09 + max_val: 1e-08 } } - }, - carrier: { + } + carrier: + { c3type: Carrier - params: { - freq: { - value : 3.81966664926965e9, - unit : "Hz 2pi", - min_val : 2.5e9, - max_val : 5.5e9 - }, + params: + { + freq: + { + value: 3819666649.26965 + unit: Hz 2pi + min_val: 2500000000 + max_val: 5500000000 + } framechange: { value: 0 @@ -71,23 +86,23 @@ { freq: { - value: 3.82e9 - min_val: 3e9 - max_val: 8e9 - unit: "Hz 2pi" + value: 3820000000 + min_val: 3000000000 + max_val: 8000000000 + unit: Hz 2pi symbol: \omega_1 } anhar: { - value: -229e6 - min_val: -380000000.0 + value: -229000000 + min_val: -380000000 max_val: -120000000.00000003 - unit: "Hz 2pi" + unit: Hz 2pi symbol: \alpha_1 } t1: { - value: 77e-6 + value: 7.7e-05 min_val: 5e-06 max_val: 9e-05 unit: s @@ -95,7 +110,7 @@ } t2star: { - value: 49e-6 + value: 4.9e-05 min_val: 1e-05 max_val: 9e-05 unit: s @@ -104,7 +119,7 @@ temp: { value: 0.06 - min_val: 0.0 + min_val: 0 max_val: 0.12 unit: K symbol: \alpha @@ -113,7 +128,8 @@ hilbert_dim: 3 } } - Couplings: + Couplings: {} + Drives: { d1: { @@ -143,7 +159,7 @@ c3type: AWG inputs: 0 outputs: 1 - resolution: 2400000000.0 + resolution: 2400000000 } mixer: { @@ -186,10 +202,10 @@ { V_to_Hz: { - value: 1000000000.0 - min_val: 900000000.0 - max_val: 1100000000.0 - unit: "Hz 2pi/V" + value: 1000000000 + min_val: 900000000 + max_val: 1100000000 + unit: Hz 2pi/V symbol: \alpha } } @@ -200,13 +216,26 @@ { d1: { - "lo": [], - "awg": [], - "dac": ["awg"], - "resp": ["dac"], - "mixer": ["lo", "resp"], - v2hz: ["mixer"] + lo: [] + awg: [] + dac: + [ + awg + ] + resp: + [ + dac + ] + mixer: + [ + lo + resp + ] + v2hz: + [ + mixer + ] } } } -} +} \ No newline at end of file diff --git a/test/test_model.cfg b/test/test_model.cfg index 36d7733d..5ad744f5 100644 --- a/test/test_model.cfg +++ b/test/test_model.cfg @@ -1,71 +1,100 @@ { - "Qubits" : { - "Q1" : { - "c3type": "Qubit", - "desc" : "Qubit 1", - "params": { - "freq" : { - "value" : 4.8e9, - "unit" : "Hz 2pi", - "min_val" : 4.5e9, - "max_val" : 5.5e9 + Qubits: + { + Q1: + { + c3type: Qubit + desc: Qubit 1 + params: + { + freq: + { + value: 4800000000 + unit: Hz 2pi + min_val: 4500000000 + max_val: 5500000000 } - }, - "hilbert_dim" : 2 - }, - "Q2" : { - "c3type": "Qubit", - "desc" : "Qubit 2", - "params": { - "freq" : { - "value" : 4.9e9, - "unit" : "Hz 2pi", - "min_val" : 4.5e9, - "max_val" : 5.5e9 + } + hilbert_dim: 2 + } + Q2: + { + c3type: Qubit + desc: Qubit 2 + params: + { + freq: + { + value: 4900000000 + unit: Hz 2pi + min_val: 4500000000 + max_val: 5500000000 } - }, - "hilbert_dim" : 2 - }, - "Q3" : { - "c3type": "Qubit", - "desc" : "Qubit 1", - "params": { - "freq" : { - "value" : 5e9, - "unit" : "Hz 2pi", - "min_val" : 4.5e9, - "max_val" : 5.5e9 + } + hilbert_dim: 2 + } + Q3: + { + c3type: Qubit + desc: Qubit 1 + params: + { + freq: + { + value: 5000000000 + unit: Hz 2pi + min_val: 4500000000 + max_val: 5500000000 } - }, - "hilbert_dim" : 2 - }, - }, - "Couplings" : { - "Q1-Q2" : { - "c3type": "Coupling", - "desc" : "Coupling qubit 1 and 2", - "params": { - "strength" : { - "value" : 20e6, - "unit" : "Hz 2pi", - "min_val" : -1e6, - "max_val" : 50e6 + } + hilbert_dim: 2 + } + } + Couplings: + { + Q1-Q2: + { + c3type: Coupling + desc: Coupling qubit 1 and 2 + params: + { + strength: + { + value: 20000000 + unit: Hz 2pi + min_val: -1000000 + max_val: 50000000 } - }, - "hamiltonian_func" : "int_XX", - "connected" : ["Q1", "Q2"] - }, - "d1" : { - "c3type": "Drive", - "desc" : "Drive on qubit 1", - "connected" : ["Q1"], - "hamiltonian_func" : "x_drive" - }, - "d2" : { - "c3type": "Drive", - "desc" : "Drive on qubit 2", - "connected" : ["Q2"], - "hamiltonian_func" : "x_drive" + } + hamiltonian_func: int_XX + connected: + [ + Q1 + Q2 + ] + } + } + Drives: + { + d1: + { + c3type: Drive + desc: Drive on qubit 1 + connected: + [ + Q1 + ] + hamiltonian_func: x_drive + } + d2: + { + c3type: Drive + desc: Drive on qubit 2 + connected: + [ + Q2 + ] + hamiltonian_func: x_drive } } -} +} \ No newline at end of file diff --git a/test/test_model_breaking.cfg b/test/test_model_breaking.cfg index 4157d504..d6d81fd7 100644 --- a/test/test_model_breaking.cfg +++ b/test/test_model_breaking.cfg @@ -1,124 +1,169 @@ { - "Qubits" : { - "Q1" : { - "c3type": "Qubit", - "desc" : "Qubit 1", - "params": { - "freq" : { - "value" : 4.8e9, - "unit" : "Hz 2pi", - "min_val" : 4.5e9, - "max_val" : 5.5e9 + Qubits: + { + Q1: + { + c3type: Qubit + desc: Qubit 1 + params: + { + freq: + { + value: 4800000000 + unit: Hz 2pi + min_val: 4500000000 + max_val: 5500000000 } - }, - "hilbert_dim" : 2 - }, - "Q2" : { - "c3type": "Qubit", - "desc" : "Qubit 2", - "params": { - "freq" : { - "value" : 4.9e9, - "unit" : "Hz 2pi", - "min_val" : 4.5e9, - "max_val" : 5.5e9 + } + hilbert_dim: 2 + } + Q2: + { + c3type: Qubit + desc: Qubit 2 + params: + { + freq: + { + value: 4900000000 + unit: Hz 2pi + min_val: 4500000000 + max_val: 5500000000 } - }, - "hilbert_dim" : 2 - }, - "Q3" : { - "c3type": "Qubit", - "desc" : "Qubit 1", - "params": { - "freq" : { - "value" : 5e9, - "unit" : "Hz 2pi", - "min_val" : 4.5e9, - "max_val" : 5.5e9 + } + hilbert_dim: 2 + } + Q3: + { + c3type: Qubit + desc: Qubit 1 + params: + { + freq: + { + value: 5000000000 + unit: Hz 2pi + min_val: 4500000000 + max_val: 5500000000 } - }, - "hilbert_dim" : 2 - }, - "Q4" : { - "c3type": "Qubit", - "desc" : "Qubit 2", - "params": { - "freq" : { - "value" : 5.2e9, - "unit" : "Hz 2pi", - "min_val" : 4.5e9, - "max_val" : 5.5e9 + } + hilbert_dim: 2 + } + Q4: + { + c3type: Qubit + desc: Qubit 2 + params: + { + freq: + { + value: 5200000000 + unit: Hz 2pi + min_val: 4500000000 + max_val: 5500000000 } - }, - "hilbert_dim" : 2 - }, - "Q5" : { - "c3type": "Qubit", - "desc" : "Qubit 1", - "params": { - "freq" : { - "value" : 5.1e9, - "unit" : "Hz 2pi", - "min_val" : 4.5e9, - "max_val" : 5.5e9 + } + hilbert_dim: 2 + } + Q5: + { + c3type: Qubit + desc: Qubit 1 + params: + { + freq: + { + value: 5100000000 + unit: Hz 2pi + min_val: 4500000000 + max_val: 5500000000 } - }, - "hilbert_dim" : 2 - }, - "Q6" : { - "c3type": "Qubit", - "desc" : "Qubit 2", - "params": { - "freq" : { - "value" : 4.6e9, - "unit" : "Hz 2pi", - "min_val" : 4.5e9, - "max_val" : 5.5e9 + } + hilbert_dim: 2 + } + Q6: + { + c3type: Qubit + desc: Qubit 2 + params: + { + freq: + { + value: 4600000000 + unit: Hz 2pi + min_val: 4500000000 + max_val: 5500000000 } - }, - "hilbert_dim" : 2 + } + hilbert_dim: 2 } - }, - "Couplings" : { - "Q1-Q2" : { - "c3type": "Coupling", - "desc" : "Coupling qubit 1 and 2", - "params": { - "strength" : { - "value" : 20e6, - "unit" : "Hz 2pi", - "min_val" : -1e6, - "max_val" : 50e6 + } + Couplings: + { + Q1-Q2: + { + c3type: Coupling + desc: Coupling qubit 1 and 2 + params: + { + strength: + { + value: 20000000 + unit: Hz 2pi + min_val: -1000000 + max_val: 50000000 } - }, - "hamiltonian_func" : "int_XX", - "connected" : ["Q1", "Q2"] - }, - "Q4-Q6" : { - "c3type": "Coupling", - "desc" : "Coupling qubit 1 and 2", - "params": { - "strength" : { - "value" : 20e6, - "unit" : "Hz 2pi", - "min_val" : -1e6, - "max_val" : 50e6 + } + hamiltonian_func: int_XX + connected: + [ + Q1 + Q2 + ] + } + Q4-Q6: + { + c3type: Coupling + desc: Coupling qubit 1 and 2 + params: + { + strength: + { + value: 20000000 + unit: Hz 2pi + min_val: -1000000 + max_val: 50000000 } - }, - "hamiltonian_func" : "int_XX", - "connected" : ["Q4", "Q6"] - }, - "d1" : { - "c3type": "Drive", - "desc" : "Drive on qubit 1", - "connected" : ["Q1"], - "hamiltonian_func" : "x_drive" - }, - "Q2" : { - "c3type": "Drive", - "desc" : "Drive on qubit 2", - "connected" : ["Q2"], - "hamiltonian_func" : "x_drive" + } + hamiltonian_func: int_XX + connected: + [ + Q4 + Q6 + ] + } + } + Drives: + { + d1: + { + c3type: Drive + desc: Drive on qubit 1 + connected: + [ + Q1 + ] + hamiltonian_func: x_drive + } + Q2: + { + c3type: Drive + desc: Drive on qubit 2 + connected: + [ + Q2 + ] + hamiltonian_func: x_drive } } -} +} \ No newline at end of file diff --git a/test/test_model_spam.cfg b/test/test_model_spam.cfg index 76e982da..dacc06f3 100644 --- a/test/test_model_spam.cfg +++ b/test/test_model_spam.cfg @@ -1,124 +1,146 @@ { - "Qubits" : { - "Q1" : { - "c3type": "Qubit", - "desc" : "Qubit 1", - "params": { - "freq" : { - "value" : 4.8e9, - "unit" : "Hz 2pi", - "min_val" : 4.5e9, - "max_val" : 5.5e9 + Qubits: + { + Q1: + { + c3type: Qubit + desc: Qubit 1 + params: + { + freq: + { + value: 4800000000 + unit: Hz 2pi + min_val: 4500000000 + max_val: 5500000000 } - }, - "hilbert_dim" : 2 - }, - "Q2" : { - "c3type": "Qubit", - "desc" : "Qubit 2", - "params": { - "freq" : { - "value" : 4.9e9, - "unit" : "Hz 2pi", - "min_val" : 4.5e9, - "max_val" : 5.5e9 + } + hilbert_dim: 2 + } + Q2: + { + c3type: Qubit + desc: Qubit 2 + params: + { + freq: + { + value: 4900000000 + unit: Hz 2pi + min_val: 4500000000 + max_val: 5500000000 } - }, - "hilbert_dim" : 2 - }, - "Q3" : { - "c3type": "Qubit", - "desc" : "Qubit 1", - "params": { - "freq" : { - "value" : 5e9, - "unit" : "Hz 2pi", - "min_val" : 4.5e9, - "max_val" : 5.5e9 + } + hilbert_dim: 2 + } + Q3: + { + c3type: Qubit + desc: Qubit 1 + params: + { + freq: + { + value: 5000000000 + unit: Hz 2pi + min_val: 4500000000 + max_val: 5500000000 } - }, - "hilbert_dim" : 2 - }, - "Q4" : { - "c3type": "Qubit", - "desc" : "Qubit 2", - "params": { - "freq" : { - "value" : 5.2e9, - "unit" : "Hz 2pi", - "min_val" : 4.5e9, - "max_val" : 5.5e9 + } + hilbert_dim: 2 + } + Q4: + { + c3type: Qubit + desc: Qubit 2 + params: + { + freq: + { + value: 5200000000 + unit: Hz 2pi + min_val: 4500000000 + max_val: 5500000000 } - }, - "hilbert_dim" : 2 - }, - "Q5" : { - "c3type": "Qubit", - "desc" : "Qubit 1", - "params": { - "freq" : { - "value" : 5.1e9, - "unit" : "Hz 2pi", - "min_val" : 4.5e9, - "max_val" : 5.5e9 + } + hilbert_dim: 2 + } + Q5: + { + c3type: Qubit + desc: Qubit 1 + params: + { + freq: + { + value: 5100000000 + unit: Hz 2pi + min_val: 4500000000 + max_val: 5500000000 } - }, - "hilbert_dim" : 2 - }, - "Q6" : { - "c3type": "Qubit", - "desc" : "Qubit 2", - "params": { - "freq" : { - "value" : 4.6e9, - "unit" : "Hz 2pi", - "min_val" : 4.5e9, - "max_val" : 5.5e9 + } + hilbert_dim: 2 + } + Q6: + { + c3type: Qubit + desc: Qubit 2 + params: + { + freq: + { + value: 4600000000 + unit: Hz 2pi + min_val: 4500000000 + max_val: 5500000000 } - }, - "hilbert_dim" : 2 + } + hilbert_dim: 2 } - }, - "Couplings" : { - "Q1-Q2" : { - "c3type": "Coupling", - "desc" : "Coupling qubit 1 and 2", - "params": { - "strength" : { - "value" : 20e6, - "unit" : "Hz 2pi", - "min_val" : -1e6, - "max_val" : 50e6 + } + Couplings: + { + Q1-Q2: + { + c3type: Coupling + desc: Coupling qubit 1 and 2 + params: + { + strength: + { + value: 20000000 + unit: Hz 2pi + min_val: -1000000 + max_val: 50000000 } - }, - "hamiltonian_func" : "int_XX", - "connected" : ["Q1", "Q2"] - }, - "Q4-Q6" : { - "c3type": "Coupling", - "desc" : "Coupling qubit 1 and 2", - "params": { - "strength" : { - "value" : 20e6, - "unit" : "Hz 2pi", - "min_val" : -1e6, - "max_val" : 50e6 + } + hamiltonian_func: int_XX + connected: + [ + Q1 + Q2 + ] + } + Q4-Q6: + { + c3type: Coupling + desc: Coupling qubit 1 and 2 + params: + { + strength: + { + value: 20000000 + unit: Hz 2pi + min_val: -1000000 + max_val: 50000000 } - }, - "hamiltonian_func" : "int_XX", - "connected" : ["Q4", "Q6"] - }, - "d1" : { - "c3type": "Drive", - "desc" : "Drive on qubit 1", - "connected" : ["Q1"], - "hamiltonian_func" : "x_drive" - }, - "d2" : { - "c3type": "Drive", - "desc" : "Drive on qubit 2", - "connected" : ["Q2"], - "hamiltonian_func" : "x_drive" + } + hamiltonian_func: int_XX + connected: + [ + Q4 + Q6 + ] } } Tasks: @@ -154,12 +176,12 @@ min_val: [ 0.8 - 0.0 - 0.0 + 0 + 0 ] max_val: [ - 1.0 + 1 0.2 0.2 ] @@ -177,12 +199,12 @@ min_val: [ 0.8 - 0.0 - 0.0 + 0 + 0 ] max_val: [ - 1.0 + 1 0.2 0.2 ] @@ -207,12 +229,12 @@ min_val: [ 0.8 - 0.0 - 0.0 + 0 + 0 ] max_val: [ - 1.0 + 1 0.2 0.2 ] @@ -230,12 +252,12 @@ min_val: [ 0.8 - 0.0 - 0.0 + 0 + 0 ] max_val: [ - 1.0 + 1 0.2 0.2 ] @@ -245,4 +267,27 @@ } } } -} + Drives: + { + d1: + { + c3type: Drive + desc: Drive on qubit 1 + connected: + [ + Q1 + ] + hamiltonian_func: x_drive + } + d2: + { + c3type: Drive + desc: Drive on qubit 2 + connected: + [ + Q2 + ] + hamiltonian_func: x_drive + } + } +} \ No newline at end of file From 645a8d5db0c3f4c2516436915eedabdcea6930b7 Mon Sep 17 00:00:00 2001 From: Nicolas Wittler Date: Fri, 10 Jun 2022 15:46:32 +0000 Subject: [PATCH 04/14] Handling of reference frame information --- c3/model.py | 210 +++++++++++++++++++++------------------------------- 1 file changed, 83 insertions(+), 127 deletions(-) diff --git a/c3/model.py b/c3/model.py index 9c4d6abf..269cf54a 100755 --- a/c3/model.py +++ b/c3/model.py @@ -3,12 +3,11 @@ import numpy as np import hjson import itertools -import copy import tensorflow as tf import c3.utils.tf_utils as tf_utils import c3.utils.qt_utils as qt_utils from c3.c3objs import hjson_encode, hjson_decode -from c3.libraries.chip import device_lib, Drive, Coupling +from c3.libraries.chip import device_lib, Drive, Coupling, PhysicalComponent from c3.libraries.tasks import task_lib from typing import Dict, List, Tuple @@ -42,31 +41,25 @@ class Model: def __init__( self, - subsystems=None, - couplings=None, - drives=None, - tasks=None, + subsystems: List[PhysicalComponent] = [], + couplings: List[Coupling] = [], + drives: List[Drive] = [], + tasks: List = [], max_excitations=0, ): - self.dressed = True - self.lindbladian = False - self.use_FR = False + self.frame = set(["dressed", "rotating"]) self.dephasing_strength = 0.0 - self.params = {} - self.subsystems: dict = dict() + self.params: Dict = {} + self.subsystems: Dict = {} self.couplings: Dict[str, Coupling] = {} self.drives: Dict[str, Drive] = {} - self.tasks: dict = dict() + self.tasks: Dict = {} self.drift_ham = None - self.dressed_drift_ham = None - self.__hamiltonians = None - self.__dressed_hamiltonians = None if subsystems: self.set_components(subsystems, couplings, drives, max_excitations) if tasks: self.set_tasks(tasks) - self.controllability = False - self.get_Hamiltonian = self._get_interaction_Hamiltonian + self.get_Hamiltonian = self._get_Hamiltonian def get_ground_state(self) -> tf.constant: gs = [[0] * self.tot_dim] @@ -77,7 +70,7 @@ def get_init_state(self) -> tf.Tensor: """Get an initial state. If a task to compute a thermal state is set, return that.""" if "init_ground" in self.tasks: psi_init = self.tasks["init_ground"].initialise( - self.drift_ham, self.lindbladian + self.drift_ham, "lindbladian" in self.frame ) else: psi_init = self.get_ground_state() @@ -94,23 +87,31 @@ def __check_drive_connect(self, comp): ) def set_components( - self, subsystems, couplings=None, drives=None, max_excitations=0 + self, + subsystems: List[PhysicalComponent], + couplings: List[Coupling] = [], + drives: List[Drive] = [], + max_excitations=0, ) -> None: for comp in subsystems: self.subsystems[comp.name] = comp - for comp in couplings: - self.couplings[comp.name] = comp - if len(set(comp.connected) - set(self.subsystems.keys())) > 0: + for coup in couplings: + self.couplings[coup.name] = coup + if len(set(coup.connected) - set(self.subsystems.keys())) > 0: raise Exception("Tried to couple non-existent devices.") - for comp in drives: - self.drives[comp.name] = comp + for drive in drives: + self.drives[drive.name] = drive # Check that the target of a drive exists and is store the info in the target. - self.__check_drive_connect(comp) - if len(set(comp.connected) - set(self.subsystems.keys())) > 0: + self.__check_drive_connect(drive) + if len(set(drive.connected) - set(self.subsystems.keys())) > 0: raise Exception("Tried to drive non-existent devices.") if len(set(self.couplings.keys()).intersection(self.subsystems.keys())) > 0: raise KeyError("Do not use same name for multiple devices") + if len(set(self.drives.keys()).intersection(self.subsystems.keys())) > 0: + raise KeyError("Do not use same name for multiple devices") + if len(set(self.couplings.keys()).intersection(self.drives.keys())) > 0: + raise KeyError("Do not use same name for multiple devices") self.__create_labels() self.__create_annihilators() self.__create_matrix_representations() @@ -271,7 +272,7 @@ def fromdict(self, cfg: dict) -> None: self.set_tasks(tasks) if "use_dressed_basis" in cfg: - self.dressed = cfg["use_dressed_basis"] + self.set_dressed(cfg["use_dressed_basis"]) self.set_components(subsystems, couplings, drives) self.__create_labels() self.__create_annihilators() @@ -318,7 +319,10 @@ def set_dressed(self, dressed): dressed : boolean """ - self.dressed = dressed + if dressed: + self.frame.add("dressed") + else: + self.frame.discard("dressed") self.update_model() def set_lindbladian(self, lindbladian: bool) -> None: @@ -331,15 +335,21 @@ def set_lindbladian(self, lindbladian: bool) -> None: """ - self.lindbladian = lindbladian + if lindbladian: + self.frame.add("lindbladian") + else: + self.frame.discard("lindbladian") self.update_model() - def set_FR(self, use_FR): + def set_FR(self, use_FR: bool) -> None: """ Setter for the frame rotation option for adjusting the individual rotating frames of qubits when using gate sequences """ - self.use_FR = use_FR + if use_FR: + self.frame.add("rotating") + else: + self.frame.discard("rotating") def set_dephasing_strength(self, dephasing_strength): self.dephasing_strength = dephasing_strength @@ -350,61 +360,20 @@ def list_parameters(self): ids.append(("Model", key)) return ids - def get_Hamiltonians(self): - drift = [] - controls = [] - - if self.dressed: - drift = self.dressed_drift_ham - controls = self.dressed_control_hams - else: - drift = self.drift_ham - controls = self.control_hams - if self.max_excitations: - drift = self.cut_excitations(drift) - controls = self.cut_excitations(controls) - return drift, controls - - def get_sparse_Hamiltonians(self): - drift, controls = self.get_Hamiltonians - sparse_drift = self.blowup_excitations(drift) - sparse_controls = tf.vectorized_map(self.blowup_excitations, controls) - return sparse_drift, sparse_controls + def get_control_ops(self) -> Dict[str, tf.Tensor]: + """Returns a dictionary of control operators""" + hks = {} + for key, drive in self.drives.items(): + hks[key] = drive.h + return hks - def _get_Hamiltonian(self, signal=None): + def _get_Hamiltonian(self, signal={}): """Get a hamiltonian with an optional signal. This will return an hamiltonian over time. Can be used e.g. for tuning the frequency of a transmon, where the control hamiltonian is not easily accessible. If max.excitation is non-zero the resulting Hamiltonian is cut accordingly""" - if signal is None: - if self.dressed: - signal_hamiltonian = self.dressed_drift_ham - else: - signal_hamiltonian = self.drift_ham - else: - if self.dressed: - hamiltonians = copy.deepcopy(self.__dressed_hamiltonians) - transform = self.transform - else: - hamiltonians = copy.deepcopy(self.__hamiltonians) - transform = None - for key, sig in signal.items(): - if key in self.subsystems: - hamiltonians[key] = self.subsystems[key].get_Hamiltonian( - sig, transform - ) - elif key in self.couplings: - hamiltonians[key] = self.couplings[key].get_Hamiltonian( - sig, transform - ) - else: - raise Exception(f"Signal channel {key} not in model systems") - - signal_hamiltonian = sum( - [ - tf.expand_dims(h, 0) if len(h.shape) == 2 else h - for h in hamiltonians.values() - ] - ) + signal_hamiltonian = self.drift_ham + for key, sig in signal.items(): + signal_hamiltonian += self.drives[key].get_Hamiltonian(sig) if self.max_excitations: signal_hamiltonian = self.cut_excitations(signal_hamiltonian) @@ -416,12 +385,11 @@ def _get_interaction_Hamiltonian(self, signal: Dict = {}) -> tf.Tensor: ts = tf.expand_dims( tf.expand_dims(signal["d1"]["ts"], -1), -1 ) # ts as batch dimension - hamiltonians = [] + signal_hamiltonian = tf.expand_dims(tf.zeros_like(self.drift_ham), 0) transform = tf.linalg.expm(-1j * drift * tf_utils.tf_complexify(ts)) for key, sig in signal.items(): h_of_t = self.drives[key].get_Hamiltonian(sig) - hamiltonians.append(tf.linalg.adjoint(transform) @ h_of_t @ transform) - signal_hamiltonian = tf.reduce_sum(hamiltonians, axis=0) + signal_hamiltonian += tf.linalg.adjoint(transform) @ h_of_t @ transform if self.max_excitations: signal_hamiltonian = self.cut_excitations(signal_hamiltonian) @@ -432,32 +400,36 @@ def get_sparse_Hamiltonian(self, signal=None): return self.blowup_excitations(self.get_Hamiltonian(signal)) def get_Lindbladians(self): - if self.dressed: - return self.dressed_col_ops - else: - return self.col_ops + return self.col_ops def update_model(self, ordered=True): self.update_Hamiltonians() - if self.lindbladian: + if "lindbladian" in self.frame: self.update_Lindbladians() - if self.dressed: + if "dressed" in self.frame: self.update_dressed(ordered=ordered) def update_Hamiltonians(self): """Recompute the matrix representations of the Hamiltonians.""" - control_hams = dict() - hamiltonians = dict() + hamiltonians = [] for key, sub in self.subsystems.items(): - hamiltonians[key] = sub.get_Hamiltonian() + hamiltonians.append(sub.get_Hamiltonian()) for key, line in self.couplings.items(): - hamiltonians[key] = line.get_Hamiltonian() - for key, line in self.drives.items(): - control_hams[key] = line.get_Hamiltonian(signal=True) + hamiltonians.append(line.get_Hamiltonian()) - self.drift_ham = sum(hamiltonians.values()) - self.control_hams = control_hams - self.__hamiltonians = hamiltonians + self.drift_ham = tf.reduce_sum(hamiltonians, axis=0) + for drive in self.drives.values(): + conn = drive.connected + opers_list = [] + for sub in conn: + try: + indx = self.names.index(sub) + except ValueError as ve: + raise Exception( + f"C3:ERROR: Trying to couple to unkown subcomponent: {sub}" + ) from ve + opers_list.append(self.ann_opers[indx]) + drive.init_Hs(opers_list) def update_Lindbladians(self): """Return Lindbladian operators and their prefactors.""" @@ -512,33 +484,17 @@ def update_dressed(self, ordered=True): """Compute the Hamiltonians in the dressed basis by diagonalizing the drift and applying the resulting transformation to the control Hamiltonians.""" self.update_drift_eigen(ordered=ordered) - dressed_control_hams = {} - dressed_col_ops = [] - dressed_hamiltonians = dict() - for k, h in self.__hamiltonians.items(): - dressed_hamiltonians[k] = tf.matmul( - tf.matmul(tf.linalg.adjoint(self.transform), h), self.transform - ) - dressed_drift_ham = tf.matmul( - tf.matmul(tf.linalg.adjoint(self.transform), self.drift_ham), self.transform - ) - for key in self.control_hams: - dressed_control_hams[key] = tf.matmul( - tf.matmul(tf.linalg.adjoint(self.transform), self.control_hams[key]), - self.transform, + self.drift_ham = tf.linalg.diag(tf_utils.tf_complexify(self.eigenframe)) + for drive in self.drives.values(): + drive.h = tf.matmul( + tf.matmul(tf.linalg.adjoint(self.transform), drive.h), self.transform ) - self.dressed_drift_ham = dressed_drift_ham - self.dressed_control_hams = dressed_control_hams - self.__dressed_hamiltonians = dressed_hamiltonians - if self.lindbladian: + if "lindbladian" in self.frame: for col_op in self.col_ops: - dressed_col_ops.append( - tf.matmul( - tf.matmul(tf.linalg.adjoint(self.transform), col_op), - self.transform, - ) + col_op = tf.matmul( + tf.matmul(tf.linalg.adjoint(self.transform), col_op), + self.transform, ) - self.dressed_col_ops = dressed_col_ops def get_Frame_Rotation(self, t_final: np.float64, freqs: dict, framechanges: dict): """ @@ -564,8 +520,8 @@ def get_Frame_Rotation(self, t_final: np.float64, freqs: dict, framechanges: dic for line in freqs.keys(): freq = freqs[line] framechange = framechanges[line] - if line in self.couplings: - qubit = self.couplings[line].connected[0] + if line in self.drives: + qubit = self.drives[line].connected[0] elif line in self.subsystems: qubit = line else: @@ -585,7 +541,7 @@ def get_Frame_Rotation(self, t_final: np.float64, freqs: dict, framechanges: dic return FR def get_qubit_freqs(self) -> List[float]: - es = tf.math.real(tf.linalg.diag_part(self.dressed_drift_ham)) + es = self.eigenframe frequencies = [] for i in range(len(self.dims)): state = [0] * len(self.dims) From 6c9c304ede96b57cc955d1073df71a8eb5841ba7 Mon Sep 17 00:00:00 2001 From: Nicolas Wittler Date: Fri, 10 Jun 2022 15:47:51 +0000 Subject: [PATCH 05/14] Changed interface to Model class --- c3/experiment.py | 13 ++-- c3/libraries/chip.py | 19 ++--- c3/libraries/propagation.py | 119 ++++---------------------------- c3/optimizers/optimalcontrol.py | 4 +- 4 files changed, 24 insertions(+), 131 deletions(-) diff --git a/c3/experiment.py b/c3/experiment.py index 21e49c2e..e7e9b584 100755 --- a/c3/experiment.py +++ b/c3/experiment.py @@ -64,7 +64,6 @@ def __init__(self, pmap: ParameterMap = None, prop_method=None, sim_res=100e9): self.created_by = None self.logdir: str = "" self.propagate_batch_size = None - self.use_control_fields = True self.overwrite_propagators = True # Keep only currently computed propagators self.compute_propagators_timestamp = 0 self.stop_partial_propagator_gradient = True @@ -259,7 +258,6 @@ def asdict(self) -> Dict: exp_dict["generator"] = self.pmap.generator.asdict() exp_dict["options"] = { "propagate_batch_size": self.propagate_batch_size, - "use_control_fields": self.use_control_fields, "overwrite_propagators": self.overwrite_propagators, "stop_partial_propagator_gradient": self.stop_partial_propagator_gradient, } @@ -296,7 +294,7 @@ def evaluate_legacy(self, sequences, psi_init: tf.Tensor = None): for gate in sequence: psi_t = tf.matmul(self.propagators[gate], psi_t) - pops = self.populations(psi_t, model.lindbladian) + pops = self.populations(psi_t, "lindbladian" in model.frame) populations.append(pops) return populations @@ -329,7 +327,7 @@ def evaluate_qasm(self, sequences, psi_init: tf.Tensor = None): for gate in sequence: psi_t = tf.matmul(self.lookup_gate(**gate), psi_t) - pops = self.populations(psi_t, model.lindbladian) + pops = self.populations(psi_t, "lindbladian" in model.frame) populations.append(pops) return populations @@ -496,7 +494,6 @@ def compute_propagators(self): f" Available gates are:\n {list(instructions.keys())}." ) - model.controllability = self.use_control_fields steps = int((instr.t_end - instr.t_start) * self.sim_res) result = self.propagation( model, generator, instr, self.folding_stack[steps] @@ -504,7 +501,7 @@ def compute_propagators(self): U = result["U"] dUs = result["dUs"] self.ts = result["ts"] - if model.use_FR: + if "rotating" in model.frame: # TODO change LO freq to at the level of a line freqs = {} framechanges = {} @@ -525,7 +522,7 @@ def compute_propagators(self): ) t_final = tf.constant(instr.t_end - instr.t_start, dtype=tf.complex128) FR = model.get_Frame_Rotation(t_final, freqs, framechanges) - if model.lindbladian: + if "lindbladian" in model.frame: SFR = tf_super(FR) U = tf.matmul(SFR, U) self.FR = SFR @@ -533,7 +530,7 @@ def compute_propagators(self): U = tf.matmul(FR, U) self.FR = FR if model.dephasing_strength != 0.0: - if not model.lindbladian: + if "lindbladian" not in model.frame: raise ValueError("Dephasing can only be added when lindblad is on.") else: amps = {} diff --git a/c3/libraries/chip.py b/c3/libraries/chip.py index e55c3c60..a15f23a2 100755 --- a/c3/libraries/chip.py +++ b/c3/libraries/chip.py @@ -1220,19 +1220,8 @@ def init_Hs(self, ann_opers: list): hs.append(tf.constant(self.hamiltonian_func(a), dtype=tf.complex128)) self.h: tf.Tensor = tf.cast(sum(hs), tf.complex128) - def get_Hamiltonian( - self, signal: Union[Dict, bool] = None, transform: tf.Tensor = None - ) -> tf.Tensor: - if signal is None: - return tf.zeros_like(self.h) + def get_Hamiltonian(self, signal: Dict = {}) -> tf.Tensor: h = self.h - if transform is not None: - transform = tf.cast(transform, tf.complex128) - h = tf.matmul(tf.matmul(transform, h, adjoint_a=True), transform) - - if signal is True: - return h - elif isinstance(signal, dict): - sig = tf.cast(signal["values"], tf.complex128) - sig = tf.reshape(sig, [sig.shape[0], 1, 1]) - return tf.expand_dims(h, 0) * sig + sig = tf.cast(signal["values"], tf.complex128) + sig = tf.reshape(sig, [sig.shape[0], 1, 1]) + return tf.expand_dims(h, 0) * sig diff --git a/c3/libraries/propagation.py b/c3/libraries/propagation.py index 244c6d33..a2a2e9b9 100644 --- a/c3/libraries/propagation.py +++ b/c3/libraries/propagation.py @@ -72,66 +72,6 @@ def rk4_step(h, psi, dt): def get_hs_of_t_ts( model: Model, gen: Generator, instr: Instruction, prop_res=1 -) -> Dict: - if model.controllability: - hs_of_ts = _get_hs_of_t_ts_controlled(model, gen, instr, prop_res) - else: - hs_of_ts = _get_hs_of_t_ts(model, gen, instr, prop_res) - return hs_of_ts - - -def _get_hs_of_t_ts_controlled( - model: Model, gen: Generator, instr: Instruction, prop_res=1 -) -> Dict: - """ - Return a Dict containing: - - - a list of - - H(t) = H_0 + sum_k c_k H_k. - - - time slices ts - - - timestep dt - - Parameters - ---------- - prop_res : tf.float - resolution required by the propagation method - h0 : tf.tensor - Drift Hamiltonian. - hks : list of tf.tensor - List of control Hamiltonians. - cflds_t : array of tf.float - Vector of control field values at time t. - ts : float - Length of one time slice. - """ - Hs = [] - ts = [] - gen.resolution = prop_res * gen.resolution - signal = gen.generate_signals(instr) - h0, hctrls = model.get_Hamiltonians() - signals = [] - hks = [] - for key in signal: - signals.append(signal[key]["values"]) - ts = signal[key]["ts"] - hks.append(hctrls[key]) - cflds = tf.cast(signals, tf.complex128) - hks = tf.cast(hks, tf.complex128) - for ii in range(cflds[0].shape[0]): - cf_t = [] - for fields in cflds: - cf_t.append(tf.cast(fields[ii], tf.complex128)) - Hs.append(sum_h0_hks(h0, hks, cf_t)) - - dt = tf.constant(ts[1 * prop_res].numpy() - ts[0].numpy(), dtype=tf.complex128) - return {"Hs": Hs, "ts": ts[::prop_res], "dt": dt} - - -def _get_hs_of_t_ts( - model: Model, gen: Generator, instr: Instruction, prop_res=1 ) -> Dict: """ Return a Dict containing: @@ -245,23 +185,14 @@ def pwc(model: Model, gen: Generator, instr: Instruction, folding_stack: list) - ts = [] h0 = model.get_Hamiltonian(signal) ts_list = [sig["ts"][1:] for sig in signal.values()] - ts = tf.constant(tf.math.reduce_mean(ts_list, axis=0)) - hks = None - signals = None - if not np.all(tf.math.reduce_variance(ts_list, axis=0) < 1e-5 * (ts[1] - ts[0])): - raise Exception("C3Error:Something with the times happend.") - if not np.all( - tf.math.reduce_variance(ts[1:] - ts[:-1]) < 1e-5 * (ts[1] - ts[0]) # type: ignore - ): - raise Exception("C3Error:Something with the times happend.") + ts = ts_list[-1] dt = ts[1] - ts[0] batch_size = tf.constant(len(h0), tf.int32) - dUs = tf_batch_propagate(h0, hks, signals, dt, batch_size=batch_size) + dUs = tf_batch_propagate(h0, dt, batch_size=batch_size) - # U = tf_matmul_left(tf.cast(dUs, tf.complex128)) U = tf_matmul_n(dUs, folding_stack) if model.max_excitations: @@ -353,20 +284,9 @@ def tf_dU_of_t_lind(h0, hks, col_ops, cflds_t, dt): return dU -def tf_propagation_vectorized(h0, hks, cflds_t, dt): +def tf_propagation_vectorized(h_of_t, dt): dt = tf.cast(dt, dtype=tf.complex128) - if hks is not None and cflds_t is not None: - cflds_t = tf.cast(cflds_t, dtype=tf.complex128) - hks = tf.cast(hks, dtype=tf.complex128) - cflds = tf.expand_dims(tf.expand_dims(cflds_t, 2), 3) - hks = tf.expand_dims(hks, 1) - if len(h0.shape) < 3: - h0 = tf.expand_dims(h0, 0) - prod = cflds * hks - h = h0 + tf.reduce_sum(prod, axis=0) - else: - h = tf.cast(h0, tf.complex128) - dh = -1.0j * h * dt + dh = -1.0j * h_of_t * dt return tf.linalg.expm(dh) @@ -387,7 +307,7 @@ def pwc_trott_drift(h0, hks, cflds_t, dt): return dUs -def tf_batch_propagate(hamiltonian, hks, signals, dt, batch_size): +def tf_batch_propagate(hamiltonian, dt, batch_size): """ Propagate signal in batches Parameters @@ -407,32 +327,19 @@ def tf_batch_propagate(hamiltonian, hks, signals, dt, batch_size): ------- """ - if signals is not None: - batches = int(tf.math.ceil(signals.shape[0] / batch_size)) - batch_array = tf.TensorArray( - signals.dtype, size=batches, dynamic_size=False, infer_shape=False - ) - for i in range(batches): - batch_array = batch_array.write( - i, signals[i * batch_size : i * batch_size + batch_size] - ) - else: - batches = int(tf.math.ceil(hamiltonian.shape[0] / batch_size)) - batch_array = tf.TensorArray( - hamiltonian.dtype, size=batches, dynamic_size=False, infer_shape=False + batches = int(tf.math.ceil(hamiltonian.shape[0] / batch_size)) + batch_array = tf.TensorArray( + hamiltonian.dtype, size=batches, dynamic_size=False, infer_shape=False + ) + for i in range(batches): + batch_array = batch_array.write( + i, hamiltonian[i * batch_size : i * batch_size + batch_size] ) - for i in range(batches): - batch_array = batch_array.write( - i, hamiltonian[i * batch_size : i * batch_size + batch_size] - ) dUs_array = tf.TensorArray(tf.complex128, size=batches, infer_shape=False) for i in range(batches): x = batch_array.read(i) - if signals is not None: - result = tf_propagation_vectorized(hamiltonian, hks, x, dt) - else: - result = tf_propagation_vectorized(x, None, None, dt) + result = tf_propagation_vectorized(x, dt) dUs_array = dUs_array.write(i, result) return dUs_array.concat() diff --git a/c3/optimizers/optimalcontrol.py b/c3/optimizers/optimalcontrol.py index 116955ca..0bc2c7da 100755 --- a/c3/optimizers/optimalcontrol.py +++ b/c3/optimizers/optimalcontrol.py @@ -85,7 +85,7 @@ def __init__( def set_fid_func(self, fid_func) -> None: if type(fid_func) is str: - if self.pmap.model.lindbladian: + if "lindbladian" in self.pmap.model.frame: fid = "lindbladian_" + fid_func else: fid = fid_func @@ -98,7 +98,7 @@ def set_fid_func(self, fid_func) -> None: self.fid_func = fid_func def set_callback_fids(self, callback_fids) -> None: - if self.pmap.model.lindbladian: + if "lindbladian" in self.pmap.model.frame: cb_fids = ["lindbladian_" + f for f in callback_fids] else: cb_fids = callback_fids From 657c98bbc84ff287ea64eaa349b8d50a79316651 Mon Sep 17 00:00:00 2001 From: Nicolas Wittler Date: Fri, 10 Jun 2022 15:48:49 +0000 Subject: [PATCH 06/14] Updated check for lindbladian simulation --- examples/Full_loop_single_qubit.ipynb | 4 ++-- examples/Piecewise_constant_controls.ipynb | 4 ++-- examples/two_qubit_entangling_gate.ipynb | 8 ++++---- examples/two_qubits.ipynb | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/Full_loop_single_qubit.ipynb b/examples/Full_loop_single_qubit.ipynb index 4dd84ce2..65c8d881 100644 --- a/examples/Full_loop_single_qubit.ipynb +++ b/examples/Full_loop_single_qubit.ipynb @@ -443,11 +443,11 @@ " model = exp.pmap.model\n", " dUs = exp.partial_propagators\n", " psi_t = psi_init.numpy()\n", - " pop_t = exp.populations(psi_t, model.lindbladian)\n", + " pop_t = exp.populations(psi_t, "lindbladian" in model.frame)\n", " for gate in seq:\n", " for du in dUs[gate]:\n", " psi_t = np.matmul(du.numpy(), psi_t)\n", - " pops = exp.populations(psi_t, model.lindbladian)\n", + " pops = exp.populations(psi_t, "lindbladian" in model.frame)\n", " pop_t = np.append(pop_t, pops, axis=1)\n", "\n", " fig, axs = plt.subplots(1, 1)\n", diff --git a/examples/Piecewise_constant_controls.ipynb b/examples/Piecewise_constant_controls.ipynb index 875a0d51..369707a8 100644 --- a/examples/Piecewise_constant_controls.ipynb +++ b/examples/Piecewise_constant_controls.ipynb @@ -372,11 +372,11 @@ " exp.compute_propagators()\n", " dUs = exp.partial_propagators\n", " psi_t = psi_init.numpy()\n", - " pop_t = exp.populations(psi_t, model.lindbladian)\n", + " pop_t = exp.populations(psi_t, "lindbladian" in model.frame)\n", " for gate in seq:\n", " for du in dUs[gate]:\n", " psi_t = np.matmul(du.numpy(), psi_t)\n", - " pops = exp.populations(psi_t, model.lindbladian)\n", + " pops = exp.populations(psi_t, "lindbladian" in model.frame)\n", " pop_t = np.append(pop_t, pops, axis=1)\n", "\n", " fig, axs = plt.subplots(1, 1)\n", diff --git a/examples/two_qubit_entangling_gate.ipynb b/examples/two_qubit_entangling_gate.ipynb index 703078fb..7f8ec3ed 100644 --- a/examples/two_qubit_entangling_gate.ipynb +++ b/examples/two_qubit_entangling_gate.ipynb @@ -765,11 +765,11 @@ " exp.compute_propagators()\n", " dUs = exp.partial_propagators\n", " psi_t = psi_init.numpy()\n", - " pop_t = exp.populations(psi_t, model.lindbladian)\n", + " pop_t = exp.populations(psi_t, "lindbladian" in model.frame)\n", " for gate in seq:\n", " for du in dUs[gate]:\n", " psi_t = np.matmul(du.numpy(), psi_t)\n", - " pops = exp.populations(psi_t, model.lindbladian)\n", + " pops = exp.populations(psi_t, "lindbladian" in model.frame)\n", " pop_t = np.append(pop_t, pops, axis=1)\n", "\n", " fig, axs = plt.subplots(1, 1)\n", @@ -837,11 +837,11 @@ " model = exp.pmap.model\n", " dUs = exp.partial_propagators\n", " psi_t = psi_init.numpy()\n", - " pop_t = exp.populations(psi_t, model.lindbladian)\n", + " pop_t = exp.populations(psi_t, "lindbladian" in model.frame)\n", " for gate in sequence:\n", " for du in dUs[gate]:\n", " psi_t = np.matmul(du, psi_t)\n", - " pops = exp.populations(psi_t, model.lindbladian)\n", + " pops = exp.populations(psi_t, "lindbladian" in model.frame)\n", " pop_t = np.append(pop_t, pops, axis=1)\n", " dims = [s.hilbert_dim for s in model.subsystems.values()]\n", " splitted = getQubitsPopulation(pop_t, dims)\n", diff --git a/examples/two_qubits.ipynb b/examples/two_qubits.ipynb index 031a4960..771c9c85 100644 --- a/examples/two_qubits.ipynb +++ b/examples/two_qubits.ipynb @@ -1099,11 +1099,11 @@ " exp.compute_propagators()\n", " dUs = exp.partial_propagators\n", " psi_t = psi_init.numpy()\n", - " pop_t = exp.populations(psi_t, model.lindbladian)\n", + " pop_t = exp.populations(psi_t, "lindbladian" in model.frame)\n", " for gate in seq:\n", " for du in dUs[gate]:\n", " psi_t = np.matmul(du.numpy(), psi_t)\n", - " pops = exp.populations(psi_t, model.lindbladian)\n", + " pops = exp.populations(psi_t, "lindbladian" in model.frame)\n", " pop_t = np.append(pop_t, pops, axis=1)\n", "\n", " fig, axs = plt.subplots(1, 1)\n", From 5fd4db7d393ac2b9d74470206594a71d69cb82f0 Mon Sep 17 00:00:00 2001 From: Nicolas Wittler Date: Fri, 10 Jun 2022 15:50:39 +0000 Subject: [PATCH 07/14] Better default for drift and updated tests for Model class interface --- c3/model.py | 2 +- test/conftest.py | 5 ++-- test/convert_cfgs_1.5.py | 53 +++++++++++++++++++++++++++++++++++ test/test_model.py | 15 ++++++---- test/test_parsers.py | 7 ++++- test/test_three_wave_mixer.py | 9 +++--- test/test_tunable_coupler.py | 9 ++++-- test/test_two_qubits.py | 3 +- 8 files changed, 85 insertions(+), 18 deletions(-) create mode 100755 test/convert_cfgs_1.5.py diff --git a/c3/model.py b/c3/model.py index 269cf54a..af1e4d47 100755 --- a/c3/model.py +++ b/c3/model.py @@ -54,7 +54,7 @@ def __init__( self.couplings: Dict[str, Coupling] = {} self.drives: Dict[str, Drive] = {} self.tasks: Dict = {} - self.drift_ham = None + self.drift_ham = tf.zeros([2, 2]) if subsystems: self.set_components(subsystems, couplings, drives, max_excitations) if tasks: diff --git a/test/conftest.py b/test/conftest.py index 11c9a73c..f65571a9 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -305,8 +305,9 @@ def get_two_qubit_chip() -> Experiment: ) model = Model( - [q1, q2], # Individual, self-contained components - [drive, drive2, q1q2], # Interactions between components + subsystems=[q1, q2], # Individual, self-contained components + couplings=[q1q2], + drives=[drive, drive2], # Interactions between components ) model.set_lindbladian(False) diff --git a/test/convert_cfgs_1.5.py b/test/convert_cfgs_1.5.py new file mode 100755 index 00000000..dd2604ba --- /dev/null +++ b/test/convert_cfgs_1.5.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +import argparse +import hjson +import shutil + +parser = argparse.ArgumentParser() +parser.add_argument( + "files", metavar="F", type=str, nargs="+", help="List of files to convert" +) + +args = parser.parse_args() + + +def convert(dct): + if "Drives" not in dct: + dct["Drives"] = {} + drv_keys = [] + for key, coup in dct["Couplings"].items(): + if coup["c3type"] == "Drive": + dct["Drives"][key] = coup + drv_keys.append(key) + for key in drv_keys: + dct["Couplings"].pop(key, None) + return dct + + +def write(cfg, dct): + with open(cfg, "w") as cfg_file: + hjson.dump(dct, cfg_file) + + +for cfg in args.files: + with open(cfg, "r") as cfg_file: + cfg_dct = hjson.load(cfg_file) + if "model" in cfg_dct: + if type(cfg_dct["model"]) is str: + # Just convert separate model file + model_str = cfg_dct["model"] + shutil.copy(model_str, model_str + ".old") + with open(model_str, "r") as cfg_file: + dct = hjson.load(cfg_file) + write(model_str, convert(dct)) + else: + # Convert embedded model dict + shutil.copy(cfg, cfg + ".old") + dct = convert(cfg_dct["model"]) + cfg_dct["model"] = dct + write(cfg, cfg_dct) + + elif "Couplings" in cfg_dct: + # Convert model file + shutil.copy(cfg, cfg + ".old") + write(cfg, convert(cfg_dct)) diff --git a/test/test_model.py b/test/test_model.py index d611e4ca..b7a8cf4e 100644 --- a/test/test_model.py +++ b/test/test_model.py @@ -94,15 +94,18 @@ ) model = Model( - [q1, q2], # Individual, self-contained components - [drive, drive2, q1q2], # Interactions between components - [conf_matrix, init_ground], # SPAM processing + subsystems=[q1, q2], # Individual, self-contained components + couplings=[q1q2], + drives=[drive, drive2], # Interactions between components + tasks=[conf_matrix, init_ground], # SPAM processing ) pmap = ParameterMap(model=model) model.set_dressed(False) -hdrift, hks = model.get_Hamiltonians() +hdrift = model.drift_ham +hks = model.get_control_ops() + with open("test/model.pickle", "rb") as filename: test_data = pickle.load(filename) @@ -158,10 +161,10 @@ def test_get_indeces() -> None: @pytest.mark.unit def test_model_update_by_parametermap() -> None: pmap.set_parameters([freq_q1 * 0.9995], [[("Q1", "freq")]]) - hdrift_a, _ = model.get_Hamiltonians() + hdrift_a = model.get_Hamiltonian() pmap.set_parameters([freq_q1 * 1.0005], [[("Q1", "freq")]]) - hdrift_b, _ = model.get_Hamiltonians() + hdrift_b = model.get_Hamiltonian() assert hdrift_a[3, 3] - hdrift_a[0, 0] == freq_q1 * 0.9995 * 2 * np.pi assert hdrift_b[3, 3] - hdrift_b[0, 0] == freq_q1 * 1.0005 * 2 * np.pi diff --git a/test/test_parsers.py b/test/test_parsers.py index e4b006cc..dcf393b1 100644 --- a/test/test_parsers.py +++ b/test/test_parsers.py @@ -35,7 +35,12 @@ def test_subsystems() -> None: @pytest.mark.unit def test_couplings() -> None: - assert list(model.couplings.keys()) == ["Q1-Q2", "d1", "d2"] + assert list(model.couplings.keys()) == ["Q1-Q2"] + + +@pytest.mark.unit +def test_drives() -> None: + assert list(model.drives.keys()) == ["d1", "d2"] @pytest.mark.unit diff --git a/test/test_three_wave_mixer.py b/test/test_three_wave_mixer.py index ac42eb17..997790b3 100644 --- a/test/test_three_wave_mixer.py +++ b/test/test_three_wave_mixer.py @@ -60,14 +60,15 @@ ) model = Model( - [S], # Individual, self-contained components - [drive], # Interactions between components - [conf_matrix, init_ground], # SPAM processing + subsystems=[S], # Individual, self-contained components + drives=[drive], # Interactions between components + tasks=[conf_matrix, init_ground], # SPAM processing ) model.set_dressed(False) -hdrift, hks = model.get_Hamiltonians() +hdrift = model.drift_ham +hks = model.get_control_ops() @pytest.mark.unit diff --git a/test/test_tunable_coupler.py b/test/test_tunable_coupler.py index da40f9f1..48f4b98c 100644 --- a/test/test_tunable_coupler.py +++ b/test/test_tunable_coupler.py @@ -149,10 +149,13 @@ connected=["TCQubit"], hamiltonian_func=hamiltonians.z_drive, ) -phys_components = [tc_at, q1, q2] -line_components = [q1tc, q2tc, q1q2, drive_q1, drive_q2, flux] -model = Mdl(phys_components, line_components, []) +model = Mdl( + subsystems=[tc_at, q1, q2], + couplings=[q1tc, q2tc, q1q2], + drives=[drive_q1, drive_q2, flux], + tasks=[], +) model.set_lindbladian(lindblad) model.set_dressed(dressed) diff --git a/test/test_two_qubits.py b/test/test_two_qubits.py index c015dfd7..0cedc986 100644 --- a/test/test_two_qubits.py +++ b/test/test_two_qubits.py @@ -33,7 +33,8 @@ def test_signals(get_two_qubit_chip) -> None: def test_hamiltonians(get_two_qubit_chip) -> None: """Compare Hamilonians""" model = get_two_qubit_chip.pmap.model - hdrift, hks = model.get_Hamiltonians() + hdrift = model.drift_ham + hks = model.get_control_ops() assert (hdrift.numpy() - test_data["hdrift"].numpy() < 1).any() for key in hks: almost_equal(hks[key], test_data["hks"][key]) From 804a9da4df53995eb1468c4ec1feeb7715d94e6e Mon Sep 17 00:00:00 2001 From: Nicolas Wittler Date: Fri, 10 Jun 2022 15:58:24 +0000 Subject: [PATCH 08/14] Deleted helper file. --- test/convert_cfgs_1.5.py | 53 ---------------------------------------- 1 file changed, 53 deletions(-) delete mode 100755 test/convert_cfgs_1.5.py diff --git a/test/convert_cfgs_1.5.py b/test/convert_cfgs_1.5.py deleted file mode 100755 index dd2604ba..00000000 --- a/test/convert_cfgs_1.5.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env python3 -import argparse -import hjson -import shutil - -parser = argparse.ArgumentParser() -parser.add_argument( - "files", metavar="F", type=str, nargs="+", help="List of files to convert" -) - -args = parser.parse_args() - - -def convert(dct): - if "Drives" not in dct: - dct["Drives"] = {} - drv_keys = [] - for key, coup in dct["Couplings"].items(): - if coup["c3type"] == "Drive": - dct["Drives"][key] = coup - drv_keys.append(key) - for key in drv_keys: - dct["Couplings"].pop(key, None) - return dct - - -def write(cfg, dct): - with open(cfg, "w") as cfg_file: - hjson.dump(dct, cfg_file) - - -for cfg in args.files: - with open(cfg, "r") as cfg_file: - cfg_dct = hjson.load(cfg_file) - if "model" in cfg_dct: - if type(cfg_dct["model"]) is str: - # Just convert separate model file - model_str = cfg_dct["model"] - shutil.copy(model_str, model_str + ".old") - with open(model_str, "r") as cfg_file: - dct = hjson.load(cfg_file) - write(model_str, convert(dct)) - else: - # Convert embedded model dict - shutil.copy(cfg, cfg + ".old") - dct = convert(cfg_dct["model"]) - cfg_dct["model"] = dct - write(cfg, cfg_dct) - - elif "Couplings" in cfg_dct: - # Convert model file - shutil.copy(cfg, cfg + ".old") - write(cfg, convert(cfg_dct)) From de2ff4e8c92f1906a4f130f7d53695e643b83d2d Mon Sep 17 00:00:00 2001 From: Nicolas Wittler Date: Tue, 12 Jul 2022 14:00:36 +0000 Subject: [PATCH 09/14] Added batch dimension in control ops. --- test/convert_cfgs_1.5.py | 53 ++++++++++++++++++++++++++++++++++++++++ test/test_model.py | 4 +-- test/test_two_qubits.py | 2 +- 3 files changed, 56 insertions(+), 3 deletions(-) create mode 100755 test/convert_cfgs_1.5.py diff --git a/test/convert_cfgs_1.5.py b/test/convert_cfgs_1.5.py new file mode 100755 index 00000000..dd2604ba --- /dev/null +++ b/test/convert_cfgs_1.5.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +import argparse +import hjson +import shutil + +parser = argparse.ArgumentParser() +parser.add_argument( + "files", metavar="F", type=str, nargs="+", help="List of files to convert" +) + +args = parser.parse_args() + + +def convert(dct): + if "Drives" not in dct: + dct["Drives"] = {} + drv_keys = [] + for key, coup in dct["Couplings"].items(): + if coup["c3type"] == "Drive": + dct["Drives"][key] = coup + drv_keys.append(key) + for key in drv_keys: + dct["Couplings"].pop(key, None) + return dct + + +def write(cfg, dct): + with open(cfg, "w") as cfg_file: + hjson.dump(dct, cfg_file) + + +for cfg in args.files: + with open(cfg, "r") as cfg_file: + cfg_dct = hjson.load(cfg_file) + if "model" in cfg_dct: + if type(cfg_dct["model"]) is str: + # Just convert separate model file + model_str = cfg_dct["model"] + shutil.copy(model_str, model_str + ".old") + with open(model_str, "r") as cfg_file: + dct = hjson.load(cfg_file) + write(model_str, convert(dct)) + else: + # Convert embedded model dict + shutil.copy(cfg, cfg + ".old") + dct = convert(cfg_dct["model"]) + cfg_dct["model"] = dct + write(cfg, cfg_dct) + + elif "Couplings" in cfg_dct: + # Convert model file + shutil.copy(cfg, cfg + ".old") + write(cfg, convert(cfg_dct)) diff --git a/test/test_model.py b/test/test_model.py index b7a8cf4e..f1b78f6d 100644 --- a/test/test_model.py +++ b/test/test_model.py @@ -125,8 +125,8 @@ def test_model_eigenfrequencies_2() -> None: @pytest.mark.unit def test_model_couplings() -> None: - assert hks["d1"][3, 0] == 1 - assert hks["d2"][1, 0] == 1 + assert hks["d1"][0, 3, 0] == 1 + assert hks["d2"][0, 1, 0] == 1 @pytest.mark.unit diff --git a/test/test_two_qubits.py b/test/test_two_qubits.py index 0cedc986..fb660ce1 100644 --- a/test/test_two_qubits.py +++ b/test/test_two_qubits.py @@ -37,7 +37,7 @@ def test_hamiltonians(get_two_qubit_chip) -> None: hks = model.get_control_ops() assert (hdrift.numpy() - test_data["hdrift"].numpy() < 1).any() for key in hks: - almost_equal(hks[key], test_data["hks"][key]) + almost_equal(hks[key][0], test_data["hks"][key]) @pytest.mark.tensorflow From 00e57e0b0fc29622a962fdc7cb3a317833352338 Mon Sep 17 00:00:00 2001 From: Nicolas Wittler Date: Tue, 12 Jul 2022 14:24:55 +0000 Subject: [PATCH 10/14] Fixed notebook formatting. --- examples/Full_loop_single_qubit.ipynb | 4 ++-- examples/Piecewise_constant_controls.ipynb | 4 ++-- examples/Simulated_calibration.ipynb | 10 ++++++---- examples/two_qubit_entangling_gate.ipynb | 8 ++++---- examples/two_qubits.ipynb | 4 ++-- 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/examples/Full_loop_single_qubit.ipynb b/examples/Full_loop_single_qubit.ipynb index 65c8d881..d9131d82 100644 --- a/examples/Full_loop_single_qubit.ipynb +++ b/examples/Full_loop_single_qubit.ipynb @@ -443,11 +443,11 @@ " model = exp.pmap.model\n", " dUs = exp.partial_propagators\n", " psi_t = psi_init.numpy()\n", - " pop_t = exp.populations(psi_t, "lindbladian" in model.frame)\n", + " pop_t = exp.populations(psi_t, \"lindbladian\" in model.frame)\n", " for gate in seq:\n", " for du in dUs[gate]:\n", " psi_t = np.matmul(du.numpy(), psi_t)\n", - " pops = exp.populations(psi_t, "lindbladian" in model.frame)\n", + " pops = exp.populations(psi_t, \"lindbladian\" in model.frame)\n", " pop_t = np.append(pop_t, pops, axis=1)\n", "\n", " fig, axs = plt.subplots(1, 1)\n", diff --git a/examples/Piecewise_constant_controls.ipynb b/examples/Piecewise_constant_controls.ipynb index 369707a8..96645dc8 100644 --- a/examples/Piecewise_constant_controls.ipynb +++ b/examples/Piecewise_constant_controls.ipynb @@ -372,11 +372,11 @@ " exp.compute_propagators()\n", " dUs = exp.partial_propagators\n", " psi_t = psi_init.numpy()\n", - " pop_t = exp.populations(psi_t, "lindbladian" in model.frame)\n", + " pop_t = exp.populations(psi_t, \"lindbladian\" in model.frame)\n", " for gate in seq:\n", " for du in dUs[gate]:\n", " psi_t = np.matmul(du.numpy(), psi_t)\n", - " pops = exp.populations(psi_t, "lindbladian" in model.frame)\n", + " pops = exp.populations(psi_t, \"lindbladian\" in model.frame)\n", " pop_t = np.append(pop_t, pops, axis=1)\n", "\n", " fig, axs = plt.subplots(1, 1)\n", diff --git a/examples/Simulated_calibration.ipynb b/examples/Simulated_calibration.ipynb index e85f2a49..58ec16be 100644 --- a/examples/Simulated_calibration.ipynb +++ b/examples/Simulated_calibration.ipynb @@ -708,11 +708,8 @@ } ], "metadata": { - "interpreter": { - "hash": "8fc56ae400e717d872a76f4d6b257151d16696a9d0a72e6998d355f9b43887c7" - }, "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3.8.10 64-bit", "language": "python", "name": "python3" }, @@ -727,6 +724,11 @@ "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.10" + }, + "vscode": { + "interpreter": { + "hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6" + } } }, "nbformat": 4, diff --git a/examples/two_qubit_entangling_gate.ipynb b/examples/two_qubit_entangling_gate.ipynb index 7f8ec3ed..530fb65d 100644 --- a/examples/two_qubit_entangling_gate.ipynb +++ b/examples/two_qubit_entangling_gate.ipynb @@ -765,11 +765,11 @@ " exp.compute_propagators()\n", " dUs = exp.partial_propagators\n", " psi_t = psi_init.numpy()\n", - " pop_t = exp.populations(psi_t, "lindbladian" in model.frame)\n", + " pop_t = exp.populations(psi_t, \"lindbladian\" in model.frame)\n", " for gate in seq:\n", " for du in dUs[gate]:\n", " psi_t = np.matmul(du.numpy(), psi_t)\n", - " pops = exp.populations(psi_t, "lindbladian" in model.frame)\n", + " pops = exp.populations(psi_t, \"lindbladian\" in model.frame)\n", " pop_t = np.append(pop_t, pops, axis=1)\n", "\n", " fig, axs = plt.subplots(1, 1)\n", @@ -837,11 +837,11 @@ " model = exp.pmap.model\n", " dUs = exp.partial_propagators\n", " psi_t = psi_init.numpy()\n", - " pop_t = exp.populations(psi_t, "lindbladian" in model.frame)\n", + " pop_t = exp.populations(psi_t, \"lindbladian\" in model.frame)\n", " for gate in sequence:\n", " for du in dUs[gate]:\n", " psi_t = np.matmul(du, psi_t)\n", - " pops = exp.populations(psi_t, "lindbladian" in model.frame)\n", + " pops = exp.populations(psi_t, \"lindbladian\" in model.frame)\n", " pop_t = np.append(pop_t, pops, axis=1)\n", " dims = [s.hilbert_dim for s in model.subsystems.values()]\n", " splitted = getQubitsPopulation(pop_t, dims)\n", diff --git a/examples/two_qubits.ipynb b/examples/two_qubits.ipynb index 771c9c85..cf5b5f27 100644 --- a/examples/two_qubits.ipynb +++ b/examples/two_qubits.ipynb @@ -1099,11 +1099,11 @@ " exp.compute_propagators()\n", " dUs = exp.partial_propagators\n", " psi_t = psi_init.numpy()\n", - " pop_t = exp.populations(psi_t, "lindbladian" in model.frame)\n", + " pop_t = exp.populations(psi_t, \"lindbladian\" in model.frame)\n", " for gate in seq:\n", " for du in dUs[gate]:\n", " psi_t = np.matmul(du.numpy(), psi_t)\n", - " pops = exp.populations(psi_t, "lindbladian" in model.frame)\n", + " pops = exp.populations(psi_t, \"lindbladian\" in model.frame)\n", " pop_t = np.append(pop_t, pops, axis=1)\n", "\n", " fig, axs = plt.subplots(1, 1)\n", From e87df50e681e971320a3e05ee7fe75e98e52385f Mon Sep 17 00:00:00 2001 From: Nicolas Wittler Date: Wed, 13 Jul 2022 14:59:45 +0000 Subject: [PATCH 11/14] Interaction picture method and separating drives --- c3/libraries/chip.py | 28 +++++++++++++++++++---- c3/model.py | 54 +++++++++++++++++++++++++------------------- 2 files changed, 55 insertions(+), 27 deletions(-) diff --git a/c3/libraries/chip.py b/c3/libraries/chip.py index a15f23a2..80bd9e20 100755 --- a/c3/libraries/chip.py +++ b/c3/libraries/chip.py @@ -41,7 +41,7 @@ def __init__(self, **props): super().__init__(**props) self.Hs = {} self.collapse_ops = {} - self.drive_line = None + self.has_drive = False self.index = None def set_subspace_index(self, index): @@ -327,6 +327,7 @@ def __init__( hilbert_dim=hilbert_dim, params=params, ) + self.has_drive = True if freq: self.params["freq"] = freq if phi: @@ -1138,6 +1139,7 @@ def __init__(self, **props): self.hamiltonian_func = hamiltonians[h_func] super().__init__(**props) self.Hs = {} + self.has_drive = False def asdict(self) -> dict: params = {} @@ -1214,14 +1216,32 @@ class Drive(LineComponent): """ + def __init__( + self, + name, + desc=None, + comment=None, + connected: List[str] = None, + params=None, + hamiltonian_func=None, + ): + super().__init__( + name=name, + desc=desc, + comment=comment, + params=params, + connected=connected, + hamiltonian_func=hamiltonian_func, + ) + self.has_drive = True + def init_Hs(self, ann_opers: list): hs = [] for a in ann_opers: hs.append(tf.constant(self.hamiltonian_func(a), dtype=tf.complex128)) - self.h: tf.Tensor = tf.cast(sum(hs), tf.complex128) + self.h = tf.expand_dims(tf.reduce_sum(hs, axis=0), 0) def get_Hamiltonian(self, signal: Dict = {}) -> tf.Tensor: - h = self.h sig = tf.cast(signal["values"], tf.complex128) sig = tf.reshape(sig, [sig.shape[0], 1, 1]) - return tf.expand_dims(h, 0) * sig + return self.h * sig diff --git a/c3/model.py b/c3/model.py index af1e4d47..761f08f8 100755 --- a/c3/model.py +++ b/c3/model.py @@ -53,13 +53,14 @@ def __init__( self.subsystems: Dict = {} self.couplings: Dict[str, Coupling] = {} self.drives: Dict[str, Drive] = {} + self.controllable: Dict = {} + self.drift: Dict = {} self.tasks: Dict = {} self.drift_ham = tf.zeros([2, 2]) if subsystems: self.set_components(subsystems, couplings, drives, max_excitations) if tasks: self.set_tasks(tasks) - self.get_Hamiltonian = self._get_Hamiltonian def get_ground_state(self) -> tf.constant: gs = [[0] * self.tot_dim] @@ -95,12 +96,19 @@ def set_components( ) -> None: for comp in subsystems: self.subsystems[comp.name] = comp + if comp.has_drive: + self.controllable[comp.name] = comp + self.drift[comp.name] = comp for coup in couplings: self.couplings[coup.name] = coup if len(set(coup.connected) - set(self.subsystems.keys())) > 0: raise Exception("Tried to couple non-existent devices.") + if coup.has_drive: + self.controllable[coup.name] = coup + self.drift[coup.name] = coup for drive in drives: self.drives[drive.name] = drive + self.controllable[drive.name] = drive # Check that the target of a drive exists and is store the info in the target. self.__check_drive_connect(drive) if len(set(drive.connected) - set(self.subsystems.keys())) > 0: @@ -341,6 +349,22 @@ def set_lindbladian(self, lindbladian: bool) -> None: self.frame.discard("lindbladian") self.update_model() + def set_interaction_picture( + self, ham_S: tf.Tensor, ts: tf.Tensor = tf.constant(0) + ) -> None: + """ + Transform to the interaction picture given a time-independent Hamiltonian + ..math:: H(t) = H_S + H_I(t) + such that the resulting Hamiltonian will be + ..math:: \\hat H(t) = \\exp(-i H_S t) H_I(t) \\exp(i H_S t) + """ + ham_sys = tf.expand_dims(ham_S, 0) # create batch dimension + ts = tf.expand_dims(tf.expand_dims(ts, -1), -1) # ts as batch dimension + transform = tf.linalg.expm(-1j * ham_sys * tf_utils.tf_complexify(ts)) + self.drift_ham -= ham_S + for drives in self.drives.values(): + drives.h = transform @ drives.h @ tf.linalg.adjoint(transform) + def set_FR(self, use_FR: bool) -> None: """ Setter for the frame rotation option for adjusting the individual rotating @@ -367,29 +391,15 @@ def get_control_ops(self) -> Dict[str, tf.Tensor]: hks[key] = drive.h return hks - def _get_Hamiltonian(self, signal={}): + def get_Hamiltonian(self, signal={}): """Get a hamiltonian with an optional signal. This will return an hamiltonian over time. Can be used e.g. for tuning the frequency of a transmon, where the control hamiltonian is not easily accessible. If max.excitation is non-zero the resulting Hamiltonian is cut accordingly""" signal_hamiltonian = self.drift_ham - for key, sig in signal.items(): - signal_hamiltonian += self.drives[key].get_Hamiltonian(sig) - - if self.max_excitations: - signal_hamiltonian = self.cut_excitations(signal_hamiltonian) - - return signal_hamiltonian - - def _get_interaction_Hamiltonian(self, signal: Dict = {}) -> tf.Tensor: - drift = tf.expand_dims(self.drift_ham, 0) # create batch dimension - ts = tf.expand_dims( - tf.expand_dims(signal["d1"]["ts"], -1), -1 - ) # ts as batch dimension - signal_hamiltonian = tf.expand_dims(tf.zeros_like(self.drift_ham), 0) - transform = tf.linalg.expm(-1j * drift * tf_utils.tf_complexify(ts)) - for key, sig in signal.items(): - h_of_t = self.drives[key].get_Hamiltonian(sig) - signal_hamiltonian += tf.linalg.adjoint(transform) @ h_of_t @ transform + for key in self.controllable.keys(): + signal_hamiltonian += self.controllable[key].get_Hamiltonian( + signal.get(key) + ) if self.max_excitations: signal_hamiltonian = self.cut_excitations(signal_hamiltonian) @@ -412,10 +422,8 @@ def update_model(self, ordered=True): def update_Hamiltonians(self): """Recompute the matrix representations of the Hamiltonians.""" hamiltonians = [] - for key, sub in self.subsystems.items(): + for sub in self.drift.values(): hamiltonians.append(sub.get_Hamiltonian()) - for key, line in self.couplings.items(): - hamiltonians.append(line.get_Hamiltonian()) self.drift_ham = tf.reduce_sum(hamiltonians, axis=0) for drive in self.drives.values(): From 36ec30fcb4ad57a3e4b83c53f578f199759b9904 Mon Sep 17 00:00:00 2001 From: Nicolas Wittler Date: Tue, 16 Aug 2022 13:17:07 +0000 Subject: [PATCH 12/14] Cutting time-dep hamiltonian to signal length --- c3/libraries/chip.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c3/libraries/chip.py b/c3/libraries/chip.py index 80bd9e20..3d159d8e 100755 --- a/c3/libraries/chip.py +++ b/c3/libraries/chip.py @@ -1244,4 +1244,4 @@ def init_Hs(self, ann_opers: list): def get_Hamiltonian(self, signal: Dict = {}) -> tf.Tensor: sig = tf.cast(signal["values"], tf.complex128) sig = tf.reshape(sig, [sig.shape[0], 1, 1]) - return self.h * sig + return self.h[: sig.shape[0]] * sig From 6d67a21790c463b4b4715001be64831d53ccbec4 Mon Sep 17 00:00:00 2001 From: Nicolas Wittler Date: Tue, 16 Aug 2022 13:18:09 +0000 Subject: [PATCH 13/14] ISWAP and rootISWAP --- c3/libraries/constants.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/c3/libraries/constants.py b/c3/libraries/constants.py index aa29b53f..161b205b 100755 --- a/c3/libraries/constants.py +++ b/c3/libraries/constants.py @@ -79,7 +79,16 @@ ) / np.sqrt(2), "iswap": np.array( - [[1, 0, 0, 0], [0, 0, 1j, 0], [0, 1j, 0, 0], [0, 0, 0, 1]], dtype=np.complex128 + [[1, 0, 0, 0], [0, 0, -1j, 0], [0, -1j, 0, 0], [0, 0, 0, 1]], + dtype=np.complex128, + ), + "iswap90": np.array( + [[0, 0, 0, 0], [0, 1, -1j, 0], [0, -1j, 1, 0], [0, 0, 0, 0]], + dtype=np.complex128, + ) + / np.sqrt(2) + + np.array( + [[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1]], dtype=np.complex128 ), "cz": np.diag(np.array([1, 1, 1, -1], dtype=np.complex128)), "ccz": np.diag(np.array([1, 1, 1, 1, 1, 1, 1, -1], dtype=np.complex128)), From d77091b94b4938d1c0958f4f93a802a3fe5a03fc Mon Sep 17 00:00:00 2001 From: Nicolas Wittler Date: Tue, 16 Aug 2022 13:40:55 +0000 Subject: [PATCH 14/14] Method to compute interaction picture hamiltonian --- c3/model.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/c3/model.py b/c3/model.py index 761f08f8..374a616c 100755 --- a/c3/model.py +++ b/c3/model.py @@ -358,12 +358,14 @@ def set_interaction_picture( such that the resulting Hamiltonian will be ..math:: \\hat H(t) = \\exp(-i H_S t) H_I(t) \\exp(i H_S t) """ + self.ts = ts ham_sys = tf.expand_dims(ham_S, 0) # create batch dimension ts = tf.expand_dims(tf.expand_dims(ts, -1), -1) # ts as batch dimension transform = tf.linalg.expm(-1j * ham_sys * tf_utils.tf_complexify(ts)) self.drift_ham -= ham_S for drives in self.drives.values(): drives.h = transform @ drives.h @ tf.linalg.adjoint(transform) + self.frame.add("interaction") def set_FR(self, use_FR: bool) -> None: """ @@ -418,6 +420,8 @@ def update_model(self, ordered=True): self.update_Lindbladians() if "dressed" in self.frame: self.update_dressed(ordered=ordered) + if "interaction" in self.frame: + self.set_interaction_picture(self.drift_ham, self.ts) def update_Hamiltonians(self): """Recompute the matrix representations of the Hamiltonians."""