Skip to content

Commit f0c5d8b

Browse files
committed
optimise cardinality reduced regularisation
1 parent f38cb1c commit f0c5d8b

File tree

10 files changed

+308
-249
lines changed

10 files changed

+308
-249
lines changed

external/analysis/plotConfMat/plotConfMat.m

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ function plotConfMat(varargin)
3535
% plotting the colors
3636
imagesc(confpercent);
3737
title(sprintf('Accuracy: %.2f%%', 100*trace(confmat)/sum(confmat(:))));
38+
%ylabel('Predicted Class'); xlabel('Target Class');
3839
ylabel('Predicted Class'); xlabel('Target Class');
3940

4041
% set the colormap

initCobraToolbox.m

+1-1
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ function initCobraToolbox(updateToolbox)
224224
%This means that the checked-out commit -- which is the one that the super-project (core) needs -- is not associated with a local branch name.
225225
%[status_gitSubmodule, result_gitSubmodule] = system(['git submodule update --init --remote --no-fetch ' depthFlag]);%old
226226
%[status_gitSubmodule, result_gitSubmodule] = system(['git submodule foreach git submodule update --init --recursive']);% 23/9/21 RF submodules point to master
227-
[status_gitSubmodule, result_gitSubmodule] = system('git submodule update --init --recursive');% 23/9/21 RF submodules point to master, don't pull in remote changes
227+
[status_gitSubmodule, result_gitSubmodule] = system('git submodule update --init --recursive --depth 1');% 23/9/21 RF submodules point to master, don't pull in remote changes
228228
%[status_gitSubmodule, result_gitSubmodule] = system('git submodule foreach git checkout master');
229229
[status_gitSubmodule, result_gitSubmodule] = system('git submodule foreach git checkout master');% 30/9/21 RF submodules point to master, don't pull in remote changes
230230

src/analysis/FBA/optimizeCbModel.m

+9-3
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,16 @@
4545
% * ctrs `k x 1` Cell Array of Strings giving IDs of the coupling constraints
4646
%
4747
% * dsense - `k x 1` character array with entries in {L,E,G}
48-
% * g0 - `n x 1` weights on zero norm
49-
% * g1 - `n x 1` weights on one norm
48+
% * g0 - `n x 1` weights on zero norm, where positive is minimisation, negative is maximisation, zero is neither.
49+
% * g1 - `n x 1` weights on one norm, where positive is minimisation, negative is maximisation, zero is neither.
5050
% * g2 - `n x 1` weights on two norm
5151
%
5252
% osenseStr: Maximize ('max')/minimize ('min') (opt, default =
5353
% 'max') linear part of the objective. Nonlinear
5454
% parts of the objective are always assumed to be
5555
% minimised.
5656
%
57-
% minNorm: {(0), 'one', 'zero', > 0 , n x 1 vector}, where `[m,n]=size(S)`;
57+
% minNorm: {(0), 'one', 'zero', > 0 , n x 1 vector, 'optimizeCardinality'}, where `[m,n]=size(S)`;
5858
% 0 - Default, normal LP
5959
% 'one' Minimise the Taxicab Norm using LP.
6060
%
@@ -66,6 +66,7 @@
6666
% ~& lb \leq v \leq ub
6767
%
6868
% A LP solver is required.
69+
6970
% 'zero' Minimize the cardinality (zero-norm) of v
7071
%
7172
% .. math::
@@ -86,6 +87,9 @@
8687
% http://dx.doi.org/10.1016/j.ejor.2014.11.031
8788
% A LP solver is required.
8889
%
90+
% 'optimizeCardinality' as for 'zero' option but uses
91+
% model.g0 - `n x 1` weights on zero norm, where positive is minimisation, negative is maximisation, zero is neither.
92+
%
8993
% The remaining options work only with a valid QP solver:
9094
%
9195
% > 0 Minimises the squared Euclidean Norm of internal fluxes.
@@ -107,6 +111,8 @@
107111
% s.t. ~& S v = b \\
108112
% ~& c^T v = f \\
109113
% ~& lb \leq v \leq ub
114+
%
115+
110116
%
111117
% allowLoops: {0,(1)} If false, then instead of a conventional FBA,
112118
% the solver will run an MILP version which does not allow

src/analysis/relaxedFBA/relaxFBA_cappedL1.m

+21-17
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
stop = false;
7777
solution.stat = 1;
7878

79+
feasTol = getCobraSolverParams('LP', 'feasTol');
7980

8081
if exist('param','var')
8182
if isfield(param,'excludedReactions') == 0
@@ -95,11 +96,6 @@
9596
param.nbMaxIteration = 1000;
9697
end
9798

98-
if isfield(param,'epsilon') == 0
99-
feasTol = getCobraSolverParams('LP', 'feasTol');
100-
param.epsilon = feasTol*100;
101-
end
102-
10399
if isfield(param,'gamma0') == 0
104100
param.gamma0 = 0; %trade-off parameter of l0 part v
105101
end
@@ -108,27 +104,29 @@
108104
%Small positive penalty seems to be important to ensure algorithm
109105
%is numerically stable for small networks.
110106
%TODO: why?
111-
param.gamma1 = 1e-6; %trade-off parameter of l1 part v
107+
param.gamma1 = feasTol*100; %trade-off parameter of l1 part v
108+
112109
end
113110

114111
if isfield(param,'lambda0') == 0
115-
param.lambda0 = 10; %trade-off parameter of l0 part of r
112+
param.lambda0 = 1; %trade-off parameter of l0 part of r
116113
end
117114

118115
if isfield(param,'lambda1') == 0
119-
param.lambda1 = 1; %trade-off parameter of l1 part of r
116+
param.lambda1 = feasTol*100; %trade-off parameter of l1 part of r
120117
end
121118

122119
if isfield(param,'alpha0') == 0
123-
param.alpha0 = 10; %trade-off parameter of l0 part of p and q
120+
param.alpha0 = 1; %trade-off parameter of l0 part of p and q
124121
end
125122

126123
if isfield(param,'alpha1') == 0
127-
param.alpha1 = 1; %trade-off parameter of l1 part of p and q
124+
param.alpha1 = feasTol*100; %trade-off parameter of l1 part of p and q
125+
128126
end
129-
130-
if isfield(param,'epsilon') == 0
131-
param.epsilon = 10e-6; %stopping criterion
127+
128+
if isfield(param,'epsilon') == 0 %stopping criterion
129+
param.epsilon = feasTol*100;
132130
end
133131

134132
if isfield(param,'theta') == 0
@@ -137,7 +135,13 @@
137135
end
138136

139137
if 0
140-
param
138+
param.gamma1 = 0; % caffeine
139+
param.lambda1 = 0; % caffeine
140+
param.alpha1 = 0; % caffeine
141+
end
142+
143+
if param.printLevel>1
144+
disp(param)
141145
end
142146

143147
[nbMaxIteration,epsilon,theta] = deal(param.nbMaxIteration,param.epsilon,param.theta);
@@ -208,7 +212,7 @@
208212
v_bar = -gamma1*sign(v) + sign(v)*gamma0*theta;
209213

210214
r(abs(r) < one_over_theta) = 0;
211-
r_bar = -lamda1*sign(r) + sign(r)*lambda0*theta;
215+
r_bar = -lambda1*sign(r) + sign(r)*lambda0*theta;
212216

213217
p(p < one_over_theta) = 0;
214218
p_bar = alpha1*sign(p) + sign(p)*alpha0*theta;
@@ -253,7 +257,7 @@
253257
if nbIteration==0
254258
fprintf('%5s%12s%12s%12s%12s%10s%10s%10s%10s\n','itn','obj','obj_old','err(obj)','err(x)','card(v)','card(r)','card(p)','card(q)');
255259
end
256-
fprintf('%5u%12.5g%12.5g%12.5g%12.5g%10u%10u%10u%10u\n',nbIteration,obj_new,obj_old,error_obj,error_x,nnz(v),nnz(r),nnz(p),nnz(q));
260+
fprintf('%5u%12.5g%12.5g%12.5g%12.5g%10u%10u%10u%10u\n',nbIteration,obj_new,obj_old,error_obj,error_x,nnz(abs(v)>feasTol),nnz(abs(r)>feasTol),nnz(p>feasTol),nnz(q>feasTol));
257261
end
258262

259263
if (error_x < epsilon) || (error_obj < epsilon)
@@ -283,7 +287,7 @@
283287
if nbIteration==0
284288
fprintf('%5s%12s%12s%12s%12s%10s%10s%10s%10s\n','itn','obj','obj_old','err(obj)','err(x)','card(v)','card(r)','card(p)','card(q)');
285289
end
286-
fprintf('%5u%12.5g%12.5g%12.5g%12.5g%10u%10u%10u%10u\n',nbIteration,obj_new,obj_old,error_obj,error_x,nnz(v),nnz(r),nnz(p),nnz(q));
290+
fprintf('%5u%12.5g%12.5g%12.5g%12.5g%10u%10u%10u%10u\n',nbIteration,obj_new,obj_old,error_obj,error_x,nnz(abs(v)>feasTol),nnz(abs(r)>feasTol),nnz(p>feasTol),nnz(q>feasTol));
287291
end
288292
stop = true;
289293
end

src/analysis/relaxedFBA/relaxedFBA.m

+46-35
Original file line numberDiff line numberDiff line change
@@ -39,48 +39,40 @@
3939
% param: Structure optionally containing the relaxation parameters:
4040
%
4141
% * .internalRelax:
42-
%
4342
% * 0 = do not allow to relax bounds on internal reactions
4443
% * 1 = do not allow to relax bounds on internal reactions with finite bounds
4544
% * {2} = allow to relax bounds on all internal reactions
4645
%
4746
% * .exchangeRelax:
48-
%
4947
% * 0 = do not allow to relax bounds on exchange reactions
5048
% * 1 = do not allow to relax bounds on exchange reactions of the type [0,0]
5149
% * {2} = allow to relax bounds on all exchange reactions
5250
%
5351
% * .steadyStateRelax:
54-
%
5552
% * 0 = do not allow to relax the steady state constraint S*v = b
5653
% * {1} = allow to relax the steady state constraint S*v = b
5754
%
5855
% * .toBeUnblockedReactions - nRxns x 1 vector indicating the reactions to be unblocked
59-
%
6056
% * toBeUnblockedReactions(i) = 1 : impose v(i) to be positive
6157
% * toBeUnblockedReactions(i) = -1 : impose v(i) to be negative
6258
% * toBeUnblockedReactions(i) = 0 : do not add any constraint (default)
6359
%
6460
% * .excludedReactions - nRxns x 1 bool vector indicating the reactions to be excluded from relaxation
65-
%
6661
% * excludedReactions(i) = false : allow to relax bounds on reaction i (default)
6762
% * excludedReactions(i) = true : do not allow to relax bounds on reaction i
6863
%
6964
% * .excludedReactionLB - nRxns x 1 bool vector indicating
7065
% the reactions with lower bounds to be excluded from
7166
% relaxation (overridden by excludedReactions)
72-
%
7367
% * excludedReactionLB(i) = false : allow to relax lower bounds on reaction i (default)
7468
% * excludedReactionLB(i) = true : do not allow to relax lower bounds on reaction i
7569
%
7670
% * .excludedReactionUB - nRxns x 1 bool vector indicating
7771
% the reactions with upper bounds to be excluded from relaxation (overridden by excludedReactions)
78-
%
7972
% * excludedReactionUB(i) = false : allow to relax upper bounds on reaction i (default)
8073
% * excludedReactionUB(i) = true : do not allow to relax upper bounds on reaction i
8174
%
8275
% * .excludedMetabolites - nMets x 1 bool vector indicating the metabolites to be excluded from relaxation
83-
%
8476
% * excludedMetabolites(i) = false : allow to relax steady state constraint on metabolite i (default)
8577
% * excludedMetabolites(i) = true : do not allow to relax steady state constraint on metabolite i
8678
%
@@ -99,9 +91,8 @@
9991
% the algorithm is useful when trying different values
10092
% of theta to start with the appropriate parameter
10193
% giving the lowest cardinality solution.
102-
% * .relaxedPrintLevel (Default = 0) Printing information on relaxed reactions
103-
% * .maxRelaxR (Default = 1e4), maximum relaxation
104-
% of any bound or equality constraint permitted
94+
% * .relaxedPrintLevel (Default = 0) Printing information on relaxed reaction bounds and steady state constraints
95+
% * .maxRelaxR (Default = 1e4), maximum relaxation of any bound or equality constraint permitted
10596
%
10697
% OUTPUT:
10798
% solution: Structure containing the following fields:
@@ -127,6 +118,8 @@
127118
issueConfirmationWarning('relaxedFBA ignores additional variables defined in the model (model field .E)!')
128119
end
129120

121+
feasTol = getCobraSolverParams('LP', 'feasTol');
122+
130123
if ~isfield(model,'S')
131124
%relax generic LP problem ,e.g.
132125
% A: [1663×2942 double]
@@ -159,7 +152,7 @@
159152
param.minLB = min(-max(model.ub),min(model.lb));
160153
end
161154
if ~isfield(param,'maxRelaxR')
162-
param.maxRelaxR = 1e4; %TODO - check this for multiscale models
155+
param.maxRelaxR = 1/feasTol; %TODO - check this for multiscale models
163156
end
164157
if ~isfield(param,'printLevel')
165158
param.printLevel = 0; %TODO - check this for multiscale models
@@ -217,7 +210,7 @@
217210
end
218211
%TODO properly incorporate inf bounds
219212
%add a large finite lower bound here
220-
model.lb(model.lb==-inf) = -1e6;
213+
model.lb(model.lb==-inf) = -1/feasTol;
221214
%use this to override some other assignment
222215
excludedReactionLBTmp=param.excludedReactionLB | model.lb==-inf;
223216

@@ -228,7 +221,7 @@
228221
param.excludedReactionUB = false(nRxns,1);
229222
end
230223
%add a large finite upper bound here
231-
model.ub(model.ub==inf) = 1e6;
224+
model.ub(model.ub==inf) = 1/feasTol;
232225
%use this to override some other assignment
233226
excludedReactionUBTmp=param.excludedReactionUB | model.ub==inf;
234227

@@ -250,8 +243,7 @@
250243
end
251244

252245
if isfield(param,'epsilon') == 0
253-
feasTol = getCobraSolverParams('LP', 'feasTol');
254-
param.epsilon=feasTol*100;
246+
param.epsilon=feasTol;
255247
end
256248

257249
if isfield(param,'theta') == 0
@@ -353,10 +345,10 @@
353345

354346
%set global parameters on zero norm if they do not exist
355347
if ~isfield(param,'alpha') && ~isfield(param,'alpha0')
356-
param.alpha = 10; %weight on relaxation of bounds of reactions
348+
param.alpha = 1; %weight on relaxation of bounds of reactions
357349
end
358350
if ~isfield(param,'lambda') && ~isfield(param,'lambda0')
359-
param.lambda = 10; %weight on relaxation of steady state constraints
351+
param.lambda = 1; %weight on relaxation of steady state constraints
360352
end
361353
if ~isfield(param,'gamma') && ~isfield(param,'gamma0')
362354
%default should not be to aim for zero norm flux vector if the problem is infeasible at the begining
@@ -376,15 +368,14 @@
376368

377369
%set local paramters on one norm for capped L1
378370
if ~isfield(param,'alpha1')
379-
param.alpha1 = param.alpha0/10;
371+
param.alpha1 = feasTol;
380372
end
381373
if ~isfield(param,'lambda1')
382-
param.lambda1 = param.lambda0/10;
374+
param.lambda1 = feasTol;
383375
end
384376
if ~isfield(param,'gamma1')
385-
%always include some regularisation on the flux rates to keep it well
386-
%behaved
387-
param.gamma1 = 1e-6 + param.gamma0/10;
377+
%some regularisation on the flux rates to keep it well behaved
378+
param.gamma1 = feasTol;
388379
end
389380

390381
%Combine excludedReactions with internalRelax and exchangeRelax
@@ -426,6 +417,9 @@
426417
%override
427418
param.excludedMetabolites = param.excludedMetabolites | excludedMetabolitesTmp;
428419

420+
if param.printLevel>0
421+
disp(param)
422+
end
429423

430424
%test if the problem is feasible or not
431425
FBAsolution = optimizeCbModel(model);
@@ -441,17 +435,34 @@
441435
else
442436

443437
%too time consuming
444-
if any(~isfinite(model.S),'all')
445-
[I,J]=find(~isfinite(model.S))
446-
error('model.S has infinite entries')
447-
end
448-
if any(~isfinite(model.b))
449-
[I,J]=find(~isfinite(model.b))
450-
error('model.b has infinite entries')
451-
end
452-
if any(~isfinite(model.c))
453-
[I,J]=find(~isfinite(model.c))
454-
error('model.c has infinite entries')
438+
if isMATLABReleaseOlderThan('R2022a')
439+
if size(model.S,1)*size(model.S,2)<=1e4
440+
if any(~isfinite(model.S),'all')
441+
[I,J]=find(~isfinite(model.S))
442+
error('model.S has non-finite entries')
443+
end
444+
if any(~isfinite(model.b))
445+
[I,J]=find(~isfinite(model.b))
446+
error('model.b has non-finite entries')
447+
end
448+
if any(~isfinite(model.c))
449+
[I,J]=find(~isfinite(model.c))
450+
error('model.c has non-finite entries')
451+
end
452+
end
453+
else
454+
if ~allfinite(model.S)
455+
[I,J]=find(~isfinite(model.S))
456+
error('model.S has non-finite entries')
457+
end
458+
if ~allfinite(model.b)
459+
[I,J]=find(~isfinite(model.b))
460+
error('model.b has non-finite entries')
461+
end
462+
if ~allfinite(model.c)
463+
[I,J]=find(~isfinite(model.c))
464+
error('model.c has non-finite entries')
465+
end
455466
end
456467

457468
solution = relaxFBA_cappedL1(model,param);
@@ -495,7 +506,7 @@
495506
printConstraints(model,-inf,inf, solution.q>=feasTol,relaxedModel, 0);
496507
end
497508
if param.relaxedPrintLevel>0 && any(abs(solution.r)>=feasTol)
498-
fprintf('%s\n','The steady state constraint on this metabolite had to be relaxed:')
509+
fprintf('%s\n','The steady state constraints on these metabolites had to be relaxed:')
499510
disp(model.mets(abs(solution.r)>=feasTol));
500511
end
501512
end

0 commit comments

Comments
 (0)