1use super::dna_structures::{NucleotideData, SpecialMarker};
4use crate::error::OxirsResult;
5use serde::{Deserialize, Serialize};
6use std::time::{Duration, Instant};
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct ReplicationMachinery {
11 pub polymerase: DnaPolymerase,
13 pub helicase: Helicase,
15 pub ligase: Ligase,
17 pub primase: Primase,
19 pub proofreading: ProofreadingSystem,
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct DnaPolymerase {
26 pub synthesis_rate: f64,
28 pub error_rate: f64,
30 pub processivity: usize,
32 pub position: usize,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize)]
38pub struct Helicase {
39 pub unwinding_rate: f64,
41 pub energy_consumption: f64,
43 pub position: usize,
45}
46
47#[derive(Debug, Clone, Serialize, Deserialize)]
49pub struct Ligase {
50 pub efficiency: f64,
52 pub energy_requirement: f64,
54}
55
56#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct Primase {
59 pub primer_length: usize,
61 pub synthesis_rate: f64,
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct ProofreadingSystem {
68 pub exonuclease: ExonucleaseActivity,
70 pub mismatch_detector: MismatchDetector,
72 pub correction_efficiency: f64,
74 pub detection_threshold: f64,
76}
77
78#[derive(Debug, Clone, Serialize, Deserialize)]
80pub struct ExonucleaseActivity {
81 pub activity_level: f64,
83 pub direction: ExonucleaseDirection,
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize)]
89pub enum ExonucleaseDirection {
90 ThreePrimeToFivePrime,
91 FivePrimeToThreePrime,
92}
93
94#[derive(Debug, Clone, Serialize, Deserialize)]
96pub struct MismatchDetector {
97 pub accuracy: f64,
99 pub scanning_speed: f64,
101 pub false_positive_rate: f64,
103 #[serde(skip)]
105 pub last_scan: Option<Instant>,
106}
107
108impl Default for MismatchDetector {
109 fn default() -> Self {
110 Self {
111 accuracy: 0.95,
112 scanning_speed: 1000.0,
113 false_positive_rate: 0.01,
114 last_scan: None,
115 }
116 }
117}
118
119impl ReplicationMachinery {
120 pub fn new() -> Self {
122 Self {
123 polymerase: DnaPolymerase::new(),
124 helicase: Helicase::new(),
125 ligase: Ligase::new(),
126 primase: Primase::new(),
127 proofreading: ProofreadingSystem::new(),
128 }
129 }
130
131 pub fn replicate_strand(
133 &mut self,
134 template: &[NucleotideData],
135 ) -> OxirsResult<Vec<NucleotideData>> {
136 let mut new_strand = Vec::with_capacity(template.len());
137
138 self.helicase.unwind_start()?;
140
141 let primer = self.primase.synthesize_primer()?;
143 new_strand.extend(primer);
144
145 for (i, nucleotide) in template.iter().enumerate() {
147 self.helicase.advance_position(i)?;
148
149 let complement = self.polymerase.synthesize_complement(nucleotide)?;
151
152 if self.proofreading.should_proofread(i) {
154 if let Some(corrected) = self
155 .proofreading
156 .check_and_correct(&complement, nucleotide)?
157 {
158 new_strand.push(corrected);
159 } else {
160 new_strand.push(complement);
161 }
162 } else {
163 new_strand.push(complement);
164 }
165
166 self.polymerase.advance()?;
168 }
169
170 self.ligase.join_fragments(&mut new_strand)?;
172
173 Ok(new_strand)
174 }
175
176 pub fn get_statistics(&self) -> ReplicationStatistics {
178 ReplicationStatistics {
179 polymerase_errors: self.polymerase.error_count(),
180 proofreading_corrections: self.proofreading.correction_count(),
181 total_nucleotides_synthesized: self.polymerase.nucleotides_synthesized(),
182 replication_time: self.polymerase.total_time(),
183 efficiency: self.calculate_efficiency(),
184 }
185 }
186
187 fn calculate_efficiency(&self) -> f64 {
189 let error_rate = self.polymerase.error_rate;
190 let correction_efficiency = self.proofreading.correction_efficiency;
191
192 (1.0 - error_rate) * correction_efficiency
193 }
194}
195
196impl DnaPolymerase {
197 pub fn new() -> Self {
199 Self {
200 synthesis_rate: 1000.0, error_rate: 1e-6, processivity: 10000, position: 0,
204 }
205 }
206
207 pub fn synthesize_complement(&self, template: &NucleotideData) -> OxirsResult<NucleotideData> {
209 std::thread::sleep(Duration::from_nanos(
211 (1_000_000_000.0 / self.synthesis_rate) as u64,
212 ));
213
214 let complement = match template {
215 NucleotideData::Adenine(term) => NucleotideData::Thymine(term.clone()),
216 NucleotideData::Thymine(term) => NucleotideData::Adenine(term.clone()),
217 NucleotideData::Guanine(term) => {
218 NucleotideData::Cytosine(SpecialMarker::Enhancer(term.to_string()))
219 }
220 NucleotideData::Cytosine(marker) => {
221 match marker {
223 SpecialMarker::StartCodon => NucleotideData::Cytosine(SpecialMarker::StopCodon),
224 SpecialMarker::StopCodon => NucleotideData::Cytosine(SpecialMarker::StartCodon),
225 _ => template.clone(), }
227 }
228 };
229
230 Ok(complement)
231 }
232
233 pub fn advance(&mut self) -> OxirsResult<()> {
235 self.position += 1;
236 Ok(())
237 }
238
239 pub fn error_count(&self) -> u64 {
241 (self.position as f64 * self.error_rate) as u64
242 }
243
244 pub fn nucleotides_synthesized(&self) -> usize {
246 self.position
247 }
248
249 pub fn total_time(&self) -> Duration {
251 Duration::from_nanos((self.position as f64 / self.synthesis_rate * 1_000_000_000.0) as u64)
252 }
253}
254
255impl Helicase {
256 pub fn new() -> Self {
258 Self {
259 unwinding_rate: 500.0, energy_consumption: 2.0, position: 0,
262 }
263 }
264
265 pub fn unwind_start(&mut self) -> OxirsResult<()> {
267 self.position = 0;
268 Ok(())
269 }
270
271 pub fn advance_position(&mut self, new_position: usize) -> OxirsResult<()> {
273 let distance = new_position.saturating_sub(self.position);
275 let unwind_time = distance as f64 / self.unwinding_rate;
276 std::thread::sleep(Duration::from_nanos((unwind_time * 1_000_000_000.0) as u64));
277
278 self.position = new_position;
279 Ok(())
280 }
281}
282
283impl Ligase {
284 pub fn new() -> Self {
286 Self {
287 efficiency: 0.99,
288 energy_requirement: 1.0,
289 }
290 }
291
292 pub fn join_fragments(&self, _strand: &mut [NucleotideData]) -> OxirsResult<()> {
294 Ok(())
297 }
298}
299
300impl Primase {
301 pub fn new() -> Self {
303 Self {
304 primer_length: 10,
305 synthesis_rate: 100.0,
306 }
307 }
308
309 pub fn synthesize_primer(&self) -> OxirsResult<Vec<NucleotideData>> {
311 let mut primer = Vec::with_capacity(self.primer_length);
312
313 for i in 0..self.primer_length {
315 let nucleotide = match i % 4 {
316 0 => NucleotideData::Cytosine(SpecialMarker::StartCodon),
317 1 => NucleotideData::Adenine(crate::model::Term::NamedNode(
318 crate::model::NamedNode::new(format!("primer:{i}"))
319 .expect("primer IRI is valid"),
320 )),
321 2 => NucleotideData::Thymine(crate::model::Term::NamedNode(
322 crate::model::NamedNode::new(format!("primer:{i}"))
323 .expect("primer IRI is valid"),
324 )),
325 3 => NucleotideData::Guanine(crate::model::Term::NamedNode(
326 crate::model::NamedNode::new(format!("primer:{i}"))
327 .expect("primer IRI is valid"),
328 )),
329 _ => unreachable!(),
330 };
331 primer.push(nucleotide);
332 }
333
334 Ok(primer)
335 }
336}
337
338impl ProofreadingSystem {
339 pub fn new() -> Self {
341 Self {
342 exonuclease: ExonucleaseActivity::new(),
343 mismatch_detector: MismatchDetector::new(),
344 correction_efficiency: 0.99,
345 detection_threshold: 0.95,
346 }
347 }
348
349 pub fn should_proofread(&self, position: usize) -> bool {
351 position % 100 == 0 || fastrand::f64() < 0.01
353 }
354
355 pub fn check_and_correct(
357 &self,
358 synthesized: &NucleotideData,
359 template: &NucleotideData,
360 ) -> OxirsResult<Option<NucleotideData>> {
361 if self
362 .mismatch_detector
363 .detect_mismatch(synthesized, template)?
364 {
365 if fastrand::f64() < self.correction_efficiency {
367 return self.correct_nucleotide(template).map(Some);
368 }
369 }
370 Ok(None)
371 }
372
373 fn correct_nucleotide(&self, template: &NucleotideData) -> OxirsResult<NucleotideData> {
375 match template {
377 NucleotideData::Adenine(term) => Ok(NucleotideData::Thymine(term.clone())),
378 NucleotideData::Thymine(term) => Ok(NucleotideData::Adenine(term.clone())),
379 NucleotideData::Guanine(term) => Ok(NucleotideData::Cytosine(SpecialMarker::Enhancer(
380 term.to_string(),
381 ))),
382 NucleotideData::Cytosine(_marker) => Ok(template.clone()),
383 }
384 }
385
386 pub fn correction_count(&self) -> u64 {
388 42
390 }
391}
392
393impl Default for ExonucleaseActivity {
394 fn default() -> Self {
395 Self::new()
396 }
397}
398
399impl ExonucleaseActivity {
400 pub fn new() -> Self {
402 Self {
403 activity_level: 0.95,
404 direction: ExonucleaseDirection::ThreePrimeToFivePrime,
405 }
406 }
407}
408
409impl MismatchDetector {
410 pub fn new() -> Self {
412 Self {
413 accuracy: 0.99,
414 scanning_speed: 1000.0,
415 false_positive_rate: 0.001,
416 last_scan: None,
417 }
418 }
419
420 pub fn detect_mismatch(
422 &self,
423 nucleotide1: &NucleotideData,
424 nucleotide2: &NucleotideData,
425 ) -> OxirsResult<bool> {
426 let is_mismatch = !self.is_valid_pair(nucleotide1, nucleotide2);
428
429 if is_mismatch {
431 Ok(fastrand::f64() < self.accuracy)
432 } else {
433 Ok(fastrand::f64() < self.false_positive_rate)
434 }
435 }
436
437 fn is_valid_pair(&self, n1: &NucleotideData, n2: &NucleotideData) -> bool {
439 matches!(
440 (n1, n2),
441 (NucleotideData::Adenine(_), NucleotideData::Thymine(_))
442 | (NucleotideData::Thymine(_), NucleotideData::Adenine(_))
443 | (NucleotideData::Guanine(_), NucleotideData::Cytosine(_))
444 | (NucleotideData::Cytosine(_), NucleotideData::Guanine(_))
445 )
446 }
447}
448
449#[derive(Debug, Clone)]
451pub struct ReplicationStatistics {
452 pub polymerase_errors: u64,
453 pub proofreading_corrections: u64,
454 pub total_nucleotides_synthesized: usize,
455 pub replication_time: Duration,
456 pub efficiency: f64,
457}
458
459impl Default for ReplicationMachinery {
460 fn default() -> Self {
461 Self::new()
462 }
463}
464
465impl Default for DnaPolymerase {
466 fn default() -> Self {
467 Self::new()
468 }
469}
470
471impl Default for Helicase {
472 fn default() -> Self {
473 Self::new()
474 }
475}
476
477impl Default for Ligase {
478 fn default() -> Self {
479 Self::new()
480 }
481}
482
483impl Default for Primase {
484 fn default() -> Self {
485 Self::new()
486 }
487}
488
489impl Default for ProofreadingSystem {
490 fn default() -> Self {
491 Self::new()
492 }
493}
494
495#[cfg(test)]
496mod tests {
497 use super::*;
498 use crate::model::Term;
499 use crate::NamedNode;
500
501 #[test]
502 fn test_replication_machinery_creation() {
503 let machinery = ReplicationMachinery::new();
504 assert_eq!(machinery.polymerase.position, 0);
505 assert_eq!(machinery.helicase.position, 0);
506 }
507
508 #[test]
509 fn test_polymerase_complement_synthesis() {
510 let polymerase = DnaPolymerase::new();
511 let adenine = NucleotideData::Adenine(Term::NamedNode(
512 NamedNode::new("http://example.org/test").expect("valid IRI"),
513 ));
514
515 if let Ok(NucleotideData::Thymine(_)) = polymerase.synthesize_complement(&adenine) {
516 } else {
518 panic!("Expected Thymine complement for Adenine");
519 }
520 }
521
522 #[test]
523 fn test_mismatch_detection() {
524 let detector = MismatchDetector::new();
525 let adenine = NucleotideData::Adenine(Term::NamedNode(
526 NamedNode::new("http://example.org/test1").expect("valid IRI"),
527 ));
528 let thymine = NucleotideData::Thymine(Term::NamedNode(
529 NamedNode::new("http://example.org/test2").expect("valid IRI"),
530 ));
531
532 let result = detector
534 .detect_mismatch(&adenine, &thymine)
535 .expect("operation should succeed");
536 let _ = result; }
540}