docs: def _process_counter_example(self, mma, w_string):
          """"
          Process a counterexample in the Rivest-Schapire way.
          Args:
              mma (DFA): The hypothesis automaton
              w_string (str): The examined string to be consumed
          Return:
              None
          """
          if len(w_string) == 1:
              self.observation_table.smi_vector.append(w_string)
              for exp in self.observation_table.em_vector:
                  self._fill_table_entry(w_string, exp)
  
          diff = len(w_string)
          same = 0
          membership_answer = self._membership_query(w_string)
          while True:
              i = (same + diff) / 2
              access_string = self._run_in_hypothesis(mma, w_string, i)
              if membership_answer != self._membership_query(access_string + w_string[i:]):
                  diff = i
              else:
                  same = i
              if diff - same == 1:
                  break
  
          # First check if the transition is part of our training data.
          access_string = self._run_in_hypothesis(mma, w_string, diff - 1)
          wrong_transition = access_string + w_string[diff - 1]
          if wrong_transition not in self.observation_table.smi_vector:
              # If transition is not part of our training data add s_ib to Smi and
              # return to checking table closedness.
              self.observation_table.smi_vector.append(wrong_transition)
              for exp in self.observation_table.em_vector:
                  self._fill_table_entry(wrong_transition, exp)
              return
  
          # This point presents a tradeoff between equivalence and membership
          # queries. If the transition in the counterexample'input_string breakpoint is not
          # part of our current training data (i.e. s_ib is not part of our Smi
          # set), then we assume a wrong transition and return to checking table
          # closure by adding s_ib to our training data. This saves a number of
          # membership queries since we don't add a row in our table unless
          # absolutely necessary. Notice that even if Equivalence queries are
          # expensive in general caching the result will be able to discover that
          # this iteration required a new state in the next equivalence query.
  
          exp = w_string[diff:]
          self.observation_table.em_vector.append(exp)
          for row in self.observation_table.sm_vector + self.observation_table.smi_vector:
              self._fill_table_entry(row, exp)