1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
use crate::model::ModelLp;
use good_lp::{
solvers::ObjectiveDirection, solvers::StaticSolver, ProblemVariables, Solution, Solver,
SolverModel,
};
use std::collections::HashMap;
use std::sync::mpsc::channel;
use std::thread;
type SolverError<S> = <<S as Solver>::Model as good_lp::SolverModel>::Error;
pub fn fba<S: Solver>(
model: &mut ModelLp,
solver: S,
) -> Result<HashMap<String, f64>, SolverError<S>> {
_fva_step(model, solver, ObjectiveDirection::Maximisation)
}
fn _fva_step<S: Solver>(
model: &mut ModelLp,
solver: S,
direction: ObjectiveDirection,
) -> Result<HashMap<String, f64>, SolverError<S>> {
let mut problem = ProblemVariables::new();
model.populate_model(&mut problem);
let mut problem = problem
.optimise(direction, model.get_objective())
.using(solver);
model.add_constraints::<S>(&mut problem);
let solution = problem.solve()?;
Ok(model
.variables
.iter()
.map(|(id, var)| (id.clone(), solution.value(*var)))
.collect())
}
pub fn fva<S>(
model: &mut ModelLp,
solver: S,
reactions: &[String],
) -> Result<HashMap<String, (f64, f64)>, Box<dyn std::error::Error>>
where
S: StaticSolver + Clone + Send + Sync,
{
let original_solution = fba(model, solver.clone())?;
let fix_to = original_solution[&model.objective];
let objective = model.get_objective_reaction()?;
objective.lb = fix_to;
objective.ub = fix_to;
let cpus = num_cpus::get();
let (tx, rx) = channel();
let reacs_per_job = reactions.len() / num_cpus::get();
for i in 0..cpus {
let mut model = model.clone();
let tx = tx.clone();
let solver = solver.clone();
let (lower, mut upper) = (i * reacs_per_job, reacs_per_job * (i + 1));
if (cpus - 1) == i {
upper = reactions.len()
}
let reactions = reactions[lower..upper].to_vec();
thread::spawn(move || {
for reaction in reactions {
model.objective = reaction.clone();
let upper_value = match fba(&mut model, solver.clone()) {
Ok(sol) => sol[&model.objective],
_ => std::f64::NAN,
};
let lower_value =
match _fva_step(&mut model, solver.clone(), ObjectiveDirection::Minimisation) {
Ok(sol) => sol[&model.objective],
_ => std::f64::NAN,
};
tx.send((reaction.clone(), (lower_value, upper_value)))
.expect("Could not send data!");
}
});
}
let mut result = HashMap::new();
for _ in 0..(reactions.len()) {
let (reac_id, bounds) = rx.recv()?;
result.insert(reac_id, bounds);
}
Ok(result)
}