class_docstr: Holds information about a molecules.
  
  Resorts order of atoms internally to be in order of increasing degree. Note
  that only heavy atoms (hydrogens excluded) are considered here.
class_docstr_tok: ["Holds","information","about","a","molecules",".","Resorts","order","of","atoms","internally","to","be","in","order","of","increasing","degree",".","Note","that","only","heavy","atoms","(","hydrogens","excluded",")","are","considered","here","."]
docstr: Concatenates list of ConvMol's into one mol object that can be used to feed
      into tensorflow placeholders. The indexing of the molecules are preseved during the
      combination, but the indexing of the atoms are greatly changed.
  
  Parameters
  ----------
  mols: list
      ConvMol objects to be combined into one molecule.
docstr_tok: ["Concatenates","list","of","ConvMol","'s","into","one","mol","object","that","can","be","used","to","feed","into","tensorflow","placeholders",".","The","indexing","of","the","molecules","are","preseved","during","the","combination",",","but","the","indexing","of","the","atoms","are","greatly","changed",".","Parameters","--","--","--","--","--","mols",":","list","ConvMol","objects","to","be","combined","into","one","molecule","."]
code: def agglomerate_mols(mols, max_deg=10, min_deg=0):
      """Concatenates list of ConvMol's into one mol object that can be used to feed
          into tensorflow placeholders. The indexing of the molecules are preseved during the
          combination, but the indexing of the atoms are greatly changed.
  
      Parameters
      ----------
      mols: list
          ConvMol objects to be combined into one molecule.
      """
  
      num_mols = len(mols)
  
      # Combine the features, then sort them by (atom_degree, mol_index)
      atoms_by_deg = np.concatenate([x.atom_features for x in mols])
      degree_vector = np.concatenate(
          [x.degree_list for x in mols], axis=0
      )
      # Mergesort is a "stable" sort, so the array maintains it's secondary sort of mol_index
      order = degree_vector.argsort(kind="mergesort")
      ordered = np.empty(order.shape, np.int32)
      ordered[order] = np.arange(order.shape[0], dtype=np.int32)
      all_atoms = atoms_by_deg[order]
  
      # Create a map from the original atom indices within each molecule to the
      # indices in the combined object.
      mol_atom_map = []
      index_start = 0
      for mol in mols:
          mol_atom_map.append(
              ordered[index_start : index_start + mol.get_num_atoms()]
          )
          index_start += mol.get_num_atoms()
  
      # Sort all atoms by degree.
      # Get the size of each atom list separated by molecule id, then by degree
      mol_deg_sz = np.zeros(
          [max_deg - min_deg + 1, num_mols], dtype=np.int32
      )
      for i, mol in enumerate(mols):
          mol_deg_sz[:, i] += mol.deg_slice[:, 1]
  
      # Get the final size of each degree block
      deg_sizes = np.sum(mol_deg_sz, axis=1)
  
      # Get the index at which each degree starts, not resetting after each degree
      # And not stopping at any specific molecule
  
      deg_start = cumulative_sum_minus_last(deg_sizes)
  
      # Get the tensorflow object required for slicing (deg x 2) matrix, with the
      # first column telling the start indices of each degree block and the
      # second colum telling the size of each degree block
      deg_slice = np.array(list(zip(deg_start, deg_sizes)))
  
      # Determine the membership (atom i belongs to molecule membership[i])
      membership = np.empty(all_atoms.shape[0], np.int32)
      for i in range(num_mols):
          membership[mol_atom_map[i]] = i
  
      # Initialize the new degree separated adjacency lists
      deg_adj_lists = [
          np.empty([deg_sizes[deg], deg], dtype=np.int32)
          for deg in range(min_deg, max_deg + 1)
      ]
  
      # Update the old adjacency lists with the new atom indices and then combine
      # all together
      for deg in range(min_deg, max_deg + 1):
          row = 0  # Initialize counter
          deg_id = deg - min_deg  # Get corresponding degree id
  
          # Iterate through all the molecules
          for mol_id in range(num_mols):
              # Get the adjacency lists for this molecule and current degree id
              nbr_list = mols[mol_id].deg_adj_lists[deg_id]
  
              # Correct all atom indices to the final indices, and then save the
              # results into the new adjacency lists
              if nbr_list.shape[0] > 0:
                  if nbr_list.dtype == np.int32:
                      final_id = mol_atom_map[mol_id][nbr_list]
                      deg_adj_lists[deg_id][
                          row : (row + nbr_list.shape[0])
                      ] = final_id
                      row += nbr_list.shape[0]
                  else:
                      for i in range(nbr_list.shape[0]):
                          for j in range(nbr_list.shape[1]):
                              deg_adj_lists[deg_id][
                                  row, j
                              ] = mol_atom_map[mol_id][nbr_list[i, j]]
                          # Increment once row is done
                          row += 1
  
      # Get the final aggregated molecule
      concat_mol = MultiConvMol(
          all_atoms, deg_adj_lists, deg_slice, membership, num_mols
      )
      return concat_mol
  
imports: import csv
  import random
  import numpy
label_desc: Use image node_id 11 for calling the ConvMol obj's underlying member method code with example usage: obj.agglomerate_mols(mols, max_deg, min_deg) and returns: concat_mol