def aut_getNutrientShiftResults(randOrgList, nutrientSet, rxnMat, prodMat,
                                sumRxnVec, Core, Currency):
    """
    Gets a set of organisms and a set of nutrients and performs random nutrient shifts on each. Marks all achievable molecules on this shifted nutrient set, and tests if the organism survives, and when it does, does its yield increase or decrease.

    ARGUMENTS:
    randOrgList (list): set of reaction indices for each organism's metabolic network.
    nutrientSet (list): custom IDs of nutrients originally in the environment.
    rxnMat (np.array): matrix of shape (R x M) that lists reactants in reactions.
    prodMat (np.array): matrix of shape(R x M) that lists products in reactions.
    sumRxnVec (np.array): vector of size R that lists the number of reactants in each reaction.
    Core (list): custom IDs of core molecules.
    Currency (list): custom IDs of currency molecules.

    RETURNS:
    notSurvive (int): number of shift cases where the organism cannot make all core molecules.
    yieldInc (int): number of shift cases where the organism's yield increases.
    yieldDec (int): number of shift cases where the organism's yield decreases.
    numCoresActive (list): number of core molecules that could still be made after shift if dead.
    """
    yieldDec, yieldInc, notSurvive = 0, 0, 0
    numCoresActive = []
    for orgRxns in tqdm(randOrgList[6000:7000]):
        # Get a vector of reactants in the current network.
        reactVec = np.logical_or.reduce(rxnMat[orgRxns]) * 1
        allowedNutrients = np.where(reactVec == 1)[0]

        # Nutrient shifting pipeline.
        randShiftedNutrient = np.random.choice(
            [n for n in allowedNutrients if n not in nutrientSet])
        shiftedNutrientSet = list(
            np.append(np.random.choice(nutrientSet), randShiftedNutrient))

        # Testing for survival on this nutrient set.
        satRxns = orgRxns[:]
        currSatRxnVec = np.zeros(len(rxnMat))
        currSatRxnVec[satRxns] = 1
        tempSatRxnVec = np.copy(currSatRxnVec)
        tempSatMetVec, tempSatRxnVec = markSatMetsRxns(tempSatRxnVec, rxnMat,
                                                       prodMat, sumRxnVec, [],
                                                       shiftedNutrientSet,
                                                       Currency)

        # Survival guaranteed.
        if tempSatMetVec[Core].all():
            # Checking if yield increases or decreases.
            if (fitCost(np.nonzero(tempSatRxnVec)[0], shiftedNutrientSet) <
                    fitCost(orgRxns, nutrientSet)):
                yieldDec += 1
            else:
                yieldInc += 1
        else:
            notSurvive += 1
            numCoresActive.append(np.count_nonzero(tempSatMetVec[Core]))

    return notSurvive, yieldInc, yieldDec, numCoresActive
Ejemplo n.º 2
0
def prunedSatsMets(remRxns, satRxns, rxnMat, prodMat, sumRxnVec, coreProdRxns,
                   nutrientSet, Currency, coreTBP):
    # Creating a temporary set of reactions with
    # some reactions pruned.
    tempSatRxns = np.copy(satRxns)
    tempSatRxns[remRxns] = 0

    # Calculating the marked set of reactions from the temporary set.
    return markSatMetsRxns(tempSatRxns, rxnMat, prodMat, sumRxnVec,
                           coreProdRxns, nutrientSet, Currency)
Ejemplo n.º 3
0
def pruneOrgNet(satRxns, rxnMat, prodMat, sumRxnVec, Core, nutrientSet,
                Currency):
    currSatRxnVec = np.zeros(len(rxnMat))
    currSatRxnVec[satRxns] = 1

    while True:
        # Keeping track of what the graph currently looks like.
        currSatRxns = np.nonzero(currSatRxnVec)[0]

        # Marking out which reactions are singly removable.
        removableMets = np.array([])
        for remRxn in currSatRxns:
            tempSatRxnVec = np.copy(currSatRxnVec)
            tempSatRxnVec[remRxn] = 0
            tempSatMetVec, tempSatRxnVec = markSatMetsRxns(
                tempSatRxnVec, rxnMat, prodMat, sumRxnVec, [], nutrientSet,
                Currency)
            if tempSatMetVec[Core].all():
                removableMets = np.append(removableMets, remRxn)

        # If no more reactions can be pruned, exit with the current vector state.
        if not removableMets.any():
            return np.nonzero(currSatRxnVec)[0]

        # Randomly permuting the singly removable reactions.
        removalOrder = np.random.permutation(removableMets)

        # Calling a vector of reaction that can be removed.
        for remRxn in removalOrder.astype(int):
            # Mark what is achievable when the reaction is removed.
            tempSatRxnVec = np.copy(currSatRxnVec)
            tempSatRxnVec[remRxn] = 0
            tempSatMetVec, tempSatRxnVec = markSatMetsRxns(
                tempSatRxnVec, rxnMat, prodMat, sumRxnVec, [], nutrientSet,
                Currency)

            # If all core molecules can still be produced post removal, remove the reaction.
            if tempSatMetVec[Core].all():
                currSatRxnVec[remRxn] = 0
            else:
                break
Ejemplo n.º 4
0
def randWFitnessMinSubnet(satRxnVec, rxnMat, prodMat, sumRxnVec, coreProdRxns,
                          coreTBP, nutrientSet, Currency, stoich_matrix,
                          Energy):
    currSatRxnVec = np.copy(satRxnVec)
    mulFac = [1, 3, 3]

    while True:
        # Keeping track of what the graph currently looks like.
        currSatRxns = np.nonzero(currSatRxnVec)[0]

        # Marking out which reactions are singly removable.
        canRemoveVec = np.array([
            isFitterSubset(remRxn, currSatRxnVec, rxnMat, prodMat, sumRxnVec,
                           coreProdRxns, nutrientSet, Currency, coreTBP,
                           stoich_matrix, Energy) for remRxn in currSatRxns
        ]) * 1
        removableMets = currSatRxns[np.where(canRemoveVec)]

        # Randomly permuting the singly removable reactions.
        removalOrder = np.random.permutation(removableMets)

        # Calling a vector of reaction that can be removed.
        for remRxn in removalOrder:
            tempSatRxnVec = np.copy(currSatRxnVec)
            tempSatRxnVec[remRxn] = 0

            # Calculating the marked set of reactions from the temporary set.
            tempSatMetVec, tempSatRxnVec = markSatMetsRxns(
                tempSatRxnVec, rxnMat, prodMat, sumRxnVec, coreProdRxns,
                nutrientSet, Currency)

            # Checking if this still produces the core molecule.
            if coreTBP in np.nonzero(tempSatMetVec)[0]:
                newCost = sum([
                    sum(stoich_matrix[rxn][Energy] * mulFac)
                    for rxn in np.nonzero(tempSatRxnVec)[0]
                ])
                oldCost = sum([
                    sum(stoich_matrix[rxn][Energy] * mulFac)
                    for rxn in np.nonzero(currSatRxnVec)[0]
                ])
                if newCost >= oldCost:
                    currSatRxnVec[remRxn] = 0
            else:
                isEverythingRemovable = False
                break

        if not removableMets.any():
            return np.nonzero(currSatRxnVec)[0]
def cfn_getNutrientShiftResults(randFitterSet, secList, nutrientSet, rxnMat,
                                prodMat, sumRxnVec, Core, Currency):
    """
    Gets a set of pairs of cross-feeding organisms and a set of nutrients and performs random nutrient shifts on each. Marks all achievable molecules on this shifted nutrient set, and tests if both organisms survive, and when they do, does their yield increase or decrease.

    ARGUMENTS:
    randFitterSet (list): set of pair of reaction indices for each pair of organisms' metabolic networks.
    secList (list): set of pairs of custom IDs of metabolites secreted by first to second and vice versa.
    nutrientSet (list): custom IDs of nutrients originally in the environment.
    rxnMat (np.array): matrix of shape (R x M) that lists reactants in reactions.
    prodMat (np.array): matrix of shape(R x M) that lists products in reactions.
    sumRxnVec (np.array): vector of size R that lists the number of reactants in each reaction.
    Core (list): custom IDs of core molecules.
    Currency (list): custom IDs of currency molecules.

    RETURNS:
    notSurvive (int): number of shift cases where both organisms cannot make all core molecules.
    notSec (int): number of shift cases where the secretions where lost.
    yieldInc (int): number of shift cases where both organisms yield increases.
    yieldDec (int): number of shift cases where both organisms yield decreases.
    numCoresActive (list): number of core molecules that could still be made after shift if dead.
    """
    yieldDec, yieldInc, notSurvive, notSec = 0, 0, 0, 0
    numCoresActive = []
    thisIter = -1
    for (o1Rxns, o2Rxns) in tqdm(randFitterSet):
        thisIter += 1
        # Get a vector of reactants present in both networks.
        reactVec = np.logical_or(
            np.logical_or.reduce(rxnMat[o1Rxns]) * 1,
            np.logical_or.reduce(rxnMat[o2Rxns]) * 1)
        allowedNutrients = np.where(reactVec == 1)[0]

        # Nutrient shifting pipeline.
        randShiftedNutrient = np.random.choice(
            [n for n in allowedNutrients if n not in nutrientSet])
        shiftedNutrientSet = list(
            np.append(np.random.choice(nutrientSet), randShiftedNutrient))

        # Testing for survival on this nutrient set.
        sat1Rxns, sat2Rxns = o1Rxns[:], o2Rxns[:]
        currSatRxnVec1, currSatRxnVec2 = np.zeros(len(rxnMat)), np.zeros(
            len(rxnMat))
        currSatRxnVec1[sat1Rxns], currSatRxnVec2[sat2Rxns] = 1, 1
        tempSatRxnVec1, tempSatRxnVec2 = np.copy(currSatRxnVec1), np.copy(
            currSatRxnVec2)
        tempSatMetVec1, tempSatRxnVec1 = markSatMetsRxns(
            tempSatRxnVec1, rxnMat, prodMat, sumRxnVec, [], shiftedNutrientSet,
            Currency)
        tempSatMetVec2, tempSatRxnVec2 = markSatMetsRxns(
            tempSatRxnVec2, rxnMat, prodMat, sumRxnVec, [], shiftedNutrientSet,
            Currency)
        # Survival guaranteed.
        if tempSatMetVec1[Core].all() and tempSatMetVec2[Core].all():

            if (tempSatMetVec1[secList[thisIter][0]].all()
                    and tempSatMetVec2[secList[thisIter][1]].all()):

                # Checking if yield increases or decreases.
                if (fitCost(np.nonzero(tempSatRxnVec1)[0],
                            shiftedNutrientSet) < fitCost(o1Rxns, nutrientSet)
                        and (fitCost(
                            np.nonzero(tempSatRxnVec2)[0], shiftedNutrientSet)
                             < fitCost(o2Rxns, nutrientSet))):
                    yieldDec += 1
                else:
                    yieldInc += 1
            else:
                notSec += 1
                numCoresActive.append(
                    np.count_nonzero(tempSatMetVec1[Core]) - 1)
                numCoresActive.append(
                    np.count_nonzero(tempSatMetVec2[Core]) - 1)

        else:
            notSurvive += 1
            numCoresActive.append(np.count_nonzero(tempSatMetVec1[Core]))
            numCoresActive.append(np.count_nonzero(tempSatMetVec2[Core]))

    return notSurvive, notSec, yieldInc, yieldDec, numCoresActive
Ejemplo n.º 6
0
def giveRevScope(rxnMat, prodMat, sumRxnVec, nutrientSet, Currency, coreTBP):
    """
    Takes in the stoichiometric matrix in the form of a reaction 
    and product matrix, along with a sum vector mentioning the 
    number of reactants in each reaction in the matrix. Also takes
    in a set of nutrients available in the medium and a set of currency
    metabolites. Receives information about which core molecule must
    be produced.

    By reverse scope-expansion, discovers a subgraph that uses only the 
    nutrient set and currency metabolites to successfully generate the 
    core molecule. Note that this subgraph is not minimal, and must be
    pruned in order to remove side-reactions that are added but may, in
    principle, not be used to make the final core molecule. This merely
    returns the reverse-scope of the core molecule upto the nutrient set.

    RETURNS:
    Returns the satisfied metabolites and reactions in the subgraph
    (corresponding to a pathway.)

    Returns empty vectors if no such wholly satisfied subgraph is found.

    satMets, satRxns are sets of metabolites and reactions, with their custom IDs.
    """

    # Initializing all the vectors to propagate the satisfied subgraph search.
    seedVec, rxnProc = np.zeros(len(np.transpose(rxnMat))), np.zeros(
        len(rxnMat))
    seedVec[coreTBP] = 1
    coreProdRxns = (prodMat[:, coreTBP] == 1) * 1
    currScopeMets, prevScopeMets, deltaMetVec = np.copy(seedVec), np.copy(
        seedVec), np.copy(seedVec)

    while True:
        prevScopeMets = np.logical_or(currScopeMets, prevScopeMets)

        # Propagating reverse scope.
        rxnProc = (np.dot(prodMat, deltaMetVec) + rxnProc > 0) * 1
        currScopeMets = (np.dot(np.transpose(rxnMat),
                                np.dot(prodMat, deltaMetVec)) > 0) * 1
        currScopeMets = np.logical_xor(
            currScopeMets, np.logical_and(currScopeMets, prevScopeMets))

        # Marking the satisfied metabolites and reactions.
        satMets, satRxns = markSatMetsRxns(rxnProc, rxnMat, prodMat, sumRxnVec,
                                           coreProdRxns, nutrientSet, Currency)

        # If core has been reached, checking if everything is marked, then returning.
        if np.array_equal(satRxns, rxnProc):
            print('Everything marked.')
            return satMets, satRxns

        # Calculating the new metabolites that need to be produced
        # due to the new steps added to the reverse scope.
        deltaMetVec = np.logical_xor(
            currScopeMets, np.logical_and(currScopeMets, satMets)) * 1

        # If the full reverse scope has been reached, stopping and returning the marked set.
        if set(np.nonzero(currScopeMets)[0]).issubset(
                set(np.nonzero(prevScopeMets)[0])):
            print('Reached as far back as possible.')
            return satMets, satRxns
Ejemplo n.º 7
0
allowedNutrients = np.where(np.logical_or.reduce(rxnMat[necoliRxns]))[0]
viableNutrientSets = []
SIZE_OF_NUTRIENT_SET = 2

while not viableNutrientSets:
    SIZE_OF_NUTRIENT_SET += 1
    for thisNutSet in tqdm(
            list(itertools.combinations(allowedNutrients,
                                        SIZE_OF_NUTRIENT_SET))):
        # Testing for survival on this nutrient set.
        satRxns = necoliRxns[:]
        currSatRxnVec = np.zeros(len(rxnMat))
        currSatRxnVec[satRxns] = 1
        tempSatRxnVec = np.copy(currSatRxnVec)
        tempSatMetVec, tempSatRxnVec = markSatMetsRxns(tempSatRxnVec, rxnMat,
                                                       prodMat, sumRxnVec, [],
                                                       list(thisNutSet),
                                                       Currency)

        # Survival guaranteed.
        if np.sum(tempSatMetVec[Core]) == len(Core) - 1:
            # Checking if yield increases or decreases.
            viableNutrientSets.append(thisNutSet)

#---------------------------------------------------------------------------
# Results
#---------------------------------------------------------------------------
# [17, 19, 42, 69]
# [17, 19, 69, 228]
# [17, 20, 69, 228]
# [17, 69, 133, 228]
# [17, 69, 228, 458]