code: def crossover(self, donor, random_state):
          
          # Get a subtree to replace
          start, end = self.get_subtree(random_state)
          removed = range(start, end)
          # Get a subtree to donate
          donor_start, donor_end = self.get_subtree(random_state, donor)
          donor_removed = list(set(range(len(donor))) -
                               set(range(donor_start, donor_end)))
          # Insert genetic material from donor
          return (self.program[:start] +
                  donor[donor_start:donor_end] +
                  self.program[end:]), removed, donor_removed
docs: Perform the crossover genetic operation on the program.
  
          Crossover selects a random subtree from the embedded program to be
          replaced. A donor also has a subtree selected at random and this is
          inserted into the original parent to form an offspring.
  
          Parameters
          ----------
          donor : list
              The flattened tree representation of the donor program.
  
          random_state : RandomState instance
              The random number generator.
  
          Returns
          -------
          program : list
              The flattened tree representation of the program.