def PartList_PropLoss(N, Loss):
    """
    Calculation of the partition list in a fragmentation with given proportional losses.
    This case represent the fragmentation of linear filaments
    The sum of offspring sizes is equal to the size of the fragmented group minus Loss*(#parts-1)
    
    Arguments:
    (int) N - the maximal size of group presented in population.
    (int) Loss - the number of cells lost at each break of the chain
    NOTE: the partition goes up to sizes N+1, since the fragmentation follows the growth of group of size N into size N+1
    
    Return:
    (list of lists) LC_ID - the list of partitions. Each partition contain its ID number and the LifeCycle tuple that describes the fragmentation pattern
    """
    #create list of life cycles
    LifeCycle = []
    for SizeOff in range(2, N + 2):
        #create generator of partitions of SizeOff (i.e. list of fragments sizes)
        PartitionGenerator = revlex_partitions(SizeOff)
        #convert generator into a list of partititons
        PartList = []
        for Part in PartitionGenerator:
            L = len(Part)
            E = [0] * L
            for j in range(L):
                E[j] = Part[j]
            PartList.append(E)
        #Transform list of partitions into list of life cycles
        for Reaction in range(
                1, len(PartList)
        ):  #the first partition is trivial and therefore does not correspond to a reaction
            Num_of_parts = len(PartList[Reaction])
            LifeCycle.append([(SizeOff + Loss * (Num_of_parts - 1),
                               PartList[Reaction], 1, 0)])

    #attach an ID number to each life cycle
    pre_LC_ID = []
    for counter in range(len(LifeCycle)):
        pre_LC_ID.append([counter, LifeCycle[counter]])

    LC_ID = []
    for ID in pre_LC_ID:
        if ID[1][0][0] < (N + 2):
            LC_ID.append(ID)

    return LC_ID
def Generate_Random_Stochastic_LC(Nmax):
    """
    Generates life cycle as a list of tuples
    
    Arguments:
    Nmax - the maximal size of groups EXISTING in the population
    
    Return:
    LifeCycle - life cycle structure
    """
    TrigProbMagnitude = np.random.uniform(
        0.0, 1.0, Nmax + 1
    )  #the sum of probabilities of all rates of triggered fragmentation occurring with groups of a each size

    LifeCycle = []
    #set up triggered reactions
    for Size in range(2, Nmax + 2):
        #create generator of partitions of Size (i.e. list of fragments sizes)
        PartitionGenerator = revlex_partitions(Size)
        #convert generator into a list
        PartList = []
        for Part in PartitionGenerator:
            L = len(Part)
            E = [0] * L
            for j in range(L):
                E[j] = Part[j]
            PartList.append(E)

        #compute fragmentation probabilities
        Probs = np.random.exponential(1, len(PartList))
        if Size < Nmax + 1:
            Norm = TrigProbMagnitude[Size] / sum(Probs[1:])
        else:  #the combined fragmentation probability at the maximal size is equal to one
            Norm = 1 / sum(Probs[1:])
        Probs = Probs * Norm

        #Construct biological reactions data
        for Reaction in range(
                1, len(PartList)
        ):  #the first partition is trivial and therefore does not correspond to a reaction
            RData = (Size, PartList[Reaction], Probs[Reaction], 0)
            LifeCycle.append(RData)

    return LifeCycle
def PartList_WL(N):
    """
    Calculation of the partition list in a fragmentation with losses
    The sum of offspring sizes is one less than the size of the fragmented group
        
    Arguments:
    (int) N - the maximal size of group presented in population.
    NOTE: the partition goes up to sizes N+1, since the fragmentation follows the growth of group of size N into size N+1
    
    Return:
    (list of lists) LC_ID - the list of partitions. Each partition contain its ID number and the LifeCycle tuple that describes the fragmentation pattern
    """
    #create list of life cycles
    LifeCycle = []
    for Size in range(2, N + 1):
        #create generator of partitions of Size (i.e. list of fragments sizes)
        PartitionGenerator = revlex_partitions(Size)
        #convert generator into a list of partititons
        PartList = []
        for Part in PartitionGenerator:
            L = len(Part)
            E = [0] * L
            for j in range(L):
                E[j] = Part[j]
            PartList.append(E)
        #Transform list of partitions into list of life cycles
        for Reaction in range(
                1, len(PartList)
        ):  #the first partition is trivial and therefore does not correspond to a reaction
            LifeCycle.append([(Size + 1, PartList[Reaction], 1, 0)])

    #attach an ID number to each life cycle
    LC_ID = []
    for counter in range(len(LifeCycle)):
        LC_ID.append([counter, LifeCycle[counter]])

    return LC_ID