From eae7fcaf7a7bd00f8c4b205594a20598991f1850 Mon Sep 17 00:00:00 2001 From: rochisha0 Date: Tue, 22 Jul 2025 18:06:00 +0900 Subject: [PATCH 1/3] match grape infid with manually computed one --- src/qutip_qoc/pulse_optim.py | 69 +++++++++++++++++++++++------------- src/qutip_qoc/result.py | 63 ++++++++++++++++---------------- 2 files changed, 74 insertions(+), 58 deletions(-) diff --git a/src/qutip_qoc/pulse_optim.py b/src/qutip_qoc/pulse_optim.py index 935bf18..4c53be9 100644 --- a/src/qutip_qoc/pulse_optim.py +++ b/src/qutip_qoc/pulse_optim.py @@ -196,33 +196,52 @@ def optimize_pulses( "gtol": algorithm_kwargs.get("min_grad", 0.0 if alg == "CRAB" else 1e-8), } # Iterate over objectives and convert initial and target states based on the optimization type - for objective in objectives: - H_list = objective.H if isinstance(objective.H, list) else [objective.H] - if any(qt.issuper(H_i) for H_i in H_list): - if isinstance(optimization_type, str) and optimization_type.lower() == "state_transfer": - if qt.isket(objective.initial): - objective.initial = qt.operator_to_vector(qt.ket2dm(objective.initial)) - elif qt.isoper(objective.initial): + H_list = objective.H if isinstance(objective.H, list) else [objective.H] + if any(qt.issuper(H_i) for H_i in H_list): + if isinstance(optimization_type, str) and optimization_type.lower() == "state_transfer": + if qt.isket(objective.initial): + dim = objective.initial.shape[0] + objective.initial = qt.operator_to_vector(qt.ket2dm(objective.initial)) + elif qt.isoper(objective.initial): + dim = objective.initial.shape[0] + objective.initial = qt.operator_to_vector(objective.initial) + + if qt.isket(objective.target): + objective.target = qt.operator_to_vector(qt.ket2dm(objective.target)) + elif qt.isoper(objective.target): + objective.target = qt.operator_to_vector(objective.target) + + algorithm_kwargs.setdefault("fid_params", {}) + algorithm_kwargs["fid_params"].setdefault("scale_factor", 1.0 / dim) + + elif isinstance(optimization_type, str) and optimization_type.lower() == "gate_synthesis": + objective.initial = qt.to_super(objective.initial) + objective.target = qt.to_super(objective.target) + + elif optimization_type is None: + is_state_transfer = False + if qt.isoper(objective.initial) and qt.isoper(objective.target): + if np.isclose(objective.initial.tr(), 1) and np.isclose(objective.target.tr(), 1): + dim = objective.initial.shape[0] objective.initial = qt.operator_to_vector(objective.initial) - if qt.isket(objective.target): - objective.target = qt.operator_to_vector(qt.ket2dm(objective.target)) - elif qt.isoper(objective.target): objective.target = qt.operator_to_vector(objective.target) - elif isinstance(optimization_type, str) and optimization_type.lower() == "gate_synthesis": - objective.initial = qt.to_super(objective.initial) - objective.target = qt.to_super(objective.target) - elif optimization_type is None: - if qt.isoper(objective.initial) and qt.isoper(objective.target): - if np.isclose((objective.initial).tr(), 1) and np.isclose((objective.target).tr(), 1): - objective.initial = qt.operator_to_vector(objective.initial) - objective.target = qt.operator_to_vector(objective.target) - else: - objective.initial = qt.to_super(objective.initial) - objective.target = qt.to_super(objective.target) - if qt.isket(objective.initial): - objective.initial = qt.operator_to_vector(qt.ket2dm(objective.initial)) - if qt.isket(objective.target): - objective.target = qt.operator_to_vector(qt.ket2dm(objective.target)) + is_state_transfer = True + else: + objective.initial = qt.to_super(objective.initial) + objective.target = qt.to_super(objective.target) + + if qt.isket(objective.initial): + dim = objective.initial.shape[0] + objective.initial = qt.operator_to_vector(qt.ket2dm(objective.initial)) + is_state_transfer = True + + if qt.isket(objective.target): + objective.target = qt.operator_to_vector(qt.ket2dm(objective.target)) + is_state_transfer = True + + if is_state_transfer: + algorithm_kwargs.setdefault("fid_params", {}) + algorithm_kwargs["fid_params"].setdefault("scale_factor", 1.0 / dim) # prepare qtrl optimizers qtrl_optimizers = [] diff --git a/src/qutip_qoc/result.py b/src/qutip_qoc/result.py index 7738aa9..a0f2d83 100644 --- a/src/qutip_qoc/result.py +++ b/src/qutip_qoc/result.py @@ -331,42 +331,39 @@ def final_states(self): if self._final_states is None: states = [] - if self.var_time: # last parameter is optimized time - evo_time = self.optimized_params[-1][0] - else: - evo_time = self.time_interval.evo_time - - # choose solver method based on type of control function - # if jax is installed, _jitfun_type is set to - # jaxlib.xla_extension.PjitFunction, otherwise it is None - if _jitfun_type is not None and isinstance( - self.objectives[0].H[1][1], _jitfun_type - ): - method = "diffrax" # for JAX defined contols + if self.qtrl_optimizers: + # Use internal final state from QTRL optimizer + for qtrl_opt in self.qtrl_optimizers: + qtrl_result = qtrl_opt._create_result() + states.append(qtrl_result.evo_full_final) else: - method = "adams" - - for obj, opt_H in zip(self.objectives, self.optimized_H): - if opt_H.issuper: # choose solver - solver = qt.MESolver( - opt_H, - options={ - "normalize_output": False, - "method": method, - }, - ) + if self.var_time: # last parameter is optimized time + evo_time = self.optimized_params[-1][0] else: - solver = qt.SESolver( - opt_H, - options={ - "normalize_output": False, - "method": method, - }, - ) + evo_time = self.time_interval.evo_time - states.append( # compute evolution - solver.run(obj.initial, tlist=[0.0, evo_time]).final_state - ) + if _jitfun_type is not None and isinstance( + self.objectives[0].H[1][1], _jitfun_type + ): + method = "diffrax" + else: + method = "adams" + + for obj, opt_H in zip(self.objectives, self.optimized_H): + if opt_H.issuper: + solver = qt.MESolver( + opt_H, + options={"normalize_output": False, "method": method}, + ) + else: + solver = qt.SESolver( + opt_H, + options={"normalize_output": False, "method": method}, + ) + + states.append( + solver.run(obj.initial, tlist=[0.0, evo_time]).final_state + ) self._final_states = states return self._final_states From 085a9d834a37407097af4bef6cd0cd69afbcb490 Mon Sep 17 00:00:00 2001 From: rochisha0 Date: Wed, 23 Jul 2025 14:31:32 +0900 Subject: [PATCH 2/3] revert result changes --- src/qutip_qoc/result.py | 63 +++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/src/qutip_qoc/result.py b/src/qutip_qoc/result.py index a0f2d83..7738aa9 100644 --- a/src/qutip_qoc/result.py +++ b/src/qutip_qoc/result.py @@ -331,40 +331,43 @@ def final_states(self): if self._final_states is None: states = [] - if self.qtrl_optimizers: - # Use internal final state from QTRL optimizer - for qtrl_opt in self.qtrl_optimizers: - qtrl_result = qtrl_opt._create_result() - states.append(qtrl_result.evo_full_final) + if self.var_time: # last parameter is optimized time + evo_time = self.optimized_params[-1][0] else: - if self.var_time: # last parameter is optimized time - evo_time = self.optimized_params[-1][0] - else: - evo_time = self.time_interval.evo_time - - if _jitfun_type is not None and isinstance( - self.objectives[0].H[1][1], _jitfun_type - ): - method = "diffrax" + evo_time = self.time_interval.evo_time + + # choose solver method based on type of control function + # if jax is installed, _jitfun_type is set to + # jaxlib.xla_extension.PjitFunction, otherwise it is None + if _jitfun_type is not None and isinstance( + self.objectives[0].H[1][1], _jitfun_type + ): + method = "diffrax" # for JAX defined contols + else: + method = "adams" + + for obj, opt_H in zip(self.objectives, self.optimized_H): + if opt_H.issuper: # choose solver + solver = qt.MESolver( + opt_H, + options={ + "normalize_output": False, + "method": method, + }, + ) else: - method = "adams" - - for obj, opt_H in zip(self.objectives, self.optimized_H): - if opt_H.issuper: - solver = qt.MESolver( - opt_H, - options={"normalize_output": False, "method": method}, - ) - else: - solver = qt.SESolver( - opt_H, - options={"normalize_output": False, "method": method}, - ) - - states.append( - solver.run(obj.initial, tlist=[0.0, evo_time]).final_state + solver = qt.SESolver( + opt_H, + options={ + "normalize_output": False, + "method": method, + }, ) + states.append( # compute evolution + solver.run(obj.initial, tlist=[0.0, evo_time]).final_state + ) + self._final_states = states return self._final_states From 311e769b7c426f069f3f38982c4495c4e7580569 Mon Sep 17 00:00:00 2001 From: rochisha0 Date: Thu, 7 Aug 2025 12:03:42 +0530 Subject: [PATCH 3/3] fix objective loop --- src/qutip_qoc/pulse_optim.py | 82 ++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/src/qutip_qoc/pulse_optim.py b/src/qutip_qoc/pulse_optim.py index 4c53be9..fc44231 100644 --- a/src/qutip_qoc/pulse_optim.py +++ b/src/qutip_qoc/pulse_optim.py @@ -195,54 +195,56 @@ def optimize_pulses( "maxiter": algorithm_kwargs.get("max_iter", 1000), "gtol": algorithm_kwargs.get("min_grad", 0.0 if alg == "CRAB" else 1e-8), } + # Iterate over objectives and convert initial and target states based on the optimization type - H_list = objective.H if isinstance(objective.H, list) else [objective.H] - if any(qt.issuper(H_i) for H_i in H_list): - if isinstance(optimization_type, str) and optimization_type.lower() == "state_transfer": - if qt.isket(objective.initial): - dim = objective.initial.shape[0] - objective.initial = qt.operator_to_vector(qt.ket2dm(objective.initial)) - elif qt.isoper(objective.initial): - dim = objective.initial.shape[0] - objective.initial = qt.operator_to_vector(objective.initial) - - if qt.isket(objective.target): - objective.target = qt.operator_to_vector(qt.ket2dm(objective.target)) - elif qt.isoper(objective.target): - objective.target = qt.operator_to_vector(objective.target) - - algorithm_kwargs.setdefault("fid_params", {}) - algorithm_kwargs["fid_params"].setdefault("scale_factor", 1.0 / dim) - - elif isinstance(optimization_type, str) and optimization_type.lower() == "gate_synthesis": - objective.initial = qt.to_super(objective.initial) - objective.target = qt.to_super(objective.target) - - elif optimization_type is None: - is_state_transfer = False - if qt.isoper(objective.initial) and qt.isoper(objective.target): - if np.isclose(objective.initial.tr(), 1) and np.isclose(objective.target.tr(), 1): + for objective in objectives: + H_list = objective.H if isinstance(objective.H, list) else [objective.H] + if any(qt.issuper(H_i) for H_i in H_list): + if isinstance(optimization_type, str) and optimization_type.lower() == "state_transfer": + if qt.isket(objective.initial): + dim = objective.initial.shape[0] + objective.initial = qt.operator_to_vector(qt.ket2dm(objective.initial)) + elif qt.isoper(objective.initial): dim = objective.initial.shape[0] objective.initial = qt.operator_to_vector(objective.initial) - objective.target = qt.operator_to_vector(objective.target) - is_state_transfer = True - else: - objective.initial = qt.to_super(objective.initial) - objective.target = qt.to_super(objective.target) - - if qt.isket(objective.initial): - dim = objective.initial.shape[0] - objective.initial = qt.operator_to_vector(qt.ket2dm(objective.initial)) - is_state_transfer = True - if qt.isket(objective.target): - objective.target = qt.operator_to_vector(qt.ket2dm(objective.target)) - is_state_transfer = True + if qt.isket(objective.target): + objective.target = qt.operator_to_vector(qt.ket2dm(objective.target)) + elif qt.isoper(objective.target): + objective.target = qt.operator_to_vector(objective.target) - if is_state_transfer: algorithm_kwargs.setdefault("fid_params", {}) algorithm_kwargs["fid_params"].setdefault("scale_factor", 1.0 / dim) + elif isinstance(optimization_type, str) and optimization_type.lower() == "gate_synthesis": + objective.initial = qt.to_super(objective.initial) + objective.target = qt.to_super(objective.target) + + elif optimization_type is None: + is_state_transfer = False + if qt.isoper(objective.initial) and qt.isoper(objective.target): + if np.isclose(objective.initial.tr(), 1) and np.isclose(objective.target.tr(), 1): + dim = objective.initial.shape[0] + objective.initial = qt.operator_to_vector(objective.initial) + objective.target = qt.operator_to_vector(objective.target) + is_state_transfer = True + else: + objective.initial = qt.to_super(objective.initial) + objective.target = qt.to_super(objective.target) + + if qt.isket(objective.initial): + dim = objective.initial.shape[0] + objective.initial = qt.operator_to_vector(qt.ket2dm(objective.initial)) + is_state_transfer = True + + if qt.isket(objective.target): + objective.target = qt.operator_to_vector(qt.ket2dm(objective.target)) + is_state_transfer = True + + if is_state_transfer: + algorithm_kwargs.setdefault("fid_params", {}) + algorithm_kwargs["fid_params"].setdefault("scale_factor", 1.0 / dim) + # prepare qtrl optimizers qtrl_optimizers = [] if alg == "CRAB" or alg == "GRAPE":