phylogenie 2.0.14__py3-none-any.whl → 2.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- phylogenie/__init__.py +22 -7
- phylogenie/generators/__init__.py +0 -8
- phylogenie/generators/configs.py +11 -12
- phylogenie/generators/dataset.py +10 -7
- phylogenie/generators/factories.py +9 -0
- phylogenie/generators/trees.py +88 -61
- phylogenie/io.py +27 -12
- phylogenie/tree.py +38 -12
- phylogenie/treesimulator/__init__.py +18 -1
- phylogenie/treesimulator/events/__init__.py +39 -0
- phylogenie/treesimulator/events/contact_tracing.py +125 -0
- phylogenie/treesimulator/{events.py → events/core.py} +73 -125
- phylogenie/treesimulator/events/mutations.py +105 -0
- phylogenie/treesimulator/gillespie.py +77 -40
- phylogenie/treesimulator/model.py +57 -56
- phylogenie/typings.py +0 -1
- phylogenie/utils.py +17 -0
- {phylogenie-2.0.14.dist-info → phylogenie-2.1.1.dist-info}/METADATA +1 -2
- phylogenie-2.1.1.dist-info/RECORD +32 -0
- phylogenie-2.0.14.dist-info/RECORD +0 -28
- {phylogenie-2.0.14.dist-info → phylogenie-2.1.1.dist-info}/LICENSE.txt +0 -0
- {phylogenie-2.0.14.dist-info → phylogenie-2.1.1.dist-info}/WHEEL +0 -0
- {phylogenie-2.0.14.dist-info → phylogenie-2.1.1.dist-info}/entry_points.txt +0 -0
|
@@ -1,86 +1,123 @@
|
|
|
1
|
+
import os
|
|
1
2
|
from collections.abc import Sequence
|
|
2
3
|
|
|
4
|
+
import joblib
|
|
3
5
|
import numpy as np
|
|
4
6
|
from numpy.random import default_rng
|
|
7
|
+
from tqdm import tqdm
|
|
5
8
|
|
|
6
|
-
from phylogenie.
|
|
9
|
+
from phylogenie.io import dump_newick
|
|
7
10
|
from phylogenie.tree import Tree
|
|
8
|
-
from phylogenie.treesimulator.
|
|
9
|
-
|
|
11
|
+
from phylogenie.treesimulator.model import Event, Model
|
|
12
|
+
|
|
13
|
+
MAX_TIPS = 2**32
|
|
10
14
|
|
|
11
15
|
|
|
12
16
|
def simulate_tree(
|
|
13
17
|
events: Sequence[Event],
|
|
14
18
|
min_tips: int = 1,
|
|
15
|
-
max_tips: int
|
|
19
|
+
max_tips: int = MAX_TIPS,
|
|
16
20
|
max_time: float = np.inf,
|
|
17
21
|
init_state: str | None = None,
|
|
18
22
|
sampling_probability_at_present: float = 0.0,
|
|
19
|
-
notification_probability: float = 0,
|
|
20
|
-
max_notified_contacts: int = 1,
|
|
21
|
-
samplable_states_after_notification: Sequence[str] | None = None,
|
|
22
|
-
sampling_rate_after_notification: SkylineParameterLike = np.inf,
|
|
23
|
-
contacts_removal_probability: SkylineParameterLike = 1,
|
|
24
|
-
max_tries: int | None = None,
|
|
25
23
|
seed: int | None = None,
|
|
26
24
|
) -> Tree | None:
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if max_tips is None and max_time == np.inf:
|
|
30
|
-
raise ValueError("Either max_tips or max_time must be specified.")
|
|
25
|
+
if max_time == np.inf and max_tips == MAX_TIPS:
|
|
26
|
+
raise ValueError("Either max_time or max_tips must be specified.")
|
|
31
27
|
|
|
32
|
-
|
|
28
|
+
if max_time == np.inf and sampling_probability_at_present:
|
|
29
|
+
raise ValueError(
|
|
30
|
+
"sampling_probability_at_present cannot be set when max_time is infinite."
|
|
31
|
+
)
|
|
33
32
|
|
|
34
|
-
if
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
sampling_rate_after_notification,
|
|
39
|
-
contacts_removal_probability,
|
|
33
|
+
states = {e.state for e in events if e.state}
|
|
34
|
+
if init_state is None and len(states) > 1:
|
|
35
|
+
raise ValueError(
|
|
36
|
+
"Init state must be provided for models with more than one state."
|
|
40
37
|
)
|
|
38
|
+
elif init_state is None:
|
|
39
|
+
(init_state,) = states
|
|
40
|
+
elif init_state not in states:
|
|
41
|
+
raise ValueError(f"Init state {init_state} not found in event states: {states}")
|
|
41
42
|
|
|
42
|
-
|
|
43
|
-
while
|
|
44
|
-
|
|
45
|
-
model = Model(root_state, max_notified_contacts, notification_probability, rng)
|
|
43
|
+
rng = default_rng(seed)
|
|
44
|
+
while True:
|
|
45
|
+
model = Model(init_state, events)
|
|
46
46
|
current_time = 0.0
|
|
47
47
|
change_times = sorted(set(t for e in events for t in e.rate.change_times))
|
|
48
48
|
next_change_time = change_times.pop(0) if change_times else np.inf
|
|
49
|
-
n_tips = None if max_tips is None else rng.integers(min_tips, max_tips + 1)
|
|
50
49
|
|
|
51
|
-
|
|
50
|
+
target_n_tips = rng.integers(min_tips, max_tips) if max_time == np.inf else None
|
|
51
|
+
while current_time < max_time:
|
|
52
|
+
events = model.events
|
|
52
53
|
rates = [e.get_propensity(model, current_time) for e in events]
|
|
53
54
|
|
|
54
55
|
instantaneous_events = [e for e, r in zip(events, rates) if r == np.inf]
|
|
55
56
|
if instantaneous_events:
|
|
56
57
|
event = instantaneous_events[rng.integers(len(instantaneous_events))]
|
|
57
|
-
event.apply(model, current_time)
|
|
58
|
+
event.apply(model, current_time, rng)
|
|
58
59
|
continue
|
|
59
60
|
|
|
60
|
-
if
|
|
61
|
+
if (
|
|
62
|
+
not any(rates)
|
|
63
|
+
or model.n_sampled > max_tips
|
|
64
|
+
or target_n_tips is not None
|
|
65
|
+
and model.n_sampled >= target_n_tips
|
|
66
|
+
):
|
|
61
67
|
break
|
|
62
68
|
|
|
63
69
|
time_step = rng.exponential(1 / sum(rates))
|
|
70
|
+
if current_time + time_step >= next_change_time:
|
|
71
|
+
current_time = next_change_time
|
|
72
|
+
next_change_time = change_times.pop(0) if change_times else np.inf
|
|
73
|
+
continue
|
|
64
74
|
if current_time + time_step >= max_time:
|
|
65
75
|
current_time = max_time
|
|
66
76
|
break
|
|
67
77
|
current_time += time_step
|
|
68
78
|
|
|
69
|
-
if current_time >= next_change_time:
|
|
70
|
-
current_time = next_change_time
|
|
71
|
-
next_change_time = change_times.pop(0) if change_times else np.inf
|
|
72
|
-
continue
|
|
73
|
-
|
|
74
79
|
event_idx = np.searchsorted(np.cumsum(rates) / sum(rates), rng.random())
|
|
75
|
-
events[int(event_idx)].apply(model, current_time)
|
|
80
|
+
events[int(event_idx)].apply(model, current_time, rng)
|
|
76
81
|
|
|
77
82
|
for individual in model.get_population():
|
|
78
83
|
if rng.random() < sampling_probability_at_present:
|
|
79
|
-
model.sample(individual, current_time,
|
|
84
|
+
model.sample(individual, current_time, True)
|
|
80
85
|
|
|
81
|
-
if model.n_sampled
|
|
82
|
-
max_tips is None or model.n_sampled <= max_tips
|
|
83
|
-
):
|
|
86
|
+
if min_tips <= model.n_sampled <= max_tips:
|
|
84
87
|
return model.get_sampled_tree()
|
|
85
88
|
|
|
86
|
-
|
|
89
|
+
|
|
90
|
+
def generate_trees(
|
|
91
|
+
output_dir: str,
|
|
92
|
+
n_trees: int,
|
|
93
|
+
events: list[Event],
|
|
94
|
+
min_tips: int = 1,
|
|
95
|
+
max_tips: int = 2**32,
|
|
96
|
+
max_time: float = np.inf,
|
|
97
|
+
init_state: str | None = None,
|
|
98
|
+
sampling_probability_at_present: float = 0.0,
|
|
99
|
+
seed: int | None = None,
|
|
100
|
+
n_jobs: int = -1,
|
|
101
|
+
) -> None:
|
|
102
|
+
if os.path.exists(output_dir):
|
|
103
|
+
raise FileExistsError(f"Output directory {output_dir} already exists")
|
|
104
|
+
os.mkdir(output_dir)
|
|
105
|
+
|
|
106
|
+
rng = default_rng(seed)
|
|
107
|
+
jobs = joblib.Parallel(n_jobs=n_jobs, return_as="generator_unordered")(
|
|
108
|
+
joblib.delayed(simulate_tree)(
|
|
109
|
+
events=events,
|
|
110
|
+
min_tips=min_tips,
|
|
111
|
+
max_tips=max_tips,
|
|
112
|
+
max_time=max_time,
|
|
113
|
+
init_state=init_state,
|
|
114
|
+
sampling_probability_at_present=sampling_probability_at_present,
|
|
115
|
+
seed=int(rng.integers(2**32)),
|
|
116
|
+
)
|
|
117
|
+
for _ in range(n_trees)
|
|
118
|
+
)
|
|
119
|
+
for i, tree in tqdm(
|
|
120
|
+
enumerate(jobs), total=n_trees, desc=f"Generating trees in {output_dir}..."
|
|
121
|
+
):
|
|
122
|
+
if tree is not None:
|
|
123
|
+
dump_newick(tree, os.path.join(output_dir, f"{i}.nwk"))
|
|
@@ -1,62 +1,74 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
1
2
|
from collections import defaultdict
|
|
2
|
-
from
|
|
3
|
-
from
|
|
3
|
+
from collections.abc import Sequence
|
|
4
|
+
from copy import deepcopy
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import Any
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
import numpy as np
|
|
9
|
+
from numpy.random import Generator
|
|
6
10
|
|
|
11
|
+
from phylogenie.skyline import SkylineParameterLike, skyline_parameter
|
|
7
12
|
from phylogenie.tree import Tree
|
|
8
13
|
|
|
9
|
-
CT_POSTFIX = "-CT"
|
|
10
14
|
|
|
15
|
+
class Event(ABC):
|
|
16
|
+
def __init__(self, state: str, rate: SkylineParameterLike):
|
|
17
|
+
self.state = state
|
|
18
|
+
self.rate = skyline_parameter(rate)
|
|
11
19
|
|
|
12
|
-
def
|
|
13
|
-
|
|
20
|
+
def draw_individual(self, model: "Model", rng: Generator) -> int:
|
|
21
|
+
return rng.choice(model.get_population(self.state))
|
|
14
22
|
|
|
23
|
+
def get_propensity(self, model: "Model", time: float) -> float:
|
|
24
|
+
n_individuals = model.count_individuals(self.state)
|
|
25
|
+
rate = self.rate.get_value_at_time(time)
|
|
26
|
+
if rate == np.inf and not n_individuals:
|
|
27
|
+
return 0
|
|
28
|
+
return rate * n_individuals
|
|
15
29
|
|
|
16
|
-
|
|
17
|
-
|
|
30
|
+
@abstractmethod
|
|
31
|
+
def apply(self, model: "Model", time: float, rng: Generator) -> None: ...
|
|
18
32
|
|
|
19
33
|
|
|
20
34
|
@dataclass
|
|
21
35
|
class Individual:
|
|
36
|
+
id: int
|
|
22
37
|
node: Tree
|
|
23
38
|
state: str
|
|
24
|
-
id: int = field(init=False)
|
|
25
|
-
_id_counter: ClassVar[int] = 0
|
|
26
|
-
|
|
27
|
-
def __post_init__(self):
|
|
28
|
-
Individual._id_counter += 1
|
|
29
|
-
self.id = Individual._id_counter
|
|
30
39
|
|
|
31
40
|
|
|
32
41
|
class Model:
|
|
33
|
-
def __init__(
|
|
34
|
-
self,
|
|
35
|
-
init_state: str,
|
|
36
|
-
max_notified_contacts: int = 1,
|
|
37
|
-
notification_probability: float = 0,
|
|
38
|
-
rng: int | Generator | None = None,
|
|
39
|
-
):
|
|
42
|
+
def __init__(self, init_state: str, events: Sequence[Event]):
|
|
40
43
|
self._next_node_id = 0
|
|
44
|
+
self._next_individual_id = 0
|
|
41
45
|
self._population: dict[int, Individual] = {}
|
|
42
46
|
self._states: dict[str, set[int]] = defaultdict(set)
|
|
43
|
-
self._contacts: dict[int, list[Individual]] = defaultdict(list)
|
|
44
47
|
self._sampled: set[str] = set()
|
|
45
48
|
self._tree = self._get_new_individual(init_state).node
|
|
46
|
-
self.
|
|
47
|
-
self.
|
|
48
|
-
self._rng = rng if isinstance(rng, Generator) else default_rng(rng)
|
|
49
|
+
self._events = list(events)
|
|
50
|
+
self.context: dict[str, Any] = {}
|
|
49
51
|
|
|
50
52
|
@property
|
|
51
53
|
def n_sampled(self) -> int:
|
|
52
54
|
return len(self._sampled)
|
|
53
55
|
|
|
56
|
+
@property
|
|
57
|
+
def events(self) -> tuple[Event, ...]:
|
|
58
|
+
return tuple(self._events)
|
|
59
|
+
|
|
60
|
+
def add_event(self, event: Event) -> None:
|
|
61
|
+
self._events.append(event)
|
|
62
|
+
|
|
54
63
|
def _get_new_node(self, state: str) -> Tree:
|
|
55
64
|
self._next_node_id += 1
|
|
56
65
|
return Tree(f"{self._next_node_id}|{state}")
|
|
57
66
|
|
|
58
67
|
def _get_new_individual(self, state: str) -> Individual:
|
|
59
|
-
|
|
68
|
+
self._next_individual_id += 1
|
|
69
|
+
individual = Individual(
|
|
70
|
+
self._next_individual_id, self._get_new_node(state), state
|
|
71
|
+
)
|
|
60
72
|
self._population[individual.id] = individual
|
|
61
73
|
self._states[state].add(individual.id)
|
|
62
74
|
return individual
|
|
@@ -77,9 +89,8 @@ class Model:
|
|
|
77
89
|
def remove(self, id: int, time: float) -> None:
|
|
78
90
|
individual = self._population[id]
|
|
79
91
|
self._set_branch_length(individual.node, time)
|
|
80
|
-
state = individual.state
|
|
81
92
|
self._population.pop(id)
|
|
82
|
-
self._states[state].remove(id)
|
|
93
|
+
self._states[individual.state].remove(id)
|
|
83
94
|
|
|
84
95
|
def migrate(self, id: int, state: str, time: float) -> None:
|
|
85
96
|
individual = self._population[id]
|
|
@@ -88,17 +99,16 @@ class Model:
|
|
|
88
99
|
self._states[state].add(id)
|
|
89
100
|
self._stem(individual, time)
|
|
90
101
|
|
|
91
|
-
def birth_from(self, id: int, state: str, time: float) ->
|
|
102
|
+
def birth_from(self, id: int, state: str, time: float) -> int:
|
|
92
103
|
individual = self._population[id]
|
|
93
104
|
new_individual = self._get_new_individual(state)
|
|
94
105
|
individual.node.add_child(new_individual.node)
|
|
95
106
|
self._stem(individual, time)
|
|
96
|
-
|
|
97
|
-
self._contacts[new_individual.id].append(individual)
|
|
107
|
+
return new_individual.id
|
|
98
108
|
|
|
99
|
-
def sample(self, id: int, time: float,
|
|
109
|
+
def sample(self, id: int, time: float, removal: bool) -> None:
|
|
100
110
|
individual = self._population[id]
|
|
101
|
-
if
|
|
111
|
+
if removal:
|
|
102
112
|
self._sampled.add(individual.node.id)
|
|
103
113
|
self.remove(id, time)
|
|
104
114
|
else:
|
|
@@ -108,47 +118,38 @@ class Model:
|
|
|
108
118
|
individual.node.add_child(sample_node)
|
|
109
119
|
self._stem(individual, time)
|
|
110
120
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
contact.id in self._population
|
|
114
|
-
and not is_CT_state(contact.state)
|
|
115
|
-
and self._rng.random() < self._notification_probability
|
|
116
|
-
):
|
|
117
|
-
self.migrate(contact.id, get_CT_state(contact.state), time)
|
|
121
|
+
def get_state(self, id: int) -> str:
|
|
122
|
+
return self._population[id].state
|
|
118
123
|
|
|
119
124
|
def get_sampled_tree(self) -> Tree:
|
|
120
|
-
tree = self._tree
|
|
125
|
+
tree = deepcopy(self._tree)
|
|
121
126
|
for node in list(tree.postorder_traversal()):
|
|
122
127
|
if node.id not in self._sampled and not node.children:
|
|
123
128
|
if node.parent is None:
|
|
124
129
|
raise ValueError("No samples in the tree.")
|
|
125
130
|
else:
|
|
126
|
-
node.parent.
|
|
131
|
+
node.parent.remove_child(node)
|
|
127
132
|
elif len(node.children) == 1:
|
|
128
133
|
(child,) = node.children
|
|
129
|
-
child.
|
|
134
|
+
child.set_parent(node.parent)
|
|
130
135
|
assert child.branch_length is not None
|
|
131
136
|
assert node.branch_length is not None
|
|
132
137
|
child.branch_length += node.branch_length
|
|
133
138
|
if node.parent is None:
|
|
134
139
|
return child
|
|
135
140
|
else:
|
|
136
|
-
node.parent.
|
|
137
|
-
node.parent.children.remove(node)
|
|
141
|
+
node.parent.remove_child(node)
|
|
138
142
|
return tree
|
|
139
143
|
|
|
140
144
|
def get_full_tree(self) -> Tree:
|
|
141
|
-
return self._tree
|
|
142
|
-
|
|
143
|
-
def get_random_individual(self, state: str | None = None) -> int:
|
|
144
|
-
if state is None:
|
|
145
|
-
return self._rng.choice(list(self._population))
|
|
146
|
-
return self._rng.choice(list(self._states[state]))
|
|
145
|
+
return deepcopy(self._tree)
|
|
147
146
|
|
|
148
|
-
def get_population(self) -> list[int]:
|
|
149
|
-
|
|
147
|
+
def get_population(self, states: str | None = None) -> list[int]:
|
|
148
|
+
if states is None:
|
|
149
|
+
return list(self._population)
|
|
150
|
+
return list(self._states[states])
|
|
150
151
|
|
|
151
|
-
def count_individuals(self,
|
|
152
|
-
if
|
|
152
|
+
def count_individuals(self, states: str | None = None) -> int:
|
|
153
|
+
if states is None:
|
|
153
154
|
return len(self._population)
|
|
154
|
-
return len(self._states[
|
|
155
|
+
return len(self._states[states])
|
phylogenie/typings.py
CHANGED
phylogenie/utils.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, ConfigDict
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class StrictBaseModel(BaseModel):
|
|
7
|
+
model_config = ConfigDict(extra="forbid")
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Distribution(BaseModel):
|
|
11
|
+
type: str
|
|
12
|
+
model_config = ConfigDict(extra="allow")
|
|
13
|
+
|
|
14
|
+
@property
|
|
15
|
+
def args(self) -> dict[str, Any]:
|
|
16
|
+
assert self.model_extra is not None
|
|
17
|
+
return self.model_extra
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: phylogenie
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.1.1
|
|
4
4
|
Summary: Generate phylogenetic datasets with minimal setup effort
|
|
5
5
|
Author: Gabriele Marino
|
|
6
6
|
Author-email: gabmarino.8601@gmail.com
|
|
@@ -24,7 +24,6 @@ Description-Content-Type: text/markdown
|
|
|
24
24
|
|
|
25
25
|
[](https://iqtree.github.io/doc/AliSim)
|
|
26
26
|
[](https://pypi.org/project/phylogenie/)
|
|
27
|
-
[](https://pypi.org/project/phylogenie/)
|
|
28
27
|
|
|
29
28
|
Phylogenie is a [Python](https://www.python.org/) package designed to easily simulate phylogenetic datasets—such as trees and multiple sequence alignments (MSAs)—with minimal setup effort. Simply specify the distributions from which your parameters should be sampled, and Phylogenie will handle the rest!
|
|
30
29
|
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
phylogenie/__init__.py,sha256=T2mRLsYtoLlWt8GlxrrUnfXJ9XVioq7hTvVq3uJpwQI,2215
|
|
2
|
+
phylogenie/generators/__init__.py,sha256=zsOxy28-9j9alOQLIgrOAFfmM58NNHO_NEtW-KXQXAY,888
|
|
3
|
+
phylogenie/generators/alisim.py,sha256=dDqlSwLDbRE2u5SZlsq1mArobTBtuk0aeXY3m1N-bWA,2374
|
|
4
|
+
phylogenie/generators/configs.py,sha256=AiiFS6rpH9BPwDKCkT4SVrRzfLFFrwRCJM4CRj0Srdk,1072
|
|
5
|
+
phylogenie/generators/dataset.py,sha256=wYtb5fxjrM0bD9KVDlgZPpiR4ACezdKKfsmsXyc4__0,2755
|
|
6
|
+
phylogenie/generators/factories.py,sha256=14p1wvJtjdXgM4mPqV9vX34HYcKpemx9TPfemvoB5Wo,7265
|
|
7
|
+
phylogenie/generators/trees.py,sha256=EEj5KPuu7FSOoti_gGTmgWgiX68rEKFh57Hp6BDw8po,10049
|
|
8
|
+
phylogenie/generators/typeguards.py,sha256=yj4VkhOaUXJ2OrY-6zhOeY9C4yKIQxjZtk2d-vIxttQ,828
|
|
9
|
+
phylogenie/io.py,sha256=y7nQIvLgCvqELsXFKfm1GgKJO_saoQ-7zQpE3Kvajzc,3509
|
|
10
|
+
phylogenie/main.py,sha256=vtvSpQxBNlYABoFQ25czl-l3fIr4QRo3svWVd-jcArw,1170
|
|
11
|
+
phylogenie/msa.py,sha256=JDGyZUsAq6-m-SQjoCDjAkAZIxfgyl_PDIhdYn5HOow,2064
|
|
12
|
+
phylogenie/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
+
phylogenie/skyline/__init__.py,sha256=7pF4CUb4ZCLzNYJNhOjpuTOLTRhlK7L6ugfccNqjIGo,620
|
|
14
|
+
phylogenie/skyline/matrix.py,sha256=Gl8OgKjtieG0NwPYiPimKI36gefV8fm_OeorjdXxPTs,9146
|
|
15
|
+
phylogenie/skyline/parameter.py,sha256=EM9qlPt0JhMBy3TbztM0dj24BaGNEy8KWKdTObDKhbI,4644
|
|
16
|
+
phylogenie/skyline/vector.py,sha256=bJP7_FNX_Klt6wXqsyfj0KX3VNj6-dIhzCKSJuQcOV0,7115
|
|
17
|
+
phylogenie/tree.py,sha256=fmCLDNIls3VjY413b-khzj-2jlaQ9rJo7AFN1cz4zXk,2411
|
|
18
|
+
phylogenie/treesimulator/__init__.py,sha256=XG_xwETKWgDmCihqNUFCcMHtFg4WvZu5qbqWn9Dndt8,879
|
|
19
|
+
phylogenie/treesimulator/events/__init__.py,sha256=UGfvXOVJ_ZAkk_8sBPihjmxciiaEnXZEPFIY53sttWI,940
|
|
20
|
+
phylogenie/treesimulator/events/contact_tracing.py,sha256=_nJ85yhgGkeruQgMHvGpDYoyhheBf8M4LgZWiWdi5dY,4801
|
|
21
|
+
phylogenie/treesimulator/events/core.py,sha256=JokGmieAv2xEX7KsjBWZr05jHN1jB-XZbpxe9gwdbDA,7953
|
|
22
|
+
phylogenie/treesimulator/events/mutations.py,sha256=xkXUIppbLIWZqKwVf-hi7d-_pS42TG2EPVfJA_grxBg,3443
|
|
23
|
+
phylogenie/treesimulator/gillespie.py,sha256=TMDNKBkFwVyAEhBlbwxCTA61GuGwP-42HxpsAVXiU0s,4275
|
|
24
|
+
phylogenie/treesimulator/model.py,sha256=bWoFiO-99tTjHtueKPvGV9RSHQKYJ625XP1dvYbP1_Q,5454
|
|
25
|
+
phylogenie/typeguards.py,sha256=JtqmbEWJZBRHbWgCvcl6nrWm3VcBfzRbklbTBYHItn0,1325
|
|
26
|
+
phylogenie/typings.py,sha256=GknvAFXyiaWeeYJ8Lk5d6E2VHT-xW6ONEojYbtJYiB8,476
|
|
27
|
+
phylogenie/utils.py,sha256=pCg9ob0RpLUHwM49x4knKxL4FNPr3-EU_6zMXsvxtAg,370
|
|
28
|
+
phylogenie-2.1.1.dist-info/LICENSE.txt,sha256=NUrDqElK-eD3I0WqC004CJsy6cs0JgsAoebDv_42-pw,1071
|
|
29
|
+
phylogenie-2.1.1.dist-info/METADATA,sha256=Ay--Y2G4F1KwK9GgJFhtiTwGyKJ815JUCLYbXMyek1o,5375
|
|
30
|
+
phylogenie-2.1.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
31
|
+
phylogenie-2.1.1.dist-info/entry_points.txt,sha256=Rt6_usN0FkBX1ZfiqCirjMN9FKOgFLG8rydcQ8kugeE,51
|
|
32
|
+
phylogenie-2.1.1.dist-info/RECORD,,
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
phylogenie/__init__.py,sha256=4BytT42_M1K6T3W9eqHQCrKc6g0Lh5LTQxP8dGIJTsk,1915
|
|
2
|
-
phylogenie/generators/__init__.py,sha256=VCpuvmOoY_N6p1h_Q0peYgGIIUIFLsvZT3T7vbHG6w0,1090
|
|
3
|
-
phylogenie/generators/alisim.py,sha256=dDqlSwLDbRE2u5SZlsq1mArobTBtuk0aeXY3m1N-bWA,2374
|
|
4
|
-
phylogenie/generators/configs.py,sha256=4jSBUZiFo2GacXWed5dy7lUEkaOWZkZG-KY9vHfhqGU,993
|
|
5
|
-
phylogenie/generators/dataset.py,sha256=hbkN5McM4BKY7D0hLNaxdoAGsLHac6O-D4sgnZ0wFX4,2618
|
|
6
|
-
phylogenie/generators/factories.py,sha256=0ckeAsKnPy69Vbdoi1rIyf6zRcqamz9VfSi0mAiTzds,6938
|
|
7
|
-
phylogenie/generators/trees.py,sha256=jukaVXGcPGzDBEYMGJ1MKqWt4XbAB5EEfuHXDpwKTqM,9173
|
|
8
|
-
phylogenie/generators/typeguards.py,sha256=yj4VkhOaUXJ2OrY-6zhOeY9C4yKIQxjZtk2d-vIxttQ,828
|
|
9
|
-
phylogenie/io.py,sha256=ZXlofnSh7FX5UJiP0svRHrTraMSNgKa1GiAv0bMz7jU,2854
|
|
10
|
-
phylogenie/main.py,sha256=vtvSpQxBNlYABoFQ25czl-l3fIr4QRo3svWVd-jcArw,1170
|
|
11
|
-
phylogenie/msa.py,sha256=JDGyZUsAq6-m-SQjoCDjAkAZIxfgyl_PDIhdYn5HOow,2064
|
|
12
|
-
phylogenie/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
-
phylogenie/skyline/__init__.py,sha256=7pF4CUb4ZCLzNYJNhOjpuTOLTRhlK7L6ugfccNqjIGo,620
|
|
14
|
-
phylogenie/skyline/matrix.py,sha256=Gl8OgKjtieG0NwPYiPimKI36gefV8fm_OeorjdXxPTs,9146
|
|
15
|
-
phylogenie/skyline/parameter.py,sha256=EM9qlPt0JhMBy3TbztM0dj24BaGNEy8KWKdTObDKhbI,4644
|
|
16
|
-
phylogenie/skyline/vector.py,sha256=bJP7_FNX_Klt6wXqsyfj0KX3VNj6-dIhzCKSJuQcOV0,7115
|
|
17
|
-
phylogenie/tree.py,sha256=dk8Sj1tqyGOunVO2crtIqb0LH-ws-PXqA8SuNcYfVHI,1738
|
|
18
|
-
phylogenie/treesimulator/__init__.py,sha256=INPU9LrPdUmt3dYGzWDRoRKrPR9xENcHu44pJVUbyNA,525
|
|
19
|
-
phylogenie/treesimulator/events.py,sha256=X3_0U9qqMpYgh6-7TwQEnlUipANkHz6QTCXlm-qXFQk,9524
|
|
20
|
-
phylogenie/treesimulator/gillespie.py,sha256=NHiBLVlpKdcTPohMr6ehywbPeB8gnn6erEv2bkgvf4c,3268
|
|
21
|
-
phylogenie/treesimulator/model.py,sha256=XpzAicmg2O6K0Trk5YolH-B_HJZxoSauF2wZOMqp-Iw,5559
|
|
22
|
-
phylogenie/typeguards.py,sha256=JtqmbEWJZBRHbWgCvcl6nrWm3VcBfzRbklbTBYHItn0,1325
|
|
23
|
-
phylogenie/typings.py,sha256=O1X6lGKTjJ2YJz3ApQ-rYb_tEJNUIcHdUIeYlSM4s5o,500
|
|
24
|
-
phylogenie-2.0.14.dist-info/LICENSE.txt,sha256=NUrDqElK-eD3I0WqC004CJsy6cs0JgsAoebDv_42-pw,1071
|
|
25
|
-
phylogenie-2.0.14.dist-info/METADATA,sha256=NXOQmoUHSTA2AjrXjt4VKSaM2KO6H2rBF7nrRuGK2f4,5473
|
|
26
|
-
phylogenie-2.0.14.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
27
|
-
phylogenie-2.0.14.dist-info/entry_points.txt,sha256=Rt6_usN0FkBX1ZfiqCirjMN9FKOgFLG8rydcQ8kugeE,51
|
|
28
|
-
phylogenie-2.0.14.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|