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..3d159d8e 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,25 +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: Union[Dict, bool] = None, transform: tf.Tensor = None - ) -> tf.Tensor: - if signal is None: - return tf.zeros_like(self.h) - 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 + 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.shape[0]] * sig 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)), diff --git a/c3/libraries/propagation.py b/c3/libraries/propagation.py index e711788a..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: @@ -243,38 +183,16 @@ 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 = 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: @@ -366,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) @@ -400,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 @@ -420,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/model.py b/c3/model.py index 432bc2b8..374a616c 100755 --- a/c3/model.py +++ b/c3/model.py @@ -3,14 +3,13 @@ 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, Union +from typing import Dict, List, Tuple class Model: @@ -40,24 +39,28 @@ class Model: """ - def __init__(self, subsystems=None, couplings=None, tasks=None, max_excitations=0): - self.dressed = True - self.lindbladian = False - self.use_FR = True + def __init__( + self, + subsystems: List[PhysicalComponent] = [], + couplings: List[Coupling] = [], + drives: List[Drive] = [], + tasks: List = [], + max_excitations=0, + ): + self.frame = set(["dressed", "rotating"]) self.dephasing_strength = 0.0 - self.params = {} - self.subsystems: dict = dict() - self.couplings: Dict[str, Union[Drive, Coupling]] = {} - self.tasks: dict = dict() - self.drift_ham = None - self.dressed_drift_ham = None - self.__hamiltonians = None - self.__dressed_hamiltonians = None + self.params: Dict = {} + 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, max_excitations) + self.set_components(subsystems, couplings, drives, max_excitations) if tasks: self.set_tasks(tasks) - self.controllability = True def get_ground_state(self) -> tf.constant: gs = [[0] * self.tot_dim] @@ -68,7 +71,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() @@ -84,19 +87,39 @@ 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: 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 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. - if isinstance(comp, Drive): - self.__check_drive_connect(comp) - if len(set(comp.connected) - set(self.subsystems.keys())) > 0: - raise Exception("Tried to connect non-existent devices.") + 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() @@ -161,6 +184,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 +263,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(): @@ -238,8 +280,8 @@ def fromdict(self, cfg: dict) -> None: self.set_tasks(tasks) if "use_dressed_basis" in cfg: - self.dressed = cfg["use_dressed_basis"] - self.set_components(subsystems, couplings) + self.set_dressed(cfg["use_dressed_basis"]) + self.set_components(subsystems, couplings, drives) self.__create_labels() self.__create_annihilators() self.__create_matrix_representations() @@ -285,7 +327,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: @@ -298,15 +343,39 @@ 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_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) + """ + 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: """ 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 @@ -317,60 +386,21 @@ 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 in self.controllable.keys(): + signal_hamiltonian += self.controllable[key].get_Hamiltonian( + signal.get(key) ) if self.max_excitations: @@ -382,33 +412,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) + 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.""" - control_hams = dict() - hamiltonians = dict() - 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) - - self.drift_ham = sum(hamiltonians.values()) - self.control_hams = control_hams - self.__hamiltonians = hamiltonians + hamiltonians = [] + for sub in self.drift.values(): + hamiltonians.append(sub.get_Hamiltonian()) + + 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.""" @@ -463,33 +496,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 + 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 ) - 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.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): """ @@ -515,8 +532,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: @@ -536,7 +553,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) 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 diff --git a/examples/Full_loop_single_qubit.ipynb b/examples/Full_loop_single_qubit.ipynb index 4dd84ce2..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, 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..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, 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/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 703078fb..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, 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..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, 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/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/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/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.py b/test/test_model.py index d611e4ca..f1b78f6d 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) @@ -122,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 @@ -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_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 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..fb660ce1 100644 --- a/test/test_two_qubits.py +++ b/test/test_two_qubits.py @@ -33,10 +33,11 @@ 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]) + almost_equal(hks[key][0], test_data["hks"][key]) @pytest.mark.tensorflow