nodes: 0, module; 1, function_definition; 2, function_name:merge_units; 3, parameters; 4, block; 5, identifier:self; 6, identifier:unit_ids; 7, expression_statement; 8, expression_statement; 9, for_statement; 10, expression_statement; 11, if_statement; 12, string; 13, assignment; 14, identifier:i; 15, call; 16, block; 17, assignment; 18, parenthesized_expression; 19, comment:#Find all unique feature names and create all feature lists; 20, block; 21, else_clause; 22, string_content:This function merges two roots from the curation tree according to the given unit_ids. It creates a new unit_id and root
          that has the merged roots as children.
  
          Parameters
          ----------
          unit_ids: list
              The unit ids to be merged; 23, identifier:root_ids; 24, list; 25, identifier:range; 26, argument_list; 27, expression_statement; 28, expression_statement; 29, identifier:indices_to_be_deleted; 30, list; 31, boolean_operator; 32, expression_statement; 33, for_statement; 34, expression_statement; 35, for_statement; 36, expression_statement; 37, expression_statement; 38, for_statement; 39, expression_statement; 40, expression_statement; 41, expression_statement; 42, expression_statement; 43, for_statement; 44, expression_statement; 45, expression_statement; 46, expression_statement; 47, delete_statement; 48, expression_statement; 49, expression_statement; 50, for_statement; 51, block; 52, call; 53, assignment; 54, call; 55, call; 56, comparison_operator:len(unit_ids) > 1; 57, assignment; 58, identifier:unit_id; 59, identifier:unit_ids; 60, block; 61, assignment; 62, identifier:feature_names; 63, subscript; 64, block; 65, assignment; 66, assignment; 67, identifier:i; 68, call; 69, block; 70, assignment; 71, call; 72, assignment; 73, assignment; 74, identifier:unit_id; 75, identifier:unit_ids; 76, block; 77, assignment; 78, assignment; 79, call; 80, identifier:all_spike_trains; 81, assignment; 82, call; 83, pattern_list; 84, call; 85, block; 86, raise_statement; 87, identifier:len; 88, argument_list; 89, identifier:root_id; 90, attribute; 91, attribute; 92, argument_list; 93, attribute; 94, argument_list; 95, call; 96, integer:1; 97, identifier:all_feature_names; 98, list; 99, expression_statement; 100, expression_statement; 101, identifier:shared_feature_names; 102, call; 103, identifier:all_feature_names; 104, slice; 105, expression_statement; 106, identifier:shared_feature_names; 107, call; 108, identifier:shared_features; 109, list; 110, identifier:range; 111, argument_list; 112, expression_statement; 113, identifier:new_root_id; 114, binary_operator:max(self._all_ids)+1; 115, attribute; 116, argument_list; 117, identifier:new_root; 118, call; 119, identifier:all_spike_trains; 120, list; 121, expression_statement; 122, expression_statement; 123, expression_statement; 124, for_statement; 125, delete_statement; 126, expression_statement; 127, comment:#clear spiketrain; 128, expression_statement; 129, identifier:all_spike_trains; 130, call; 131, identifier:sort_indices; 132, call; 133, attribute; 134, argument_list; 135, attribute; 136, list_comprehension; 137, attribute; 138, argument_list; 139, identifier:i; 140, identifier:feature_name; 141, identifier:enumerate; 142, argument_list; 143, expression_statement; 144, call; 145, attribute; 146, subscript; 147, identifier:unit_id; 148, identifier:root_ids; 149, identifier:append; 150, identifier:root_id; 151, call; 152, identifier:issubset; 153, call; 154, identifier:len; 155, argument_list; 156, assignment; 157, call; 158, identifier:set; 159, argument_list; 160, integer:1; 161, call; 162, identifier:list; 163, argument_list; 164, call; 165, call; 166, call; 167, integer:1; 168, attribute; 169, identifier:append; 170, identifier:new_root_id; 171, identifier:Unit; 172, argument_list; 173, assignment; 174, call; 175, call; 176, pattern_list; 177, call; 178, block; 179, subscript; 180, call; 181, call; 182, attribute; 183, argument_list; 184, attribute; 185, argument_list; 186, identifier:new_root; 187, identifier:set_spike_train; 188, subscript; 189, identifier:self; 190, identifier:_roots; 191, subscript; 192, for_in_clause; 193, if_clause; 194, attribute; 195, identifier:append; 196, identifier:new_root; 197, identifier:shared_feature_names; 198, call; 199, identifier:ValueError; 200, argument_list; 201, identifier:self; 202, identifier:_roots; 203, attribute; 204, identifier:i; 205, identifier:set; 206, argument_list; 207, identifier:set; 208, argument_list; 209, identifier:unit_ids; 210, identifier:feature_names; 211, call; 212, attribute; 213, argument_list; 214, subscript; 215, attribute; 216, argument_list; 217, identifier:shared_feature_names; 218, identifier:len; 219, argument_list; 220, attribute; 221, argument_list; 222, identifier:max; 223, argument_list; 224, identifier:self; 225, identifier:_all_ids; 226, identifier:new_root_id; 227, identifier:root_index; 228, call; 229, attribute; 230, argument_list; 231, attribute; 232, argument_list; 233, identifier:i; 234, identifier:feature_name; 235, identifier:enumerate; 236, argument_list; 237, expression_statement; 238, expression_statement; 239, attribute; 240, identifier:unit_id; 241, attribute; 242, argument_list; 243, attribute; 244, argument_list; 245, identifier:np; 246, identifier:concatenate; 247, identifier:all_spike_trains; 248, identifier:np; 249, identifier:argsort; 250, identifier:all_spike_trains; 251, call; 252, identifier:sort_indices; 253, attribute; 254, identifier:i; 255, pattern_list; 256, call; 257, comparison_operator:i not in indices_to_be_deleted; 258, identifier:self; 259, identifier:_roots; 260, attribute; 261, argument_list; 262, binary_operator:str(unit_ids) + " has one or more invalid unit ids"; 263, identifier:self; 264, identifier:_roots; 265, identifier:unit_ids; 266, identifier:root_ids; 267, attribute; 268, argument_list; 269, identifier:all_feature_names; 270, identifier:append; 271, identifier:feature_names; 272, identifier:all_feature_names; 273, integer:0; 274, identifier:shared_feature_names; 275, identifier:intersection_update; 276, identifier:feature_names; 277, identifier:shared_feature_names; 278, identifier:shared_features; 279, identifier:append; 280, list; 281, attribute; 282, attribute; 283, argument_list; 284, identifier:new_root; 285, identifier:add_child; 286, subscript; 287, identifier:all_spike_trains; 288, identifier:append; 289, call; 290, identifier:shared_feature_names; 291, assignment; 292, call; 293, identifier:self; 294, identifier:_unit_features; 295, subscript; 296, identifier:set_spike_train; 297, call; 298, identifier:indices_to_be_deleted; 299, identifier:append; 300, identifier:root_index; 301, attribute; 302, argument_list; 303, identifier:self; 304, identifier:_roots; 305, identifier:i; 306, identifier:_; 307, identifier:enumerate; 308, argument_list; 309, identifier:i; 310, identifier:indices_to_be_deleted; 311, identifier:self; 312, identifier:set_unit_spike_features; 313, identifier:new_root_id; 314, identifier:feature_name; 315, subscript; 316, call; 317, string:" has one or more invalid unit ids"; 318, identifier:self; 319, identifier:get_unit_spike_feature_names; 320, identifier:unit_id; 321, identifier:self; 322, identifier:_all_ids; 323, identifier:root_ids; 324, identifier:index; 325, identifier:unit_id; 326, attribute; 327, identifier:root_index; 328, attribute; 329, argument_list; 330, identifier:features; 331, call; 332, attribute; 333, argument_list; 334, attribute; 335, identifier:root_index; 336, attribute; 337, argument_list; 338, identifier:np; 339, identifier:asarray; 340, identifier:all_spike_trains; 341, identifier:root_ids; 342, call; 343, identifier:sort_indices; 344, identifier:str; 345, argument_list; 346, identifier:self; 347, identifier:_roots; 348, subscript; 349, identifier:get_spike_train; 350, attribute; 351, argument_list; 352, subscript; 353, identifier:append; 354, identifier:features; 355, identifier:self; 356, identifier:_roots; 357, identifier:np; 358, identifier:asarray; 359, list; 360, attribute; 361, argument_list; 362, identifier:unit_ids; 363, attribute; 364, identifier:root_index; 365, identifier:self; 366, identifier:get_unit_spike_features; 367, identifier:unit_id; 368, identifier:feature_name; 369, identifier:shared_features; 370, identifier:i; 371, identifier:np; 372, identifier:concatenate; 373, subscript; 374, identifier:self; 375, identifier:_roots; 376, identifier:shared_features; 377, identifier:i
code: def merge_units(self, unit_ids):
          '''This function merges two roots from the curation tree according to the given unit_ids. It creates a new unit_id and root
          that has the merged roots as children.
  
          Parameters
          ----------
          unit_ids: list
              The unit ids to be merged
          '''
          root_ids = []
          for i in range(len(self._roots)):
              root_id = self._roots[i].unit_id
              root_ids.append(root_id)
  
          indices_to_be_deleted = []
          if(set(unit_ids).issubset(set(root_ids)) and len(unit_ids) > 1):
              #Find all unique feature names and create all feature lists
              all_feature_names = []
              for unit_id in unit_ids:
                  feature_names = self.get_unit_spike_feature_names(unit_id)
                  all_feature_names.append(feature_names)
  
              shared_feature_names = set(all_feature_names[0])
              for feature_names in all_feature_names[1:]:
                  shared_feature_names.intersection_update(feature_names)
              shared_feature_names = list(shared_feature_names)
              shared_features = []
              for i in range(len(shared_feature_names)):
                  shared_features.append([])
  
              new_root_id = max(self._all_ids)+1
              self._all_ids.append(new_root_id)
              new_root = Unit(new_root_id)
              all_spike_trains = []
              for unit_id in unit_ids:
                  root_index = root_ids.index(unit_id)
                  new_root.add_child(self._roots[root_index])
                  all_spike_trains.append(self._roots[root_index].get_spike_train())
                  for i, feature_name in enumerate(shared_feature_names):
                      features = self.get_unit_spike_features(unit_id, feature_name)
                      shared_features[i].append(features)
                  del self._unit_features[unit_id]
                  self._roots[root_index].set_spike_train(np.asarray([])) #clear spiketrain
                  indices_to_be_deleted.append(root_index)
  
              all_spike_trains = np.concatenate(all_spike_trains)
              sort_indices = np.argsort(all_spike_trains)
              new_root.set_spike_train(np.asarray(all_spike_trains)[sort_indices])
              del all_spike_trains
              self._roots = [self._roots[i] for i,_ in enumerate(root_ids) if i not in indices_to_be_deleted]
              self._roots.append(new_root)
              for i, feature_name in enumerate(shared_feature_names):
                  self.set_unit_spike_features(new_root_id, feature_name, np.concatenate(shared_features[i])[sort_indices])
          else:
              raise ValueError(str(unit_ids) + " has one or more invalid unit ids")