def update_global_opts(self):
     """checks if bayesian optimisation registration is better than simply taking the previous 
     best transformation found and applying that without any new registration. Updates 
     global optimal to be whichever of current transformation or previous is best
     """
     current_traj_globalT = transform_points(self.global_opt_variables['opt_transform'], self.traj)
     current_traj_globalT_list = current_traj_globalT.tolist()
     current_traj_globalT_matlab = matlab.double(current_traj_globalT_list)
     current_error = self.eng.closestPoint_error(self.aorta, current_traj_globalT_matlab, nargout=1) / self.traj.shape[0]
     #unnormalise previous error to calc new error using best found transformation so far
     updated_global_error = (((self.global_opt_variables['opt_error'] * (len(self.traj_list) - 1) ) + current_error))/ len(self.traj_list)
     if updated_global_error < self.bo_opt_variables['opt_error']:
         print('previous BO better than new BO')
         self.set_global_opt_vars(updated_global_error, 
                                  self.global_opt_variables['opt_center'],
                                  self.global_opt_variables['opt_transform'],
                                  False)
         self.global_opt_variables['opt_from_prev_noReg'] = True
     else:
         print('new BO better than previous')
         self.set_global_opt_vars(self.bo_opt_variables['opt_error'], 
                                  self.bo_opt_variables['opt_center'], 
                                  self.bo_opt_variables['opt_transform'],
                                  self.bo_opt_variables['opt_from_prev_wreg'])
         self.global_opt_variables['opt_from_prev_noReg'] = False
 def get_reg_error(self, center_positions):
     """registers trajectory with center_positions as init location. Contains 
     options to alter how the registration is performed. See class attributes.
     """
     print(self.iteration)
     self.iteration += 1
     num_trajs = len(self.traj_list)
     errors = np.zeros((1,center_positions.shape[0]))
 
     if self.reg_prev_best_transform:
         #saved transformation already moves points to CP but need to recalc CP for new larger trajectory 
         #as CP input is CP for the previous trajectory
         prev_opt_traj = transform_points(self.global_opt_variables['opt_transform'], self.traj)
         trajs_matlab, differences = self.get_traj_matlabarray(center_positions, prev_opt_traj, np.mean(prev_opt_traj, axis=0)) 
     else:
         trajs_matlab, differences = self.get_traj_matlabarray(center_positions, self.traj, self.traj_center) 
         
     diff = np.ones((1,4))
     idx = 0
     for tm in trajs_matlab: 
         errors_added = 0
         registered_points, transformation, reg_error = self.perform_reg(self.aorta, tm, nargout=3)
         errors[0,idx] += reg_error
         errors_added += 1
         transformation = np.array(transformation)
         
         if self.reg_prev_best_transform: 
             transformation = np.dot(transformation, self.global_opt_variables['opt_transform'])                          
         diff[0,:3] = differences[idx]
         translate_t = np.eye(4)
         translate_t[:,3] = diff
         transformation = np.dot(transformation, translate_t)
             
         if self.all_past_checks:
             for traj_idx in range(num_trajs - 1):
                 errors[0, idx] += self.get_past_traj_error(transformation, traj_idx)
                 errors_added += 1
         
         if self.limited_past_checks and num_trajs >= 3:
             if num_trajs % 2 == 0:
                 traj_idx = int(num_trajs / 2)
             else:
                 traj_idx = int((num_trajs + 1) / 2)
             errors[0, idx] += self.get_past_traj_error(transformation, traj_idx)
             errors_added += 1  
         
         errors[0,idx] = errors[0,idx]/ errors_added        
         if errors[0,idx] < self.bo_opt_variables['opt_error']:
             print('NEW OPTIMAL')
             if self.reg_prev_best_transform:
                 self.set_bo_opt_vars(errors[0,idx], center_positions[idx], transformation, True) 
             else:
                 self.set_bo_opt_vars(errors[0,idx], center_positions[idx], transformation, False) 
             if not self.sparse: 
                 self.sparse_error = self.get_sparse_error(transformation, self.traj)
                 
         if self.reg_prev_best_transform: self.reg_prev_best_transform = False #only use previous T once
         idx += 1
     return errors
def get_init_samples(BO_reg, selected_error, traintest_data=None, num_samples=5, GP=None):
    two_samples = False
    if GP is not None:
        print('to implement')
    else:
        if BO_reg.reg_prev_best_transform:
            prev_best = transform_points(BO_reg.global_opt_variables['opt_transform'], BO_reg.traj)
            prev_best_center = np.mean(np.array(prev_best), axis=0)
            y_BO_prev_best = selected_error(prev_best_center.reshape(1,3))
            two_samples = True
        X_BO = traintest_data['y_train'][np.random.choice(traintest_data['y_train'].shape[0], num_samples, replace=False), :]
        y_BO = selected_error(X_BO)
        if two_samples:
            X_BO = np.vstack((prev_best_center, X_BO))
            y_BO = np.concatenate((y_BO_prev_best, y_BO), axis=1)
        
    return X_BO, y_BO.reshape(-1,1)
def bo_optimisation_errors(BO_reg, selected_error_function, traintest_data, 
                           all_trajs,sparse_idxs = None, sparse=False,
                           num_subsections=8, reg_prev_best_transform=False, 
                           plot_trajs=False, max_iter=5, aq_weight=40, 
                            rand_rotation = False, max_rotation=False):
    """Performs bayesian optimisation registration between the aorta and catheter points
    for n = num_subsections subsets of the catheter points to the full trajectory. Returns 
    the results of the registration.
    
    Attributes:
        BO_reg: Instance of the registration class containing the vars needed to perform 
                different versions of the registration
        selected_error_function: The method belonging to BO_reg chosen to perform the registration
        traintest_data: Dictionary containing X_train, X_test, y_train, y_test data
        all_trajs: Dictionary containing traj_indices (list indices in trajs & 
                    GT_trajs where each trajectory subset can be found), 
                    trajs (rotated trajectory and subsets),
                    GT_trajs (ground truth trajectory and subsets)
        sparse: bool showing whether the trajectory is sparse or full
        sparse_idxs: bool array the same length as traj idicating which points are 
                     part of the sparse array
        num_subsections: how many subsets of the trajectory to register and store the results of 
        max_iter: Number of iterations to run the BO for 
        aq_weight: Value to determine how much exploration is done by the BO
        rand_rotation: Bool indicating if trajectory has been randomly rotated 
        max_rotation: Bool indicating if trajectory was rotated by the maximum value (i.e. max of rand_rotation)
        all_past_checks: boolean deciding if error measure is calculated for only 
                         the transformation and current trajectory or all past 
                         trajectories as well
        limited_past_checks: boolean deciding if error measure is for the transformation,
                             current trajectory and one previous trajectory
        reg_prev_best_transform: boolean deciding if when initialising the Bayesian
                                 optimisation the previous best transformation is 
                                 used as one if the initialisation points
        bo_opt_variables: dictionary storing the variables for the most recent Bayesian
                          optimisation round. 
                          opt_from_prev_wreg describes if the best found
                          came from the previous registration or a new one. 
                          opt_from_prev_noReg describes if best found came from 
                          the previous registration but without any registration applied
        global_opt_variables: same as above but for the entire BO registration process
                              not just the most recent
        
        Output:
            bo_stats: Dictionary containing keys of the subset index 0-num_subsections and the registration 
                      results for that subset and a key of creation_params detailing the settings of the registration 
                      and the nature of the data used
    """
    num_trajs = int(all_trajs['trajs'].shape[1] / 3)
    steps = ceil(num_trajs/num_subsections)
    BO_reg.sparse = sparse
    bo_stats = {}
    traj_idx = -1
    for test_value in range(0, num_trajs, steps):
        traj_idx += 1
        traj, GT_traj = get_test_trajs(test_value, all_trajs)
        BO_reg.add_traj(traj)
        BO_reg.set_bo_opt_vars(inf, np.zeros((1,3)), np.eye(4), False)
        if reg_prev_best_transform: BO_reg.reg_prev_best_transform = True
        if not sparse:
            BO_reg.sparse_idxs = sparse_idxs[:traj.shape[0]]
        X_BO, y_BO = get_init_samples(BO_reg, selected_error_function, traintest_data)
        t1 = time()
        bounds = [{'name':'cathReg', 'type':'bandit', 'domain':traintest_data['y_train']}]
        Bopt = GPyOpt.methods.BayesianOptimization(f=selected_error_function,
                                                  domain=bounds,
                                                  X=X_BO,
                                                  Y=y_BO,
                                                  acquisition_type='LCB',
                                                  acquisition_weight=aq_weight)
        Bopt.run_optimization(max_iter)
        t2 = time()   
        if sparse:
            bo_opt_error = GPyOpt.util.general.best_value(Bopt.Y)[-1]
            bo_opt_full_error = 0
        else:
            bo_opt_error = BO_reg.sparse_error
            bo_opt_full_error = GPyOpt.util.general.best_value(Bopt.Y)[-1]
        print('Optimal X:' + str(Bopt.x_opt))
        BO_trans = transform_points(BO_reg.bo_opt_variables['opt_transform'], traj)
        diff_to_GT = register_pointclouds(GT_traj, BO_trans, BO_reg.eng, noreg_error=True) / BO_trans.shape[0]
        GT_error = register_pointclouds(BO_reg.aorta, GT_traj, BO_reg.eng, noreg_error=True) / GT_traj.shape[0]
        
        if plot_trajs:
            reg_error, BO_registered = BO_reg.get_simple_reg_error_and_points(np.array([Bopt.x_opt]))
            BO_registered = np.array(BO_registered)
            global_traj = transform_points(BO_reg.global_opt_variables['opt_transform'], traj)
            plot_registration(np.array(BO_reg.aorta), GT_traj, BO_registered, 
                              BO_trans, global_traj, point=Bopt.x_opt)
        
        BO_reg.update_global_opts()
        bo_stats[str(traj_idx)] = {'global_opt_error':BO_reg.global_opt_variables['opt_error'], 
                                    'bo_opt_error':bo_opt_error,
                                    'bo_opt_full_error': bo_opt_full_error,
                                    'diff_to_GT_error':diff_to_GT, 'GT_error':GT_error, 
                                    'comp_time':t2-t1, 'opt_from_prev_wreg':BO_reg.global_opt_variables['opt_from_prev_wreg'],
                                    'opt_from_prev_noReg':BO_reg.global_opt_variables['opt_from_prev_noReg'], 
                                    'opt_CP':np.ndarray.tolist(Bopt.x_opt)}

    bo_stats['creation_params'] = {'max_iters':max_iter,
                                   'reg_prev_best_transform':reg_prev_best_transform,
                                   'all_past_checks':BO_reg.all_past_checks,
                                   'limited_past_checks':BO_reg.limited_past_checks,
                                   'aquisition_weight':aq_weight,
                                   'sparse':sparse,
                                   'max_rotation':max_rotation,
                                   'rand_rotation':rand_rotation,
                                   'num_subsections':num_subsections}
    return bo_stats
 def get_sparse_error(self, transformation, full_traj):
     sparse_traj = [points for points,select in zip(full_traj, self.sparse_idxs) if select]
     transformed_traj = transform_points(transformation, np.array(sparse_traj))
     transformed_traj_matlab = matlab.double(transformed_traj.tolist())
     return self.eng.closestPoint_error(self.aorta, transformed_traj_matlab, nargout=1) / transformed_traj.shape[0] 
 def get_past_traj_error(self, transformation, traj_idx):
     transformed_traj = transform_points(transformation, self.traj_list[traj_idx])
     transformed_traj_matlab = matlab.double(transformed_traj.tolist())
     return self.eng.closestPoint_error(self.aorta, transformed_traj_matlab, nargout=1) / transformed_traj.shape[0]