docs: def lexicase(self,F, num_selections=None, survival = False):
          """conducts lexicase selection for de-aggregated fitness vectors"""
          if num_selections is None:
              num_selections = F.shape[0]
          winners = []
          locs = []
  
          individual_locs = np.arange(F.shape[0])
                  
          for i in np.arange(num_selections):
              can_locs = individual_locs
              cases = list(np.arange(F.shape[1]))
              self.random_state.shuffle(cases)
              # pdb.set_trace()
              while len(cases) > 0 and len(can_locs) > 1:
                  # get best fitness for case among candidates
                  best_val_for_case = np.min(F[can_locs,cases[0]])
                  # filter individuals without an elite fitness on this case
                  can_locs = [l for l in can_locs if F[l,cases[0]] <= best_val_for_case ]
                  cases.pop(0)
  
              choice = self.random_state.randint(len(can_locs))
              locs.append(can_locs[choice])
              if survival: # filter out winners from remaining selection pool
                  individual_locs = [i for i in individual_locs if i != can_locs[choice]]
  
          while len(locs) < num_selections:
              locs.append(individual_locs[0])
  
          return locs