From b6957cb5bdae0f3d1eb6d9af1b974749127b9bfb Mon Sep 17 00:00:00 2001
From: Yizhou Cai <yizhou.cai@cern.ch>
Date: Thu, 17 Apr 2025 21:44:14 +0800
Subject: [PATCH 1/5] optimize retry

---
 quickstats/components/extended_minimizer.py | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/quickstats/components/extended_minimizer.py b/quickstats/components/extended_minimizer.py
index 357ed050..237cfd61 100644
--- a/quickstats/components/extended_minimizer.py
+++ b/quickstats/components/extended_minimizer.py
@@ -681,12 +681,15 @@ class ExtendedMinimizer(AbstractObject):
         self.status = status
         return status
 
-    def robust_minimize(self, cascade:bool=True):
+    def robust_minimize(self, cascade:bool=True, fit_from_initial:bool=True):
         self.stdout.debug('Begin robust minimization.')
         strategy = self.config['strategy']
         retry    = self.config['retry']
         minimizer_type = self.config['minimizer_type']
         minimizer_algo = self.config['minimizer_algo']
+        if fit_from_initial:
+            variables = self.pdf.getVariables()
+            snapshot = variables.snapshot()
 
         status = self.single_minimize(minimizer_type, minimizer_algo)
         # repeat if fit failed or poi(s) at boundary
@@ -700,6 +703,8 @@ class ExtendedMinimizer(AbstractObject):
             self.stdout.error(f'ExtendedMinimizer::robust_minimize("{self.name}") fit failed with status {status}. '
                               f'Retrying with strategy {strategy}')
             self.minimizer.setStrategy(strategy)
+            if fit_from_initial:
+                variables.__assign__(snapshot)
             status = self.single_minimize(minimizer_type, minimizer_algo)
             expanded_pois = self.expand_poi_bounds()
         
-- 
GitLab


From 67b0fe8cfb0b1b1c276b5b9a5c16a72238a455e1 Mon Sep 17 00:00:00 2001
From: Yizhou Cai <yizhou.cai@cern.ch>
Date: Thu, 17 Apr 2025 21:51:33 +0800
Subject: [PATCH 2/5] robust the prefit

---
 quickstats/components/extended_minimizer.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/quickstats/components/extended_minimizer.py b/quickstats/components/extended_minimizer.py
index 237cfd61..3d0dc836 100644
--- a/quickstats/components/extended_minimizer.py
+++ b/quickstats/components/extended_minimizer.py
@@ -625,7 +625,7 @@ class ExtendedMinimizer(AbstractObject):
                 # prefit minimization
                 self.minimizer.setStrategy(0)
                 self.minimizer.setEps(self.config['eps']*10)
-                status = self.single_minimize(self.config['minimizer_type'], self.config['minimizer_algo'])
+                self.robust_minimize(cascade=cascade)
                 self.minimizer.setStrategy(self.config['strategy'])
                 self.minimizer.setEps(self.config['eps'])
 
-- 
GitLab


From 9fce1d4fe918ed9377b99b0be0e98df93e51c268 Mon Sep 17 00:00:00 2001
From: Yizhou Cai <yizhou.cai@cern.ch>
Date: Thu, 24 Apr 2025 22:07:16 +0800
Subject: [PATCH 3/5] new retry

---
 quickstats/components/extended_minimizer.py | 70 +++++++++++++--------
 1 file changed, 44 insertions(+), 26 deletions(-)

diff --git a/quickstats/components/extended_minimizer.py b/quickstats/components/extended_minimizer.py
index 3d0dc836..fabbc364 100644
--- a/quickstats/components/extended_minimizer.py
+++ b/quickstats/components/extended_minimizer.py
@@ -55,6 +55,7 @@ class ExtendedMinimizer(AbstractObject):
         'postfit_hesse': 0,
         'minuit2_storage_level': 0,
         'do_prefit': 0,
+        'retry_diff_eps': 0,
         # cms dedicated configs
         'set_zero_point': 1, # change the reference point of the NLL to be zero during minimization
         # discrete nuisance configs
@@ -624,8 +625,8 @@ class ExtendedMinimizer(AbstractObject):
                 self.stdout.info('ExtendedMinimizer::minimize("{}") prefit minimization'.format(self.name))
                 # prefit minimization
                 self.minimizer.setStrategy(0)
-                self.minimizer.setEps(self.config['eps']*10)
-                self.robust_minimize(cascade=cascade)
+                self.minimizer.setEps(self.config['eps']*100)
+                self.robust_minimize(cascade=cascade, is_prefit=True)
                 self.minimizer.setStrategy(self.config['strategy'])
                 self.minimizer.setEps(self.config['eps'])
 
@@ -681,37 +682,54 @@ class ExtendedMinimizer(AbstractObject):
         self.status = status
         return status
 
-    def robust_minimize(self, cascade:bool=True, fit_from_initial:bool=True):
+    def robust_minimize(self, cascade:bool=True, is_prefit:bool=False):
         self.stdout.debug('Begin robust minimization.')
-        strategy = self.config['strategy']
         retry    = self.config['retry']
         minimizer_type = self.config['minimizer_type']
         minimizer_algo = self.config['minimizer_algo']
-        if fit_from_initial:
-            variables = self.pdf.getVariables()
-            snapshot = variables.snapshot()
-
+        
+        def require_cascade(fit_status:int):
+            return cascade and (fit_status not in [0, 1])
         status = self.single_minimize(minimizer_type, minimizer_algo)
         # repeat if fit failed or poi(s) at boundary
         expanded_pois = self.expand_poi_bounds()
-        def require_cascade(fit_status:int):
-            return cascade and (fit_status not in [0, 1])
-        while ((require_cascade(status) or expanded_pois) and (retry > 0)):
-            if (not expanded_pois) and (strategy < 2):
-                strategy += 1
-            retry -= 1
-            self.stdout.error(f'ExtendedMinimizer::robust_minimize("{self.name}") fit failed with status {status}. '
-                              f'Retrying with strategy {strategy}')
-            self.minimizer.setStrategy(strategy)
-            if fit_from_initial:
-                variables.__assign__(snapshot)
-            status = self.single_minimize(minimizer_type, minimizer_algo)
-            expanded_pois = self.expand_poi_bounds()
-        
-        if status not in [0, 1]:
-            self.stdout.error(f'ExtendedMinimizer::robust_minimize("{self.name}") fit failed with status {status}')
-        
-        self.minimizer.setStrategy(self.config['strategy'])
+
+        if self.config['retry_diff_eps']:
+            eps_init = self.config['eps'] * 100 if is_prefit else self.config['eps']
+            eps = eps_init
+
+            while ((require_cascade(status) or expanded_pois) and (retry > 0)):
+                if (not expanded_pois):
+                    eps *= 10
+                retry -= 1
+                self.stdout.error(f'ExtendedMinimizer::robust_minimize("{self.name}") fit failed with status {status}. '
+                                f'Retrying with eps {eps}')
+                self.minimizer.setEps(eps)
+                status = self.single_minimize(minimizer_type, minimizer_algo)
+                expanded_pois = self.expand_poi_bounds()
+            
+            if status not in [0, 1]:
+                self.stdout.error(f'ExtendedMinimizer::robust_minimize("{self.name}") fit failed with status {status}')
+            
+            self.minimizer.setEps(eps_init)
+        
+        else:
+            strategy = self.config['strategy']
+
+            while ((require_cascade(status) or expanded_pois) and (retry > 0)):
+                if (not expanded_pois) and (strategy < 2):
+                    strategy += 1
+                retry -= 1
+                self.stdout.error(f'ExtendedMinimizer::robust_minimize("{self.name}") fit failed with status {status}. '
+                                f'Retrying with strategy {strategy}')
+                self.minimizer.setStrategy(strategy)
+                status = self.single_minimize(minimizer_type, minimizer_algo)
+                expanded_pois = self.expand_poi_bounds()
+            
+            if status not in [0, 1]:
+                self.stdout.error(f'ExtendedMinimizer::robust_minimize("{self.name}") fit failed with status {status}')
+            
+            self.minimizer.setStrategy(self.config['strategy'])
         
         return status
 
-- 
GitLab


From b9d141aaa698f1ff8c20197fcfafa03fb6ad46ae Mon Sep 17 00:00:00 2001
From: Yizhou Cai <yizhou.cai@cern.ch>
Date: Sat, 26 Apr 2025 23:12:50 +0800
Subject: [PATCH 4/5] option of prefit_eps

---
 quickstats/components/extended_minimizer.py | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/quickstats/components/extended_minimizer.py b/quickstats/components/extended_minimizer.py
index fabbc364..7588ec61 100644
--- a/quickstats/components/extended_minimizer.py
+++ b/quickstats/components/extended_minimizer.py
@@ -55,6 +55,7 @@ class ExtendedMinimizer(AbstractObject):
         'postfit_hesse': 0,
         'minuit2_storage_level': 0,
         'do_prefit': 0,
+        'prefit_eps': 1.0,
         'retry_diff_eps': 0,
         # cms dedicated configs
         'set_zero_point': 1, # change the reference point of the NLL to be zero during minimization
@@ -625,7 +626,7 @@ class ExtendedMinimizer(AbstractObject):
                 self.stdout.info('ExtendedMinimizer::minimize("{}") prefit minimization'.format(self.name))
                 # prefit minimization
                 self.minimizer.setStrategy(0)
-                self.minimizer.setEps(self.config['eps']*100)
+                self.minimizer.setEps(self.config['prefit_eps'])
                 self.robust_minimize(cascade=cascade, is_prefit=True)
                 self.minimizer.setStrategy(self.config['strategy'])
                 self.minimizer.setEps(self.config['eps'])
@@ -695,7 +696,7 @@ class ExtendedMinimizer(AbstractObject):
         expanded_pois = self.expand_poi_bounds()
 
         if self.config['retry_diff_eps']:
-            eps_init = self.config['eps'] * 100 if is_prefit else self.config['eps']
+            eps_init = self.config['prefit_eps'] if is_prefit else self.config['eps']
             eps = eps_init
 
             while ((require_cascade(status) or expanded_pois) and (retry > 0)):
-- 
GitLab


From bff396d63be6d2c9830f42fa55c2e9202d1e1b1a Mon Sep 17 00:00:00 2001
From: Yizhou Cai <yizhou.cai@cern.ch>
Date: Sat, 26 Apr 2025 23:19:51 +0800
Subject: [PATCH 5/5] replace do_prefit option by prefit_eps

---
 quickstats/components/extended_minimizer.py | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/quickstats/components/extended_minimizer.py b/quickstats/components/extended_minimizer.py
index 7588ec61..6c0b6d47 100644
--- a/quickstats/components/extended_minimizer.py
+++ b/quickstats/components/extended_minimizer.py
@@ -54,8 +54,7 @@ class ExtendedMinimizer(AbstractObject):
         'prefit_hesse': 0,
         'postfit_hesse': 0,
         'minuit2_storage_level': 0,
-        'do_prefit': 0,
-        'prefit_eps': 1.0,
+        'prefit_eps': 0,
         'retry_diff_eps': 0,
         # cms dedicated configs
         'set_zero_point': 1, # change the reference point of the NLL to be zero during minimization
@@ -622,7 +621,7 @@ class ExtendedMinimizer(AbstractObject):
         else:
             self.discrete_nuisance.freeze_discrete_params(True)
 
-            if self.config['do_prefit']:
+            if self.config['prefit_eps'] > 0:
                 self.stdout.info('ExtendedMinimizer::minimize("{}") prefit minimization'.format(self.name))
                 # prefit minimization
                 self.minimizer.setStrategy(0)
-- 
GitLab