def assign_crn_species(crn, signals):
    """ Returns types of species in a given CRN.

    On the types of species in an implementation CRN:
        - Signal species are implementation species that (are supposed to)
          correspond to formal species in a formal CRN.
        - Fuel species are implementation species that are required for some
          reactions and are assumed to be present, always.
        - Waste species are chemically inert byproducts that never react.
        - Reactive waste species are byproducts of a reaction that can react,
          but only with fuels or other reactive waste species to produce
          exclusively (reactive) waste species. A typical example for reactive
          wastes are so-called garbage collection mechanisms to turn an
          undesired waste into a desired waste.
        - Intermediate species are all other species that do not fall in any
          above category.

    Returns:
        set(): intermediates
        set(): wastes
        set(): reactive wastes
    """
    species = set().union(*[set().union(*rxn[:2]) for rxn in crn])
    # A signal species cannot be considered waste.
    assert isinstance(signals, set)
    nonwastes = signals.copy()
    wastes = set()

    while True:
        # Add x to non-waste if in any reaction x is an reactant while there
        # are non-wastes taking part in the reaction. Reset the outer loop if
        # a new non-waste species is found.
        flag = False
        for x in species:
            if x in nonwastes:
                continue
            for rxn in crn:
                if x in rxn[0] and len(nonwastes & set(rxn[0] + rxn[1])):
                    nonwastes.add(x)
                    flag = True
                    break
        if not flag:
            break

     # Inert and reactive waste species.
    wastes = species - nonwastes

    # An intermediate species 
    intermediates = species - signals - wastes

    # Let's assert here, to find the problems.
    reactive_waste = set()
    for w in list(wastes):
        if any(w in rxn[0] for rxn in crn):
            reactive_waste.add(w)

    return intermediates, wastes, reactive_waste