getMinNrFluxes Returns the minimal set of fluxes that satisfy the model using mixed integer linear programming. model a model structure toMinimize either a cell array of reaction IDs, a logical vector with the same number of elements as reactions in the model, of a vector of indexes for the reactions that should be minimized (optional, default model.rxns) params *obsolete option* scores vector of weights for the reactions. Negative scores should not have flux. Positive scores are not possible in this implementation, and they are changed to max(scores(scores<0)). Must have the same dimension as toMinimize (find(toMinimize) if it is a logical vector) (optional, default -1 for all reactions) x the corresponding fluxes for the full model I the indexes of the reactions in toMinimize that were used in the solution exitFlag 1: optimal solution found -1: no feasible solution found -2: optimization time out NOTE: Uses 1000 mmol/gDW/h as an arbitary large flux. Could possibly cause problems if the fluxes in the model are larger than that. Usage: [x,I,exitFlag]=getMinNrFluxes(model, toMinimize, params, scores)
0001 function [x,I,exitFlag]=getMinNrFluxes(model, toMinimize, params,scores) 0002 % getMinNrFluxes 0003 % Returns the minimal set of fluxes that satisfy the model using 0004 % mixed integer linear programming. 0005 % 0006 % model a model structure 0007 % toMinimize either a cell array of reaction IDs, a logical vector 0008 % with the same number of elements as reactions in the model, 0009 % of a vector of indexes for the reactions that should be 0010 % minimized (optional, default model.rxns) 0011 % params *obsolete option* 0012 % scores vector of weights for the reactions. Negative scores 0013 % should not have flux. Positive scores are not possible in this 0014 % implementation, and they are changed to max(scores(scores<0)). 0015 % Must have the same dimension as toMinimize (find(toMinimize) 0016 % if it is a logical vector) (optional, default -1 for all reactions) 0017 % 0018 % x the corresponding fluxes for the full model 0019 % I the indexes of the reactions in toMinimize that were used 0020 % in the solution 0021 % exitFlag 1: optimal solution found 0022 % -1: no feasible solution found 0023 % -2: optimization time out 0024 % 0025 % NOTE: Uses 1000 mmol/gDW/h as an arbitary large flux. Could possibly 0026 % cause problems if the fluxes in the model are larger than that. 0027 % 0028 % Usage: [x,I,exitFlag]=getMinNrFluxes(model, toMinimize, params, scores) 0029 0030 exitFlag=1; 0031 0032 if nargin<2 0033 toMinimize=model.rxns; 0034 elseif ~islogical(toMinimize) && ~isnumeric(toMinimize) 0035 toMinimize=convertCharArray(toMinimize); 0036 else 0037 toMinimize=model.rxns(toMinimize); 0038 end 0039 0040 %For passing parameters to the solver 0041 if nargin<3 0042 params=struct(); 0043 end 0044 0045 if nargin<4 0046 %It says that the default is -1, but that is to fit with other code 0047 scores=ones(numel(toMinimize),1)*1; 0048 else 0049 if numel(scores)~=numel(toMinimize) 0050 EM='The number of scores must be the same as the number of reactions to minimize'; 0051 dispEM(EM); 0052 end 0053 0054 %Change positive scores to have a small negative weight. This is a 0055 %temporary solution. 0056 scores(scores>=0)=max(scores(scores<0)); 0057 0058 %It says that the default is -1, but that is to fit with other code 0059 scores=scores*-1; 0060 end 0061 0062 %Check if the model is in irreversible format 0063 if any(model.rev) 0064 %Convert the model to irreversible format 0065 irrevModel=convertToIrrev(model); 0066 0067 %Find the indexes for the reactions in toMinimize 0068 [indexes, I]=ismember(strrep(irrevModel.rxns,'_REV',''),toMinimize); 0069 else 0070 irrevModel=model; 0071 0072 %Find the indexes for the reactions in toMinimize 0073 [indexes, I]=ismember(irrevModel.rxns,toMinimize); 0074 end 0075 0076 indexes=find(indexes); 0077 %Adjust scores to fit with reversible 0078 scores=scores(I(indexes)); 0079 0080 %Add binary constraints in the following manner: - Add one unique 0081 %"metabolite" for each integer reaction as a substrate. 0082 % These metabolites can have net production 0083 %- Add reactions for the production of each of those metabolites. The 0084 % amount produced in one reaction unit must be larger than the largest 0085 % possible flux in the model (but not too large to avoid bad scaling) 0086 0087 %Calculate a solution to the problem without any constraints. This is to 0088 %get an estimate about the magnitude of fluxes in the model and to get a 0089 %feasible start solution. 0090 sol=solveLP(irrevModel,1); 0091 0092 %Return an empty solution if the non-constrained problem couldn't be solved 0093 if isempty(sol.x) 0094 x=[]; 0095 I=[]; 0096 exitFlag=-1; 0097 return; 0098 end 0099 0100 %Take the maximal times 5 to have a safe margin. If it's smaller than 1000, 0101 %then use 1000 instead. 0102 maxFlux=max(max(sol.x)*5,1000); 0103 0104 intArray=speye(numel(irrevModel.rxns))*-1; 0105 intArray=intArray(indexes,:); 0106 prob.a=[irrevModel.S;intArray]; 0107 a=[sparse(numel(irrevModel.mets),numel(indexes));speye(numel(indexes))*maxFlux]; 0108 prob.a=[prob.a a]; 0109 prob.ints.sub=numel(irrevModel.rxns)+1:numel(irrevModel.rxns)+numel(indexes); 0110 0111 prob.c=[zeros(numel(irrevModel.rxns),1);scores(:);zeros(size(prob.a,1),1)]; %Minimize the number of fluxes 0112 prob.A=[prob.a -speye(size(prob.a,1))]; 0113 prob.blc=[irrevModel.b(:,1);zeros(numel(indexes),1)]; 0114 if size(irrevModel.b,2)==2 0115 prob.buc=[irrevModel.b(:,2);inf(numel(indexes),1)]; 0116 else 0117 prob.buc=[irrevModel.b(:,1);inf(numel(indexes),1)]; 0118 end 0119 prob.blx=[irrevModel.lb;zeros(numel(indexes),1)]; 0120 prob.bux=[irrevModel.ub;ones(numel(indexes),1)]; 0121 prob.lb = [prob.blx; prob.blc]; 0122 prob.ub = [prob.bux; prob.buc]; 0123 prob.osense=1; 0124 prob.csense=repmat('E', 1, size(prob.a,1),1); 0125 prob.b=zeros(size(prob.a,1), 1); 0126 0127 %Use the output from the linear solution as starting point. Only the values 0128 %for the integer variables will be used, but all are supplied. 0129 prob.sol.int.xx=zeros(numel(prob.c),1); 0130 prob.sol.int.xx(prob.ints.sub(sol.x(indexes)>10^-12))=1; 0131 prob.x0=[]; 0132 prob.vartype=repmat('C', size(prob.A,2), 1); 0133 prob.vartype(prob.ints.sub) = 'I'; % with .lb = 0 and .ub = 1, they are binary 0134 % integers (glpk in octave only allows 'continuous' or '', not 'binary') 0135 prob=rmfield(prob,{'blx','bux','blc','buc'}); 0136 0137 % Optimize the problem 0138 res = optimizeProb(prob,params,false); 0139 isFeasible=checkSolution(res); 0140 0141 if ~isFeasible 0142 x=[]; 0143 I=[]; 0144 exitFlag=-1; 0145 return; 0146 end 0147 0148 xx=res.full(1:numel(irrevModel.rxns)); 0149 I=res.full(numel(xx)+1:end); 0150 0151 %Check if Mosek aborted because it reached the time limit 0152 %TODO: modify for cobra/gurobi 0153 % if strcmp('MSK_RES_TRM_MAX_TIME',res.rcode) 0154 % exitFlag=-2; 0155 % end 0156 0157 %Map back to original model from irrevModel 0158 x=xx(1:numel(model.rxns)); 0159 if numel(irrevModel.rxns)>numel(model.rxns) 0160 x(model.rev~=0)=x(model.rev~=0)-xx(numel(model.rxns)+1:end); 0161 end 0162 0163 I=ismember(toMinimize,strrep(irrevModel.rxns(indexes(I>10^-12)),'_REV','')); 0164 end