use regex::Regex;
use std::collections::HashSet;
#[warn(unused_variables)]
#[warn(unused_mut)]
fn clean_off_artifacts( item: &mut String) -> &mut String {
let items_to_clean = [" (", "(", "M)", "M)"];
if item.contains( "M)") || item.contains("M)") || item.contains(" (") || item.contains("(") {
*item = item.replace("M)", "").replace("M)", "").replace(" (", "").replace("(", "");
return item
} else {item}
}
pub fn analyse_substances(half_reaction: &str) -> (Vec<String>, Vec<f64>, Vec<f64>) {
let mut s_list = Vec::new();
let mut g_list = Vec::new();
let mut subs:Vec<String> = Vec::new();
let re_coeff = Regex::new(r"(\d+(\.\d*)?)\*?").unwrap();
let re_power = Regex::new(r"\^\ *(\d+(\.\d*)?)").unwrap();
for s in half_reaction.split('+') {
let mut s = s.trim();
print!("half reaction is: {:#?} ",s);
let mut stec_coeff = 1.0;
let mut power_coeff = 1.0;
let end_of_stoichiometric: usize = 0;
if let Some(captures) = re_coeff.captures(s) {
let regmatch = captures.get(0).unwrap();
print!(" regmatch: {:?} ", regmatch);
let start_of_stoichiometric = regmatch.start();
let end_of_stoichiometric = regmatch.end();
if start_of_stoichiometric==0{
s = &s[end_of_stoichiometric..];
stec_coeff = captures.get(1).unwrap().as_str().parse().unwrap();
print!(" stec_coeff: {} ", &stec_coeff);
}
}
if let Some(captures) = re_power.captures(s) {
power_coeff = captures.get(1).unwrap().as_str().parse().unwrap();
let end = captures.get(0).unwrap().end();
}
else{
power_coeff==stec_coeff;
}
s = s.trim();
let s_to_filter: &mut String = &mut s.to_string();
let s_filtered = clean_off_artifacts(s_to_filter);
let s: String = s_filtered.to_string();
s_list.push(stec_coeff);
g_list.push(power_coeff);
subs.push(s);
}
(subs, s_list, g_list)
}
fn clean_off_DUP( item: &mut String) -> &String {
if item.ends_with("_dup") || item.ends_with("_DUP") {
*item = item.replace("_dup", "").replace("_DUP", "");
return item
} else {item}
}
#[derive(Debug)]
pub struct ReactionAnalyzer {
pub reactions: Vec<String>, pub substances: Vec<String>, pub stecheo_matrx: Vec<Vec<f64>>, pub stecheo_reags: Vec<Vec<f64>>, pub stecheo_prods: Vec<Vec<f64>>, pub G_matrix_reag: Vec<Vec<f64>>,
pub G_matrix_prod: Vec<Vec<f64>>,
}
impl ReactionAnalyzer {
pub fn new() -> Self {
ReactionAnalyzer {
reactions: Vec::new(),
substances: Vec::new(),
stecheo_matrx: Vec::new(),
stecheo_reags: Vec::new(),
stecheo_prods: Vec::new(),
G_matrix_reag: Vec::new(),
G_matrix_prod: Vec::new(),
}
}
pub fn analyse_reactions(&mut self) {
let reactions_trimmed = self.reactions.iter().map(|s| s.replace("**", "^").trim().to_string()).collect();
self.reactions = reactions_trimmed;
self.stecheo_matrx.resize(self.reactions.len(), vec![0.0; self.substances.len()]);
self.stecheo_reags.resize(self.reactions.len(), vec![0.0; self.substances.len()]);
self.stecheo_prods.resize(self.reactions.len(), vec![0.0; self.substances.len()]);
self.G_matrix_reag.resize(self.reactions.len(), vec![0.0; self.substances.len()]);
self.G_matrix_prod.resize(self.reactions.len(), vec![0.0; self.substances.len()]);
for mut reaction in &self.reactions {
if let Some(i) = self.reactions.iter().position(|s| s == reaction){
println!("reaction number: {}", i);
let mut reaction_: &mut String = &mut reaction.to_string();
reaction = clean_off_DUP( reaction_);
println!("Reaction after dup: {}", &reaction);
let re = Regex::new(r"=|->|=>").unwrap();
let sides: Vec<String> = re.split(reaction) .map(|s| s.trim())
.map(|s| s.to_string())
.collect();
let mut subs = Vec::new();
let mut subs_r = Vec::new();
let mut s_list = Vec::new();
let mut g_list = Vec::new();
let mut s_list_r = Vec::new();
let mut g_list_r: Vec<f64> = Vec::new();
println!("direct reaction {:?}", &sides[0]);
let (mut left_subs, mut left_s_list, mut left_g_list) = analyse_substances( &sides[0]);
let mut left_subs = left_subs.iter().map(|s| s.as_str()).collect();
subs.append(&mut left_subs);
s_list.append(&mut left_s_list);
g_list.append(&mut left_g_list);
println!("direct reaction substances: {:?}", subs);
println!("iterating over substances in direct reaction");
println!("lengh of substance list found in reaction {}", &subs.len());
for j in 0..subs.len() {
let subs_j = subs[j];
if let Some(k) = self.substances.iter().position(|s| s == subs_j) {
println!("Index of substance '{}' in list of substanced of this react is: {}, in general list is {},
lengh of gen. list is {}", subs_j, j, k, &self.substances.len());
self.stecheo_matrx[i][k] -= s_list[j];
self.stecheo_reags[i][k] = s_list[j];
self.G_matrix_reag[i][k] = g_list[j];
} else {
println!("'{}' not found in the vector", subs_j);
}
}
println!("reverse reaction {:?}", &sides[1]);
let (mut right_subs, mut right_s_list, mut right_g_list) = analyse_substances( &sides[1]);
let mut right_subs = right_subs.iter().map(|s| s.as_str()).collect();
subs_r.append(&mut right_subs);
s_list_r.append(&mut right_s_list);
g_list_r.append(&mut right_g_list);
println!("reverse reaction substances: {:?}", subs_r);
println!("iterating over substances in reverse reaction");
println!("lengh of substance list found in reaction {}", &subs.len());
for j in 0..subs_r.len() {
let subs_j = subs_r[j];
if let Some(k) = self.substances.iter().position(|s| s == subs_j) {
println!("Index of substance '{}' in list of substanced of this react is: {}, in general list is {},
lengh of gen. list is {}", subs_j, j, k, &self.substances.len());
self.stecheo_matrx[i][k] += s_list_r[j];
self.stecheo_prods[i][k] = s_list_r[j];
self.G_matrix_prod[i][k] = g_list_r[j];
} else {
println!("'{}' not found in the vector", subs_j);
}
}
}
} }
pub fn search_substances(&mut self) {
let reactions_trimmed = self.reactions.iter().map(|s| s.replace("**", "^").trim().to_string()).collect();
self.reactions = reactions_trimmed;
let mut found_substances:Vec<String> = Vec::new();
for mut reaction in &mut self.reactions {
println!("Reaction: {}", reaction);
let reaction = clean_off_DUP(reaction);
let re = Regex::new(r"=|->|=>").unwrap();
let sides: Vec<&str> = re.split(reaction).map(|s| s).collect();
println!("Sides: {:?}", &sides);
for side in sides {
let (subs, _, _) = analyse_substances( &side);
let subs_mut = &mut subs.clone();
subs_mut.retain(|s|!found_substances.contains(s)); found_substances.extend(subs_mut.to_owned());
}
self.substances = found_substances.iter().map(|s| s.to_string()).collect();
println!("Substances found: {:?}", &self.substances);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_analyse_substances() {
let half_reaction = "5H2O + 10O2";
let (subs, s_list, g_list) = analyse_substances(half_reaction);
assert_eq!(subs, vec!["5H2O".to_string(), "10O2".to_string()]);
assert_eq!(s_list, vec![5.0, 10.0]);
assert_eq!(g_list, vec![1.0, 1.0]);
}
#[test]
fn test_clean_off_artifacts() {
let mut item = "A=2BM)".to_string();
let cleaned_item = clean_off_artifacts(&mut item);
assert_eq!(cleaned_item, "A=2B");
let mut item = "B->A + 3C_DUP".to_string();
let cleaned_item = clean_off_artifacts(&mut item);
assert_eq!(cleaned_item, "B->A + 3C");
}
#[test]
fn test_search_substances() {
let mut ReactionAnalyzer_instance = ReactionAnalyzer::new();
let reactions_: Vec<&str> = vec!["A=2BM)", "B->A + 3C_DUP"];
let reaction = reactions_.iter().map(|s| s.to_string()).collect();
ReactionAnalyzer_instance.reactions = reaction;
ReactionAnalyzer_instance.search_substances();
assert_eq!(ReactionAnalyzer_instance.substances, vec!["A".to_string(), "B".to_string(), "C".to_string()]);
}
}