use chiral_common::{OperatorOutput, Operator, OperatorReport};
use chiral_operator::fingerprint::ob_similarity::{Input, Output, Report};
pub struct Data {
dsk: chiral_common::kinds::Dataset,
ids: Vec<chiral_common::DatasetID>,
fps: Vec<chiral_common::FPData>
}
impl From<(&chiral_common::kinds::Fingerprint, &chiral_common::kinds::Dataset, &chiral_data::DocSMILES)> for Data {
fn from((fpk, dsk_in, doc): (&chiral_common::kinds::Fingerprint, &chiral_common::kinds::Dataset, &chiral_data::DocSMILES)) -> Self {
let fpk_ob = super::to_ob_fp_kind(fpk);
let fpg = openbabel::fingerprint::FingerprintGenerator::new(fpk_ob);
let fps = fpg.get_fingerprint_for_smiles_vec(doc.get_smiles_vec());
let ids = doc.get_ids().to_vec();
Self { dsk: dsk_in.to_owned(), ids, fps }
}
}
impl chiral_common::OperatorData for Data {
fn len(&self) -> usize {
self.ids.len()
}
}
pub struct OpenBabelSimilaritySearching {
fpk: chiral_common::kinds::Fingerprint,
fpg: openbabel::fingerprint::FingerprintGenerator,
}
impl From<chiral_common::kinds::Fingerprint> for OpenBabelSimilaritySearching {
fn from(fpk: chiral_common::kinds::Fingerprint) -> Self {
let fpk_ob = super::to_ob_fp_kind(&fpk);
let fpg = openbabel::fingerprint::FingerprintGenerator::new(fpk_ob);
Self { fpk, fpg }
}
}
impl chiral_common::Operator for OpenBabelSimilaritySearching {
type InputType = Input;
type DataType = Data;
type OutputType = Output;
type ReportType = Report;
fn compute(&self, input: &Self::InputType, data: &Self::DataType) -> Self::OutputType {
let mol = openbabel::molecule::Molecule::new_from_smiles(&input.smiles);
let fp_target = self.fpg.get_fingerprint(&mol);
let results = data.fps.iter()
.map(|fp| super::similarity_tanimoto(fp, &fp_target))
.zip(data.ids.iter())
.filter(|(coeff, _)| *coeff > input.threshold)
.map(|(mr, id)| (mr, id.to_string()))
.collect();
Output { results }
}
fn report(&self, input: Self::InputType, data: &Self::DataType, output: Self::OutputType) -> Self::ReportType {
Report {
input,
fpk: self.fpk.to_owned(),
dsk: data.dsk.to_owned(),
output
}
}
}
pub struct OpenBabelSimilaritySearchingUnit {
op: OpenBabelSimilaritySearching,
data: Data,
output: Output
}
impl From<(&chiral_common::kinds::Fingerprint, &chiral_common::kinds::Dataset, &chiral_data::DocSMILES)> for OpenBabelSimilaritySearchingUnit {
fn from((fpk, dsk, doc): (&chiral_common::kinds::Fingerprint, &chiral_common::kinds::Dataset, &chiral_data::DocSMILES)) -> Self {
let op = OpenBabelSimilaritySearching::from(fpk.to_owned());
let data = Data::from((fpk, dsk, doc));
Self { op, data, output: Output::blank() }
}
}
impl chiral_common::ComputingUnit for OpenBabelSimilaritySearchingUnit {
fn compute(&mut self, serialized_input: &chiral_common::SerializedFormat) {
self.output.clear();
let input = Input::deserialize(serialized_input);
self.output = self.op.compute(&input, &self.data);
}
fn report(&self, serialized_input: &chiral_common::SerializedFormat) -> chiral_common::SerializedFormat {
let input = Input::deserialize(serialized_input);
self.op.report(input, &self.data, self.output.to_owned()).serialize()
}
fn output_len(&self) -> usize {
self.output.len()
}
}
#[cfg(test)]
mod tests {
use super::*;
use chiral_common::{Operator, OperatorData, OperatorOutput, OperatorReport, ComputingUnit};
use chiral_data::Dummy;
#[test]
fn test_op() {
let dsk = chiral_common::kinds::Dataset::Dummy;
let doc_smiles = chiral_data::DocSMILES::dummy();
let com_fpk = chiral_common::kinds::Fingerprint::kind_openbabel_ecfp4(2048);
let op = OpenBabelSimilaritySearching::from(com_fpk.to_owned());
let data = Data::from((&com_fpk, &dsk, &doc_smiles));
assert_eq!(data.len(), 4);
let input = Input { smiles: String::from("c1ccccc1"), threshold: 0.045 };
let output = op.compute(&input, &data);
assert_eq!(output.len(), 2);
let report = op.report(input, &data, output);
let serialized_report = OperatorReport::serialize(&report);
let report_deserialized: Report = OperatorReport::deserialize(&serialized_report);
assert_eq!(report_deserialized.fpk, com_fpk);
assert_eq!(report_deserialized.dsk, dsk);
assert_eq!(report_deserialized.output.len(), 2);
}
#[test]
fn test_cu() {
let dsk = chiral_common::kinds::Dataset::Dummy;
let doc_smiles = chiral_data::DocSMILES::dummy();
let fpk = chiral_common::kinds::Fingerprint::kind_openbabel_ecfp4(2048);
let mut cu = OpenBabelSimilaritySearchingUnit::from((&fpk, &dsk, &doc_smiles));
let input = Input { smiles: String::from("c1ccccc1"), threshold: 0.045 };
cu.compute(&input.serialize());
assert_eq!(cu.output_len(), 2);
}
}