示例#1
0
    def run(self, reactions, matrix, lb, ub, fbaParams):
        """ analyze objective function, and solve the LP/QP/NLP

        Keyword arguments:

        reactions  -- dictionary of all reactions { name : matrix column } or
                      { name : tuple of indices } for split fluxes
        matrix    -- the stoichiometric matrix of the metabolic network
        lb        -- list of lower bounds (indexed like matrix columns)
        ub        -- list of upper bounds (indexed like matrix columns)
        fbaParams -- optimization parameters (incl. objective function)

        Returns:
        obj_value, solution

        obj_value -- optimal value of objective function
        solution  -- a solution where the objective function assumes obj_value
        """
        maxmin, objStr, numIter = (fbaParams.maxmin, fbaParams.objStr,
                                   fbaParams.numIter)
        # Multiply by -1 for maximization
        maxmin_factor = -1. if maxmin == True else 1.
        nCols = len(lb)

        threshold = 0.95
        nReactions = len(lb)

        # Get additional linear equality and inequality constraints
        try:
            Aeq, beq, Aineq, bineq = self.makeConstraintMatrices(
                matrix,
                *ParamParser.linConstraintsToVectors(fbaParams.linConstraints,
                                                     reactions, nCols))
        except ValueError:
            # If any linear constraint is contradictory, return empty solution
            return 0., []

        try:
            objective = ParamParser.convertObjFuncToLinVec(
                objStr, reactions, nCols, maxmin)
        except Exception, strerror:
            print(
                "Error while trying to build coefficient vector of "
                "linear objective function:")
            print strerror
            exit()
示例#2
0
def checkLinConstraints(solution, model, linConstraints):
    """ check if flux distribution 'solution' violates any of the given linear
        equality and inequality constraints

    Keyword arguments:

    solution       -- flux distribution (MetabolicFlux object)
    model          -- MetabolicModel (for generating flux and coefficient
                                      vectors)
    linConstraints -- list of LinearConstraint objects

    Returns:
    eqErr, ineqErr

    eqErr   -- dict {index in linConstraints : deviation} for each equality
               constraint
    ineqErr -- dict {index in linConstraints : deviation} for each inequality
               constraint - if deviation is negative, constraint is satisfied
    """
    solutionVec = solution.getVecOrderedByModel(model)
    eqs, ineqs = ParamParser.linConstraintsToVectors(linConstraints,
                                                     model.reactionDict)
    eqIndex, ineqIndex = [], []
    for i in range(len(linConstraints)):
        if linConstraints[i].isEq:
            eqIndex.append(i)
        else:
            ineqIndex.append(i)

    eqErr, ineqErr = {}, {}
    if eqs:
        A = [row[0] for row in eqs]
        b = [row[1] for row in eqs]
        dotVec = dot(A, solutionVec)
        for i in range(len(b)):
            eqErr[eqIndex[i]] = abs(dotVec[i] - b[i])

    if ineqs:
        A = [row[0] for row in ineqs]
        b = [row[1] for row in ineqs]
        dotVec = dot(A, solutionVec)
        for i in range(len(b)):
            ineqErr[ineqIndex[i]] = dotVec[i] - b[i]

    return eqErr, ineqErr
示例#3
0
    def runOnModel(self,
                   model,
                   fbaParams,
                   threshp=.95,
                   objFuncVal=None,
                   rmDeadEnds=True):
        """ perform metabolite flux minimization on the given model with
            objective value <= threshp * maximum

        Keyword arguments:

        model        -- the MetabolicModel
        fbaParams    -- FBA parameters
        threshp      -- threshold percentage (objective_value <= thresp*maximum)
        objFuncVal   -- FBA optimum for objective function (optional)
        rmDeadEnds   -- if True, remove all reactions with dead ends before
                        analysis (faster and gives an optimal solution, as well)

        Returns:
        minVec, dimReduced

        minVec       -- list of minimum values, indexed like metabolites
        dimReduced   -- pair (nRows, nColumns) with dimensions of reduced matrix
        """
        if rmDeadEnds:
            deadReactions = model.findDeadEnds(True)[1]
            modelRed = model.getSubModelByExcludeList(deadReactions)
            cbz = model.canBeZero(deadReactions)
            nonZeroDeadEnds = [
                deadReactions[i] for i in range(len(deadReactions))
                if not cbz[i]
            ]
            if nonZeroDeadEnds:
                print(
                    "The following blocked reactions are constrained to a "
                    "non-zero flux:\n  " + "\n  ".join(nonZeroDeadEnds) +
                    "\nThe problem is infeasible.")
                return [], array(modelRed.getStoichiometricMatrix()).shape
        else:
            modelRed = model

        matrix = array(modelRed.getStoichiometricMatrix())
        dimReduced = matrix.shape
        lb, ub = modelRed.getBounds()

        # Split fluxes into non-negative components
        matrixSplit, reactionsSplit, lbSplit, ubSplit = \
            FbAnalyzer.splitFluxes(matrix, modelRed.getReactionNames(), lb, ub)

        # Build (negative) objective function vector for split fluxes
        objective = ParamParser.convertObjFuncToLinVec(fbaParams.objStr,
                                                       reactionsSplit,
                                                       len(lbSplit),
                                                       fbaParams.maxmin)
        maxmin_factor = -1. if fbaParams.maxmin else 1.

        # If the optimum of the objective function is not given, perform FBA
        if objFuncVal is None:
            fba = FbAnalyzer(self.solver)

            objFuncVal, sFlux = fba.run(reactionsSplit, matrixSplit, lbSplit,
                                        ubSplit, fbaParams)

            if len(sFlux) == 0:
                return [], dimReduced

        # Use negative threshold (objective value >= threshold is equivalent to
        # -objective value <= -threshold, and objective already has coefficient
        # -1 due to maximization)
        threshold = maxmin_factor * objFuncVal * threshp
        print "obj func. opt:", objFuncVal
        print "Threshold: ", threshold
        try:
            eqs, ineqs = ParamParser.linConstraintsToVectors(
                fbaParams.linConstraints, modelRed.reactionDict, len(lbSplit))
        except ValueError, e:
            # If any linear constraint is contradictory, report error
            print "Optimization not possible due to contradictory constraints:"
            print "  " + e
            exit()
示例#4
0
    def runOnModel(self,
                   model,
                   wtSolution,
                   linConstraints=[],
                   numIter=1,
                   weights=None,
                   blockedReactions=[]):
        """ construct and solve the quadratic optimization problem
          - this function runs directly on a MetabolicModel and a MetabolicFlux

        Keyword arguments:

        model          -- the MetabolicModel
        wtSolution     -- FBA solution for the wildtype (given as MetabolicFlux)
        linConstraints -- list of LinearConstraint objects
        numIter        -- number of iterations of NLP to perform
        weights        -- weight vector for weighted MOMA (None -> perform
                          regular MOMA, else: weight flux i with weights[i])
        blockedReactions
                       -- remove the given blocked reactions before analysis
                          (faster and gives an optimal solution, as well)

        Returns:
        distance, solution, status, dimReduced

        distance   -- minimum possible distance from wtSolution with the given
                      matrix & constraints
        solution   -- a solution with minimal distance to wtSolution
                     (as MetabolicFlux)
        status     -- SolverStatus after optimization
        dimReduced -- pair (nRows, nColumns) with dimensions of reduced matrix
        """
        if blockedReactions:
            modelRed = model.getSubModelByExcludeList(blockedReactions)
            cbz = model.canBeZero(blockedReactions)
            nonZeroDeadEnds = [
                blockedReactions[i] for i in range(len(blockedReactions))
                if not cbz[i]
            ]
            if nonZeroDeadEnds:
                print(
                    "The following blocked reactions are constrained to a "
                    "non-zero flux:\n  " + "\n  ".join(nonZeroDeadEnds) +
                    "\nThe problem is infeasible.")
                return (nan, MetabolicFlux(), SolverStatus.PRIM_INFEAS,
                        array(modelRed.getStoichiometricMatrix()).shape)

            reactionsRed = set(modelRed.getReactionNames())
            if weights is None:
                weightsRed = None
            else:
                weightsRed = [0.] * len(modelRed)
                for rea in wtSolution:
                    if rea in reactionsRed:
                        weightsRed[modelRed.reactionDict[rea]] = \
                            weights[model.reactionDict[rea]]
                    weightsRed = array(weightsRed)
        else:
            modelRed = model
            weightsRed = weights

        matrix = array(modelRed.getStoichiometricMatrix())
        dimReduced = matrix.shape
        lb, ub = map(array, modelRed.getBounds())
        try:
            eqs, ineqs = ParamParser.linConstraintsToVectors(
                linConstraints, modelRed.reactionDict)
        except ValueError:
            # If any linear constraint is contradictory, return empty solution
            return (nan, MetabolicFlux(), SolverStatus.PRIM_INFEAS,
                    array(modelRed.getStoichiometricMatrix()).shape)

        distance, solution, status = self.run(
            matrix, lb, ub, wtSolution.getVecOrderedByModel(modelRed), eqs,
            ineqs, numIter, weightsRed)
        flux = MetabolicFlux(modelRed, solution)

        # Add removed reactions with flux 0. and original bounds to solution
        if len(modelRed) != len(model) and solution != []:
            reactionsRed = set(modelRed.getReactionNames())
            for rea in model:
                if rea.name not in reactionsRed:
                    flux.fluxDict[rea.name] = 0.
                    flux.boundsDict[rea.name] = (rea.lb, rea.ub)

        return distance, flux, status, dimReduced
示例#5
0
            else:
                obj_value, sFlux = fba.run(modelRed.getReactionNames(), matrix,
                                           lb, ub, fbaParams)

            if len(sFlux) == 0:
                lbFull, ubFull = map(array, model.getBounds())
                return [], sFlux, lbFull, ubFull, dimReduced

        # Use negative threshold (objective value >= threshold is equivalent to
        # -objective value <= -threshold, and objective already has coefficient
        # -1 due to maximization)
        threshold = maxmin_factor * obj_value * threshp
        print "obj func. opt:", obj_value
        print "Threshold: ", threshold
        try:
            eqs, ineqs = ParamParser.linConstraintsToVectors(
                fbaParams.linConstraints, modelRed.reactionDict)
        except ValueError, e:
            # If any linear constraint is contradictory, report error
            print "Optimization not possible due to contradictory constraints:"
            print "  " + e
            exit()

        minmax = self.run(objective, matrix, lb, ub, threshold, eqs, ineqs)

        # Add removed reactions with min = max = 0. to minmax and solution
        if len(modelRed) != len(model):
            minmaxFull, sFluxFull = [], []
            reactionsRed = set(modelRed.getReactionNames())

            for rea in model:
                if rea.name in reactionsRed:
示例#6
0
    def runWithTotalFluxMinimization(self,
                                     reactions,
                                     matrix,
                                     lb,
                                     ub,
                                     fbaParams,
                                     start_value_total=None,
                                     tolerance_total=EPSILON,
                                     tolerance_obj=EPSILON):
        """ perform FBA with LP iteratively to find a flux distribution with
            optimal value of objective function value and minimum total flux

        This only works with non-negative flux variables, i.e. split fluxes!
        The objective function and all constraints must be linear.

        This function limits the total flux to a parameter and then iteratively
        fits this parameter until either the change in total flux is less than
        tolerance_total or the change in the objective function is less than
        tolerance_obj

        Keyword arguments:

        reactions  -- dictionary { name : tuple of indices } for split fluxes
        matrix    -- the stoichiometric matrix of the metabolic network
        lb        -- list of lower bounds (indexed like matrix columns)
        ub        -- list of upper bounds (indexed like matrix columns)
        fbaParams -- optimization parameters (incl. objective function)
        start_value_total -- initial flux limit (if None: set to len(reactions))
        tolerance_total   -- stopping criterion: change in flux limit below this
        tolerance_obj     -- stopping criterion: change in objective function
                                                 value below this

        Returns:
        limit, obj_value, solution, nSteps

        limit     -- limit of total flux
        obj_value -- optimal value of objective function
        solution  -- a solution where the objective function assumes obj_value,
                     obtained with limited total flux
        nSteps    -- number of steps until optimal limit was found
        """
        maxmin, objStr = (fbaParams.maxmin, fbaParams.objStr)
        # Multiply by -1 for maximization
        maxmin_factor = -1. if maxmin == True else 1.
        nCols = len(lb)

        for value in lb:
            if value < 0.:
                print(
                    "Error: Minimization of total flux requires non-negative"
                    " flux variables.")
                exit()

        # Get additional linear equality and inequality constraints
        try:
            Aeq, beq, Aineq, bineq = self.makeConstraintMatrices(
                matrix,
                *ParamParser.linConstraintsToVectors(fbaParams.linConstraints,
                                                     reactions, nCols))
        except ValueError:
            # If any linear constraint is contradictory, return empty solution
            return 0., []

        # Prepare additional constraint: total flux < threshold
        if Aineq is None:
            Aineq, bineq = array([[1.] * nCols]), []
        else:
            # Aineq has extra line for total flux
            Aineq = vstack((Aineq, [[1.] * nCols]))
            # Convert bineq to list (allows easy addition of extra value)
            bineq = list(bineq)

        # Build linear objective function (given as coefficient vector)
        try:
            objective = ParamParser.convertObjFuncToLinVec(
                objStr, reactions, nCols, maxmin)
        except Exception, strerror:
            print(
                "Error while trying to build coefficient vector of "
                "linear objective function:")
            print strerror
            exit()
示例#7
0
    def run(self, reactions, matrix, lb, ub, fbaParams):
        """ analyze objective function, and solve the LP/QP/NLP

        Keyword arguments:

        reactions  -- dictionary of all reactions { name : matrix column } or
                      { name : tuple of indices } for split fluxes
        matrix    -- the stoichiometric matrix of the metabolic network
        lb        -- list of lower bounds (indexed like matrix columns)
        ub        -- list of upper bounds (indexed like matrix columns)
        fbaParams -- optimization parameters (incl. objective function)

        Returns:
        obj_value, solution

        obj_value -- optimal value of objective function
        solution  -- a solution where the objective function assumes obj_value
        """
        maxmin, objStr, numIter = (fbaParams.maxmin, fbaParams.objStr,
                                   fbaParams.numIter)
        # Multiply by -1 for maximization
        maxmin_factor = -1. if maxmin == True else 1.
        nCols = len(lb)

        # Get additional linear equality and inequality constraints
        try:
            Aeq, beq, Aineq, bineq = self.makeConstraintMatrices(matrix,
                *ParamParser.linConstraintsToVectors(fbaParams.linConstraints,
                                                     reactions, nCols))
        except ValueError:
            # If any linear constraint is contradictory, return empty solution
            return 0., []

        if objStr.lower().startswith("per_flux"):
            # special nonlinear objective function: single flux per flux unit
            # e.g. "per_flux(Biomass)"
            try:
                str_perflux, str_flux = objStr.split('(', 2)
            except ValueError:
                print ("Error in scenario file in objective function "
                       "definition.\nPER_FLUX syntax: "
                       "PER_FLUX(<reaction_name>)")
                exit()

            if str_perflux.strip().lower() != "per_flux":
                print ("Error: Objective function '%s' is not a reaction name "
                       "or a PER_FLUX definition.\n"
                       "Currently, objective function must be a linear "
                       "combination of reaction fluxes or PER_FLUX(<reaction>)."
                       % objStr)
                exit()

            rea_name = str_flux.split(')', 1)[0].strip()
            try:
                biomass_index = reactions[rea_name][0]
            except TypeError:
                biomass_index = reactions[rea_name]
            obj_func = lambda x : -biomass_per_flux(x, biomass_index)

            if numIter < 0:
                numIter = FbaParam.DEFAULT_NUMITER

            try:
                ps = NonLinearProblem(Aeq, beq, Aineq, bineq, lb, ub,
                                      self.solver)
                ps.setObjective(obj_func)
                ps.setObjGrad(lambda x :
                              neg_grad_biomass_per_flux(x, biomass_index))
                if fbaParams.nlc != []:
                    ps.setNonlinearConstraints(fbaParams.nlc)
                    ps.setNlcGrad(fbaParams.nlc_grad)
                spIter = StartPointIterator(nCols, numIter)
                spIter.setRange(-1., 1.)
                ps.setStartPointIterator(spIter)

            except ValueError, strerror:
                print strerror
                exit()