docs: def mappingBasedGrouping(protToPeps):
      """Performs protein grouping based only on protein to peptide mappings.
  
      :param protToPeps: dict, for each protein (=key) contains a set of
          associated peptides (=value). For Example {protein: {peptide, ...}, ...}
  
      #TODO: REFACTORING!!!
  
      returns a ProteinInference object
      """
      inference = ProteinInference(protToPeps)
      pepToProts = inference.pepToProts
  
      proteinClusters = _findProteinClusters(protToPeps, pepToProts)
      proteins = {}
      for clusterId, proteinCluster in enumerate(proteinClusters, 1):
          clusterProtToPeps = {p: protToPeps[p] for p in proteinCluster}
  
          #Find sameset proteins, define unique and non unique sameset proteins
          #NOTE: already unique proteins could be excluded to find sameset proteins
          samesetProteins = _findSamesetProteins(clusterProtToPeps)
          mergedProtToPeps = _mergeProteinEntries(samesetProteins,
                                                  clusterProtToPeps)
          mergedPepToProts = _invertMapping(mergedProtToPeps)
          uniqueProteins = _findUniqueMappingValues(mergedPepToProts)
          remainingProteins = set(mergedProtToPeps).difference(uniqueProteins)
  
          # Remove subset proteins and check if remaining proteins become unique
          subsetProteinInfo = _findSubsetProteins(remainingProteins,
                                                  mergedProtToPeps,
                                                  mergedPepToProts)
          subsetProteins = [p for p, _ in subsetProteinInfo]
          subsetRemovedProtToPeps = _reducedProtToPeps(mergedProtToPeps,
                                                       subsetProteins)
          subsetRemovedPepToProts = _invertMapping(subsetRemovedProtToPeps)
          uniqueSubsetRemoved = _findUniqueMappingValues(subsetRemovedPepToProts)
          remainingProteins = remainingProteins.difference(subsetProteins)
          remainingProteins = remainingProteins.difference(uniqueSubsetRemoved)
  
          # Find redundant proteins #
          subsumableProteins = _findRedundantProteins(subsetRemovedProtToPeps,
                                                      subsetRemovedPepToProts)
          remainingNonRedundant = remainingProteins.difference(subsumableProteins)
          groupInitiatingProteins = uniqueSubsetRemoved.union(remainingNonRedundant)
  
          # - Generate protein groups and assign proteins to groups - #
          #Generate protein groups
          clusterGroupIds = set()
          for protein in groupInitiatingProteins:
              proteinIds = AUX.toList(protein)
  
              groupId = inference.addProteinGroup(proteinIds[0])
              inference.addLeadingToGroups(proteinIds, groupId)
              clusterGroupIds.add(groupId)
  
          #Add redundant proteins here (must be subsumable I guess)
          for protein in subsumableProteins:
              proteinIds = AUX.toList(protein)
  
              connectedProteins = _mappingGetValueSet(
                  mergedPepToProts, mergedProtToPeps[protein]
              )
              flatConnectedProteins = _flattenMergedProteins(connectedProteins)
              groupIds = _mappingGetValueSet(
                  inference._proteinToGroupIds, flatConnectedProteins
              )
              inference.addSubsumableToGroups(proteinIds, groupIds)
              assert len(groupIds) > 1
  
          #Add subgroup proteins to the respective groups
          #NOTE: proteins that are only a subset of subsumable proteins are not
          #to be added as subset proteins to a group but as subsumable proteins.
          for protein, supersetProteins in subsetProteinInfo:
              proteinIds = AUX.toList(protein)
  
              #If the protein is a subset of at least one protein, that is not a
              #subsumable protein, then it should be added to the group as subset.
              leadingSuperProteins = supersetProteins.intersection(
                                                      groupInitiatingProteins)
              if leadingSuperProteins:
                  flatSupersetProteins = _flattenMergedProteins(
                                                      leadingSuperProteins)
                  superGroupIds = _mappingGetValueSet(
                      inference._proteinToGroupIds, flatSupersetProteins
                  )
                  inference.addSubsetToGroups(proteinIds, superGroupIds)
              #However, if all its super proteins are subsumable, the protein
              #itself is a subsumable protein.
              else:
                  flatSupersetProteins = _flattenMergedProteins(supersetProteins)
                  superGroupIds = _mappingGetValueSet(
                      inference._proteinToGroupIds, flatSupersetProteins
                  )
                  inference.addSubsumableToGroups(proteinIds, superGroupIds)
                  subsumableProteins.update(proteinIds)
              assert superGroupIds
  
          # - Define peptide properties - #
          groupToPeps = dict()
          allSubsumablePeps = set()
          for groupId in clusterGroupIds:
              group = inference.groups[groupId]
              if group.subsumableProteins:
                  subsumablePeptides = _mappingGetValueSet(
                      protToPeps, group.subsumableProteins
                  )
                  allSubsumablePeps.update(subsumablePeptides)
  
              groupPeptides = _mappingGetValueSet(protToPeps, group.proteins)
              groupToPeps[groupId] = groupPeptides
          pepToGroups = _invertMapping(groupToPeps)
  
          #Get unique peptides from peptide to protein mapping
          uniquePeptides = _findUniqueMappingKeys(mergedPepToProts)
          #Shared peptides have a groupPeptideCount > 1
          nonSharedPeptides = _findUniqueMappingKeys(pepToGroups)
          sharedPeptides = set(pepToGroups).difference(nonSharedPeptides)
          #Subsumable peptides are peptides from subsumable proteins that
          #are not shared peptides of multiple groups
          subsumablePeptides = allSubsumablePeps.difference(sharedPeptides)
          #groupUniquePeptides are the remaining ones (not shared with subsumable
          #proteins, groupPeptideCount == 1, not unique peptides)
          groupUniquePeptides = nonSharedPeptides.difference(subsumablePeptides)
          groupUniquePeptides = groupUniquePeptides.difference(uniquePeptides)
  
          inference._uniquePeptides.update(uniquePeptides)
          inference._groupUniquePeptides.update(groupUniquePeptides)
          inference._groupSubsumablePeptides.update(subsumablePeptides)
          inference._sharedPeptides.update(sharedPeptides)
  
          # - Generate protein entries and add them to the inference object - #
          subsetProteinInfoDict = dict(subsetProteinInfo)
          for protein, peptides in viewitems(mergedProtToPeps):
              _uniquePeptides = peptides.intersection(uniquePeptides)
              _groupUniquePeptides = peptides.intersection(groupUniquePeptides)
              _subsumablePeptides = peptides.intersection(subsumablePeptides)
              _sharedPeptides = peptides.intersection(sharedPeptides)
              proteinIds = AUX.toList(protein)
              for proteinId in proteinIds:
                  proteinEntry = Protein(proteinId, peptides)
                  if protein in groupInitiatingProteins:
                      proteinEntry.isLeading = True
                  elif protein in subsumableProteins:
                      proteinEntry.isSubsumable = True
                  if protein in subsetProteins:
                      superset = subsetProteinInfoDict[protein]
                      proteinEntry.isSubset = _flattenMergedProteins(superset)
                  if len(proteinIds) > 1:
                      proteinEntry.isSameset = set(proteinIds)
                  inference.proteins[proteinId] = proteinEntry
  
                  #Add peptides to protein entry
                  proteinEntry.uniquePeptides = _uniquePeptides
                  proteinEntry.groupUniquePeptides = _groupUniquePeptides
                  proteinEntry.groupSubsumablePeptides = _subsumablePeptides
                  proteinEntry.sharedPeptides = _sharedPeptides
  
          # - Save cluster information - #
          for proteinId in proteinCluster:
              inference._proteinToClusterId[proteinId] = clusterId
          inference.clusters[clusterId] = clusterGroupIds
  
      allProteins = set()
      for proteinGroup in viewvalues(inference.groups):
          allProteins.update(proteinGroup.proteins)
          allProteins.update(proteinGroup.subsumableProteins)
      assert len(allProteins) == len(protToPeps)
      return inference