-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhybrid.py
More file actions
71 lines (56 loc) · 2.45 KB
/
Copy pathhybrid.py
File metadata and controls
71 lines (56 loc) · 2.45 KB
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
# === hybrid.py ===
from __future__ import annotations
import logging
import random
from typing import TYPE_CHECKING
from genmethod import GenMethod
if TYPE_CHECKING:
from sequence import Sequence
logger = logging.getLogger(__name__)
class Hybrid(GenMethod):
"""
Generates a child sequence by combining fragments from two parent sequences.
Both parents are split at a crossover point and the leading fragment of
seq1 is joined with the trailing fragment of seq2. When the parents have
equal length the child length is preserved. When the parents differ in
length the crossover point is determined by a relative position (fraction
of each sequence), so the proportional structure of both parents is
respected and the child length can vary between calls.
The crossover fraction is drawn uniformly from (0, 1) on each call,
excluding the endpoints to ensure that both parents always contribute
at least one residue to the child.
Parameters
----------
None. All shared resources are accessed through self.generator when
needed. This method does not require the amino acid pool.
"""
method_name: str = 'HYBRID'
expected_parents: int = 2
def generate(self, seq1: Sequence, seq2: Sequence, verbose=False) -> str:
s1 = str(seq1)
s2 = str(seq2)
len1 = len(s1)
len2 = len(s2)
# Draw a crossover fraction strictly between 0 and 1 so that both
# parents always contribute at least one residue.
fraction = random.uniform(0.0, 1.0)
# Map the fraction to an absolute cut index in each parent.
# round() is used so that the cut index scales proportionally with
# sequence length. Clamping ensures the index stays within bounds
# even after rounding at the extremes.
cut1 = max(1, min(round(fraction * len1), len1 - 1))
cut2 = max(1, min(round(fraction * len2), len2 - 1))
child = s1[:cut1] + s2[cut2:]
if verbose:
ornament = int((30 - len(self.method_name))/2)
print(f"{'-' * ornament} {self.method_name} {'-' * ornament}")
print(f"Fraction={fraction:.3f}")
print(f"{s1} <- Parent 1")
print(f"{s2} <- Parent 2")
print(f"{s1[:cut1]}{' '*len(s2[cut2:])}")
print(f"{' '*len(s1[:cut1])}{s2[cut2:]}")
print(f"{child} <- Child")
print(f"{'-' * 30}")
return child
if __name__ == '__main__':
pass