use super::dna_structures::{NucleotideData, SpecialMarker};
use crate::error::OxirsResult;
use serde::{Deserialize, Serialize};
use std::time::{Duration, Instant};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReplicationMachinery {
pub polymerase: DnaPolymerase,
pub helicase: Helicase,
pub ligase: Ligase,
pub primase: Primase,
pub proofreading: ProofreadingSystem,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DnaPolymerase {
pub synthesis_rate: f64,
pub error_rate: f64,
pub processivity: usize,
pub position: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Helicase {
pub unwinding_rate: f64,
pub energy_consumption: f64,
pub position: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Ligase {
pub efficiency: f64,
pub energy_requirement: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Primase {
pub primer_length: usize,
pub synthesis_rate: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProofreadingSystem {
pub exonuclease: ExonucleaseActivity,
pub mismatch_detector: MismatchDetector,
pub correction_efficiency: f64,
pub detection_threshold: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExonucleaseActivity {
pub activity_level: f64,
pub direction: ExonucleaseDirection,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ExonucleaseDirection {
ThreePrimeToFivePrime,
FivePrimeToThreePrime,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MismatchDetector {
pub accuracy: f64,
pub scanning_speed: f64,
pub false_positive_rate: f64,
#[serde(skip)]
pub last_scan: Option<Instant>,
}
impl Default for MismatchDetector {
fn default() -> Self {
Self {
accuracy: 0.95,
scanning_speed: 1000.0,
false_positive_rate: 0.01,
last_scan: None,
}
}
}
impl ReplicationMachinery {
pub fn new() -> Self {
Self {
polymerase: DnaPolymerase::new(),
helicase: Helicase::new(),
ligase: Ligase::new(),
primase: Primase::new(),
proofreading: ProofreadingSystem::new(),
}
}
pub fn replicate_strand(
&mut self,
template: &[NucleotideData],
) -> OxirsResult<Vec<NucleotideData>> {
let mut new_strand = Vec::with_capacity(template.len());
self.helicase.unwind_start()?;
let primer = self.primase.synthesize_primer()?;
new_strand.extend(primer);
for (i, nucleotide) in template.iter().enumerate() {
self.helicase.advance_position(i)?;
let complement = self.polymerase.synthesize_complement(nucleotide)?;
if self.proofreading.should_proofread(i) {
if let Some(corrected) = self
.proofreading
.check_and_correct(&complement, nucleotide)?
{
new_strand.push(corrected);
} else {
new_strand.push(complement);
}
} else {
new_strand.push(complement);
}
self.polymerase.advance()?;
}
self.ligase.join_fragments(&mut new_strand)?;
Ok(new_strand)
}
pub fn get_statistics(&self) -> ReplicationStatistics {
ReplicationStatistics {
polymerase_errors: self.polymerase.error_count(),
proofreading_corrections: self.proofreading.correction_count(),
total_nucleotides_synthesized: self.polymerase.nucleotides_synthesized(),
replication_time: self.polymerase.total_time(),
efficiency: self.calculate_efficiency(),
}
}
fn calculate_efficiency(&self) -> f64 {
let error_rate = self.polymerase.error_rate;
let correction_efficiency = self.proofreading.correction_efficiency;
(1.0 - error_rate) * correction_efficiency
}
}
impl DnaPolymerase {
pub fn new() -> Self {
Self {
synthesis_rate: 1000.0, error_rate: 1e-6, processivity: 10000, position: 0,
}
}
pub fn synthesize_complement(&self, template: &NucleotideData) -> OxirsResult<NucleotideData> {
std::thread::sleep(Duration::from_nanos(
(1_000_000_000.0 / self.synthesis_rate) as u64,
));
let complement = match template {
NucleotideData::Adenine(term) => NucleotideData::Thymine(term.clone()),
NucleotideData::Thymine(term) => NucleotideData::Adenine(term.clone()),
NucleotideData::Guanine(term) => {
NucleotideData::Cytosine(SpecialMarker::Enhancer(term.to_string()))
}
NucleotideData::Cytosine(marker) => {
match marker {
SpecialMarker::StartCodon => NucleotideData::Cytosine(SpecialMarker::StopCodon),
SpecialMarker::StopCodon => NucleotideData::Cytosine(SpecialMarker::StartCodon),
_ => template.clone(), }
}
};
Ok(complement)
}
pub fn advance(&mut self) -> OxirsResult<()> {
self.position += 1;
Ok(())
}
pub fn error_count(&self) -> u64 {
(self.position as f64 * self.error_rate) as u64
}
pub fn nucleotides_synthesized(&self) -> usize {
self.position
}
pub fn total_time(&self) -> Duration {
Duration::from_nanos((self.position as f64 / self.synthesis_rate * 1_000_000_000.0) as u64)
}
}
impl Helicase {
pub fn new() -> Self {
Self {
unwinding_rate: 500.0, energy_consumption: 2.0, position: 0,
}
}
pub fn unwind_start(&mut self) -> OxirsResult<()> {
self.position = 0;
Ok(())
}
pub fn advance_position(&mut self, new_position: usize) -> OxirsResult<()> {
let distance = new_position.saturating_sub(self.position);
let unwind_time = distance as f64 / self.unwinding_rate;
std::thread::sleep(Duration::from_nanos((unwind_time * 1_000_000_000.0) as u64));
self.position = new_position;
Ok(())
}
}
impl Ligase {
pub fn new() -> Self {
Self {
efficiency: 0.99,
energy_requirement: 1.0,
}
}
pub fn join_fragments(&self, _strand: &mut [NucleotideData]) -> OxirsResult<()> {
Ok(())
}
}
impl Primase {
pub fn new() -> Self {
Self {
primer_length: 10,
synthesis_rate: 100.0,
}
}
pub fn synthesize_primer(&self) -> OxirsResult<Vec<NucleotideData>> {
let mut primer = Vec::with_capacity(self.primer_length);
for i in 0..self.primer_length {
let nucleotide = match i % 4 {
0 => NucleotideData::Cytosine(SpecialMarker::StartCodon),
1 => NucleotideData::Adenine(crate::model::Term::NamedNode(
crate::model::NamedNode::new(format!("primer:{i}"))
.expect("primer IRI is valid"),
)),
2 => NucleotideData::Thymine(crate::model::Term::NamedNode(
crate::model::NamedNode::new(format!("primer:{i}"))
.expect("primer IRI is valid"),
)),
3 => NucleotideData::Guanine(crate::model::Term::NamedNode(
crate::model::NamedNode::new(format!("primer:{i}"))
.expect("primer IRI is valid"),
)),
_ => unreachable!(),
};
primer.push(nucleotide);
}
Ok(primer)
}
}
impl ProofreadingSystem {
pub fn new() -> Self {
Self {
exonuclease: ExonucleaseActivity::new(),
mismatch_detector: MismatchDetector::new(),
correction_efficiency: 0.99,
detection_threshold: 0.95,
}
}
pub fn should_proofread(&self, position: usize) -> bool {
position % 100 == 0 || fastrand::f64() < 0.01
}
pub fn check_and_correct(
&self,
synthesized: &NucleotideData,
template: &NucleotideData,
) -> OxirsResult<Option<NucleotideData>> {
if self
.mismatch_detector
.detect_mismatch(synthesized, template)?
{
if fastrand::f64() < self.correction_efficiency {
return self.correct_nucleotide(template).map(Some);
}
}
Ok(None)
}
fn correct_nucleotide(&self, template: &NucleotideData) -> OxirsResult<NucleotideData> {
match template {
NucleotideData::Adenine(term) => Ok(NucleotideData::Thymine(term.clone())),
NucleotideData::Thymine(term) => Ok(NucleotideData::Adenine(term.clone())),
NucleotideData::Guanine(term) => Ok(NucleotideData::Cytosine(SpecialMarker::Enhancer(
term.to_string(),
))),
NucleotideData::Cytosine(_marker) => Ok(template.clone()),
}
}
pub fn correction_count(&self) -> u64 {
42
}
}
impl Default for ExonucleaseActivity {
fn default() -> Self {
Self::new()
}
}
impl ExonucleaseActivity {
pub fn new() -> Self {
Self {
activity_level: 0.95,
direction: ExonucleaseDirection::ThreePrimeToFivePrime,
}
}
}
impl MismatchDetector {
pub fn new() -> Self {
Self {
accuracy: 0.99,
scanning_speed: 1000.0,
false_positive_rate: 0.001,
last_scan: None,
}
}
pub fn detect_mismatch(
&self,
nucleotide1: &NucleotideData,
nucleotide2: &NucleotideData,
) -> OxirsResult<bool> {
let is_mismatch = !self.is_valid_pair(nucleotide1, nucleotide2);
if is_mismatch {
Ok(fastrand::f64() < self.accuracy)
} else {
Ok(fastrand::f64() < self.false_positive_rate)
}
}
fn is_valid_pair(&self, n1: &NucleotideData, n2: &NucleotideData) -> bool {
matches!(
(n1, n2),
(NucleotideData::Adenine(_), NucleotideData::Thymine(_))
| (NucleotideData::Thymine(_), NucleotideData::Adenine(_))
| (NucleotideData::Guanine(_), NucleotideData::Cytosine(_))
| (NucleotideData::Cytosine(_), NucleotideData::Guanine(_))
)
}
}
#[derive(Debug, Clone)]
pub struct ReplicationStatistics {
pub polymerase_errors: u64,
pub proofreading_corrections: u64,
pub total_nucleotides_synthesized: usize,
pub replication_time: Duration,
pub efficiency: f64,
}
impl Default for ReplicationMachinery {
fn default() -> Self {
Self::new()
}
}
impl Default for DnaPolymerase {
fn default() -> Self {
Self::new()
}
}
impl Default for Helicase {
fn default() -> Self {
Self::new()
}
}
impl Default for Ligase {
fn default() -> Self {
Self::new()
}
}
impl Default for Primase {
fn default() -> Self {
Self::new()
}
}
impl Default for ProofreadingSystem {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::model::Term;
use crate::NamedNode;
#[test]
fn test_replication_machinery_creation() {
let machinery = ReplicationMachinery::new();
assert_eq!(machinery.polymerase.position, 0);
assert_eq!(machinery.helicase.position, 0);
}
#[test]
fn test_polymerase_complement_synthesis() {
let polymerase = DnaPolymerase::new();
let adenine = NucleotideData::Adenine(Term::NamedNode(
NamedNode::new("http://example.org/test").expect("valid IRI"),
));
if let Ok(NucleotideData::Thymine(_)) = polymerase.synthesize_complement(&adenine) {
} else {
panic!("Expected Thymine complement for Adenine");
}
}
#[test]
fn test_mismatch_detection() {
let detector = MismatchDetector::new();
let adenine = NucleotideData::Adenine(Term::NamedNode(
NamedNode::new("http://example.org/test1").expect("valid IRI"),
));
let thymine = NucleotideData::Thymine(Term::NamedNode(
NamedNode::new("http://example.org/test2").expect("valid IRI"),
));
let result = detector
.detect_mismatch(&adenine, &thymine)
.expect("operation should succeed");
let _ = result; }
}