phylogenie 1.0.0__py3-none-any.whl → 1.0.2__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/backend/remaster/generate.py +5 -5
- phylogenie/backend/remaster/reactions.py +23 -23
- phylogenie/backend/treesimulator.py +6 -6
- phylogenie/core/configs.py +17 -12
- phylogenie/core/context/factories.py +5 -8
- phylogenie/core/dataset.py +6 -6
- phylogenie/core/factories.py +146 -69
- phylogenie/core/msas/alisim.py +2 -2
- phylogenie/core/msas/base.py +3 -3
- phylogenie/core/trees/remaster/configs.py +3 -3
- phylogenie/core/trees/remaster/factories.py +8 -12
- phylogenie/core/trees/remaster/generator.py +57 -47
- phylogenie/core/trees/treesimulator.py +18 -16
- phylogenie/core/typeguards.py +12 -20
- phylogenie/skyline/__init__.py +14 -4
- phylogenie/skyline/matrix.py +45 -55
- phylogenie/skyline/parameter.py +29 -20
- phylogenie/skyline/vector.py +42 -51
- phylogenie/typeguards.py +10 -8
- phylogenie/typings.py +8 -7
- phylogenie-1.0.2.dist-info/LICENSE.txt +22 -0
- phylogenie-1.0.2.dist-info/METADATA +120 -0
- phylogenie-1.0.2.dist-info/RECORD +39 -0
- phylogenie/core/typings.py +0 -10
- phylogenie/utils.py +0 -20
- phylogenie-1.0.0.dist-info/METADATA +0 -31
- phylogenie-1.0.0.dist-info/RECORD +0 -40
- {phylogenie-1.0.0.dist-info → phylogenie-1.0.2.dist-info}/WHEEL +0 -0
- {phylogenie-1.0.0.dist-info → phylogenie-1.0.2.dist-info}/entry_points.txt +0 -0
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
import phylogenie.core.trees.remaster.configs as cfg
|
|
2
|
+
import phylogenie.typings as pgt
|
|
2
3
|
from phylogenie.backend.remaster import PunctualReaction, Reaction
|
|
3
4
|
from phylogenie.core.factories import (
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
many_ints_factory,
|
|
6
|
+
many_scalars_factory,
|
|
6
7
|
skyline_parameter_like_factory,
|
|
7
8
|
)
|
|
8
|
-
from phylogenie.core.typings import Data
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
def reaction_factory(
|
|
12
|
-
x: cfg.ReactionConfig,
|
|
13
|
-
data: Data,
|
|
14
|
-
) -> Reaction:
|
|
11
|
+
def reaction_factory(x: cfg.ReactionConfig, data: pgt.Data) -> Reaction:
|
|
15
12
|
return Reaction(
|
|
16
13
|
rate=skyline_parameter_like_factory(x.rate, data),
|
|
17
14
|
value=x.value,
|
|
@@ -19,12 +16,11 @@ def reaction_factory(
|
|
|
19
16
|
|
|
20
17
|
|
|
21
18
|
def punctual_reaction_factory(
|
|
22
|
-
x: cfg.PunctualReactionConfig,
|
|
23
|
-
data: Data,
|
|
19
|
+
x: cfg.PunctualReactionConfig, data: pgt.Data
|
|
24
20
|
) -> PunctualReaction:
|
|
25
21
|
return PunctualReaction(
|
|
26
|
-
times=
|
|
22
|
+
times=many_scalars_factory(x.times, data),
|
|
27
23
|
value=x.value,
|
|
28
|
-
p=None if x.p is None else
|
|
29
|
-
n=None if x.n is None else
|
|
24
|
+
p=None if x.p is None else many_scalars_factory(x.p, data),
|
|
25
|
+
n=None if x.n is None else many_ints_factory(x.n, data),
|
|
30
26
|
)
|
|
@@ -6,6 +6,7 @@ from numpy.random import Generator
|
|
|
6
6
|
from pydantic import Field
|
|
7
7
|
|
|
8
8
|
import phylogenie.core.configs as cfg
|
|
9
|
+
import phylogenie.typings as pgt
|
|
9
10
|
from phylogenie.backend.remaster import (
|
|
10
11
|
DEFAULT_POPULATION,
|
|
11
12
|
SAMPLE_POPULATION,
|
|
@@ -16,8 +17,8 @@ from phylogenie.backend.remaster import (
|
|
|
16
17
|
get_FBD_reactions,
|
|
17
18
|
)
|
|
18
19
|
from phylogenie.core.factories import (
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
skyline_matrix_coercible_factory,
|
|
21
|
+
skyline_vector_coercible_factory,
|
|
21
22
|
)
|
|
22
23
|
from phylogenie.core.trees.base import BackendType, TreesGenerator
|
|
23
24
|
from phylogenie.core.trees.remaster.configs import (
|
|
@@ -28,7 +29,6 @@ from phylogenie.core.trees.remaster.factories import (
|
|
|
28
29
|
punctual_reaction_factory,
|
|
29
30
|
reaction_factory,
|
|
30
31
|
)
|
|
31
|
-
from phylogenie.core.typings import Data
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
class ParameterizationType(str, Enum):
|
|
@@ -39,6 +39,7 @@ class ParameterizationType(str, Enum):
|
|
|
39
39
|
|
|
40
40
|
class ReMASTERGenerator(TreesGenerator):
|
|
41
41
|
backend: Literal[BackendType.REMASTER] = BackendType.REMASTER
|
|
42
|
+
beast_path: str = "beast"
|
|
42
43
|
populations: str | list[str] = DEFAULT_POPULATION
|
|
43
44
|
init_population: str = DEFAULT_POPULATION
|
|
44
45
|
sample_population: str = SAMPLE_POPULATION
|
|
@@ -47,7 +48,7 @@ class ReMASTERGenerator(TreesGenerator):
|
|
|
47
48
|
trajectory_attrs: dict[str, str | int | float] = Field(default_factory=dict)
|
|
48
49
|
|
|
49
50
|
def _generate_one_from_extra_reactions(
|
|
50
|
-
self, filename: str, rng: Generator, data: Data, reactions: list[Reaction]
|
|
51
|
+
self, filename: str, rng: Generator, data: pgt.Data, reactions: list[Reaction]
|
|
51
52
|
) -> None:
|
|
52
53
|
generate_trees(
|
|
53
54
|
tree_file_name=f"{filename}.nwk",
|
|
@@ -63,9 +64,10 @@ class ReMASTERGenerator(TreesGenerator):
|
|
|
63
64
|
for k, v in self.trajectory_attrs.items()
|
|
64
65
|
},
|
|
65
66
|
seed=int(rng.integers(0, 2**31 - 1)),
|
|
67
|
+
beast_path=self.beast_path,
|
|
66
68
|
)
|
|
67
69
|
|
|
68
|
-
def _generate_one(self, filename: str, rng: Generator, data: Data) -> None:
|
|
70
|
+
def _generate_one(self, filename: str, rng: Generator, data: pgt.Data) -> None:
|
|
69
71
|
self._generate_one_from_extra_reactions(filename, rng, data, reactions=[])
|
|
70
72
|
|
|
71
73
|
|
|
@@ -73,25 +75,27 @@ class CanonicalReMASTERGenerator(ReMASTERGenerator):
|
|
|
73
75
|
parameterization: Literal[ParameterizationType.CANONICAL] = (
|
|
74
76
|
ParameterizationType.CANONICAL
|
|
75
77
|
)
|
|
76
|
-
birth_rates: cfg.
|
|
77
|
-
death_rates: cfg.
|
|
78
|
-
sampling_rates: cfg.
|
|
79
|
-
removal_probabilities: cfg.
|
|
80
|
-
migration_rates: cfg.
|
|
81
|
-
birth_rates_among_demes: cfg.
|
|
82
|
-
|
|
83
|
-
def _generate_one(self, filename: str, rng: Generator, data: Data) -> None:
|
|
78
|
+
birth_rates: cfg.SkylineVectorCoercibleConfig = 0
|
|
79
|
+
death_rates: cfg.SkylineVectorCoercibleConfig = 0
|
|
80
|
+
sampling_rates: cfg.SkylineVectorCoercibleConfig = 0
|
|
81
|
+
removal_probabilities: cfg.SkylineVectorCoercibleConfig = 0
|
|
82
|
+
migration_rates: cfg.SkylineMatrixCoercibleConfig = 0
|
|
83
|
+
birth_rates_among_demes: cfg.SkylineMatrixCoercibleConfig = 0
|
|
84
|
+
|
|
85
|
+
def _generate_one(self, filename: str, rng: Generator, data: pgt.Data) -> None:
|
|
84
86
|
reactions = get_canonical_reactions(
|
|
85
87
|
populations=self.populations,
|
|
86
88
|
sample_population=self.sample_population,
|
|
87
|
-
birth_rates=
|
|
88
|
-
death_rates=
|
|
89
|
-
sampling_rates=
|
|
90
|
-
removal_probabilities=
|
|
89
|
+
birth_rates=skyline_vector_coercible_factory(self.birth_rates, data),
|
|
90
|
+
death_rates=skyline_vector_coercible_factory(self.death_rates, data),
|
|
91
|
+
sampling_rates=skyline_vector_coercible_factory(self.sampling_rates, data),
|
|
92
|
+
removal_probabilities=skyline_vector_coercible_factory(
|
|
91
93
|
self.removal_probabilities, data
|
|
92
94
|
),
|
|
93
|
-
migration_rates=
|
|
94
|
-
|
|
95
|
+
migration_rates=skyline_matrix_coercible_factory(
|
|
96
|
+
self.migration_rates, data
|
|
97
|
+
),
|
|
98
|
+
birth_rates_among_demes=skyline_matrix_coercible_factory(
|
|
95
99
|
self.birth_rates_among_demes, data
|
|
96
100
|
),
|
|
97
101
|
)
|
|
@@ -102,31 +106,33 @@ class EpidemiologicalReMASTERGenerator(ReMASTERGenerator):
|
|
|
102
106
|
parameterization: Literal[ParameterizationType.EPIDEMIOLOGICAL] = (
|
|
103
107
|
ParameterizationType.EPIDEMIOLOGICAL
|
|
104
108
|
)
|
|
105
|
-
reproduction_numbers: cfg.
|
|
106
|
-
become_uninfectious_rates: cfg.
|
|
107
|
-
sampling_proportions: cfg.
|
|
108
|
-
removal_probabilities: cfg.
|
|
109
|
-
migration_rates: cfg.
|
|
110
|
-
reproduction_numbers_among_demes: cfg.
|
|
111
|
-
|
|
112
|
-
def _generate_one(self, filename: str, rng: Generator, data: Data) -> None:
|
|
109
|
+
reproduction_numbers: cfg.SkylineVectorCoercibleConfig = 0
|
|
110
|
+
become_uninfectious_rates: cfg.SkylineVectorCoercibleConfig = 0
|
|
111
|
+
sampling_proportions: cfg.SkylineVectorCoercibleConfig = 0
|
|
112
|
+
removal_probabilities: cfg.SkylineVectorCoercibleConfig = 0
|
|
113
|
+
migration_rates: cfg.SkylineMatrixCoercibleConfig = 0
|
|
114
|
+
reproduction_numbers_among_demes: cfg.SkylineMatrixCoercibleConfig = 0
|
|
115
|
+
|
|
116
|
+
def _generate_one(self, filename: str, rng: Generator, data: pgt.Data) -> None:
|
|
113
117
|
reactions = get_epidemiological_reactions(
|
|
114
118
|
populations=self.populations,
|
|
115
119
|
sample_population=self.sample_population,
|
|
116
|
-
reproduction_numbers=
|
|
120
|
+
reproduction_numbers=skyline_vector_coercible_factory(
|
|
117
121
|
self.reproduction_numbers, data
|
|
118
122
|
),
|
|
119
|
-
become_uninfectious_rates=
|
|
123
|
+
become_uninfectious_rates=skyline_vector_coercible_factory(
|
|
120
124
|
self.become_uninfectious_rates, data
|
|
121
125
|
),
|
|
122
|
-
sampling_proportions=
|
|
126
|
+
sampling_proportions=skyline_vector_coercible_factory(
|
|
123
127
|
self.sampling_proportions, data
|
|
124
128
|
),
|
|
125
|
-
removal_probabilities=
|
|
129
|
+
removal_probabilities=skyline_vector_coercible_factory(
|
|
126
130
|
self.removal_probabilities, data
|
|
127
131
|
),
|
|
128
|
-
migration_rates=
|
|
129
|
-
|
|
132
|
+
migration_rates=skyline_matrix_coercible_factory(
|
|
133
|
+
self.migration_rates, data
|
|
134
|
+
),
|
|
135
|
+
reproduction_numbers_among_demes=skyline_matrix_coercible_factory(
|
|
130
136
|
self.reproduction_numbers_among_demes, data
|
|
131
137
|
),
|
|
132
138
|
)
|
|
@@ -135,27 +141,31 @@ class EpidemiologicalReMASTERGenerator(ReMASTERGenerator):
|
|
|
135
141
|
|
|
136
142
|
class FBDReMASTERGenerator(ReMASTERGenerator):
|
|
137
143
|
parameterization: Literal[ParameterizationType.FBD] = ParameterizationType.FBD
|
|
138
|
-
diversification: cfg.
|
|
139
|
-
turnover: cfg.
|
|
140
|
-
sampling_proportions: cfg.
|
|
141
|
-
removal_probabilities: cfg.
|
|
142
|
-
migration_rates: cfg.
|
|
143
|
-
diversification_between_types: cfg.
|
|
144
|
-
|
|
145
|
-
def _generate_one(self, filename: str, rng: Generator, data: Data) -> None:
|
|
144
|
+
diversification: cfg.SkylineVectorCoercibleConfig = 0
|
|
145
|
+
turnover: cfg.SkylineVectorCoercibleConfig = 0
|
|
146
|
+
sampling_proportions: cfg.SkylineVectorCoercibleConfig = 0
|
|
147
|
+
removal_probabilities: cfg.SkylineVectorCoercibleConfig = 0
|
|
148
|
+
migration_rates: cfg.SkylineMatrixCoercibleConfig = 0
|
|
149
|
+
diversification_between_types: cfg.SkylineMatrixCoercibleConfig = 0
|
|
150
|
+
|
|
151
|
+
def _generate_one(self, filename: str, rng: Generator, data: pgt.Data) -> None:
|
|
146
152
|
reactions = get_FBD_reactions(
|
|
147
153
|
populations=self.populations,
|
|
148
154
|
sample_population=self.sample_population,
|
|
149
|
-
diversification=
|
|
150
|
-
|
|
151
|
-
|
|
155
|
+
diversification=skyline_vector_coercible_factory(
|
|
156
|
+
self.diversification, data
|
|
157
|
+
),
|
|
158
|
+
turnover=skyline_vector_coercible_factory(self.turnover, data),
|
|
159
|
+
sampling_proportions=skyline_vector_coercible_factory(
|
|
152
160
|
self.sampling_proportions, data
|
|
153
161
|
),
|
|
154
|
-
removal_probabilities=
|
|
162
|
+
removal_probabilities=skyline_vector_coercible_factory(
|
|
155
163
|
self.removal_probabilities, data
|
|
156
164
|
),
|
|
157
|
-
migration_rates=
|
|
158
|
-
|
|
165
|
+
migration_rates=skyline_matrix_coercible_factory(
|
|
166
|
+
self.migration_rates, data
|
|
167
|
+
),
|
|
168
|
+
diversification_between_types=skyline_matrix_coercible_factory(
|
|
159
169
|
self.diversification_between_types, data
|
|
160
170
|
),
|
|
161
171
|
)
|
|
@@ -6,6 +6,7 @@ from numpy.random import Generator
|
|
|
6
6
|
from pydantic import Field
|
|
7
7
|
|
|
8
8
|
import phylogenie.core.configs as cfg
|
|
9
|
+
import phylogenie.typings as pgt
|
|
9
10
|
from phylogenie.backend.treesimulator import (
|
|
10
11
|
DEFAULT_POPULATION,
|
|
11
12
|
TreeParams,
|
|
@@ -16,12 +17,11 @@ from phylogenie.backend.treesimulator import (
|
|
|
16
17
|
from phylogenie.core.factories import (
|
|
17
18
|
int_factory,
|
|
18
19
|
scalar_factory,
|
|
19
|
-
|
|
20
|
+
skyline_matrix_coercible_factory,
|
|
20
21
|
skyline_parameter_like_factory,
|
|
21
|
-
|
|
22
|
+
skyline_vector_coercible_factory,
|
|
22
23
|
)
|
|
23
24
|
from phylogenie.core.trees.base import BackendType, TreesGenerator
|
|
24
|
-
from phylogenie.core.typings import Data
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
class ParameterizationType(str, Enum):
|
|
@@ -35,15 +35,15 @@ class TreeSimulatorGenerator(TreesGenerator):
|
|
|
35
35
|
min_tips: cfg.IntConfig
|
|
36
36
|
max_tips: cfg.IntConfig
|
|
37
37
|
T: cfg.ScalarConfig = np.inf
|
|
38
|
+
root_state: str | None = None
|
|
38
39
|
state_frequencies: list[float] | None = None
|
|
39
40
|
notification_probability: cfg.SkylineParameterLikeConfig = 0
|
|
40
41
|
notification_sampling_rate: cfg.SkylineParameterLikeConfig = np.inf
|
|
41
42
|
allow_irremovable_states: bool = False
|
|
42
43
|
max_notified_contacts: cfg.IntConfig = 1
|
|
43
|
-
root_state: str | None = None
|
|
44
44
|
|
|
45
45
|
def _generate_one_from_params(
|
|
46
|
-
self, filename: str, rng: Generator, data: Data, params: TreeParams
|
|
46
|
+
self, filename: str, rng: Generator, data: pgt.Data, params: TreeParams
|
|
47
47
|
) -> None:
|
|
48
48
|
root_state = (
|
|
49
49
|
self.root_state
|
|
@@ -75,26 +75,28 @@ class CanonicalTreeSimulatorGenerator(TreeSimulatorGenerator):
|
|
|
75
75
|
ParameterizationType.CANONICAL
|
|
76
76
|
)
|
|
77
77
|
populations: str | list[str] = DEFAULT_POPULATION
|
|
78
|
-
transition_rates: cfg.
|
|
79
|
-
transmission_rates: cfg.
|
|
80
|
-
removal_rates: cfg.
|
|
81
|
-
sampling_proportions: cfg.
|
|
78
|
+
transition_rates: cfg.SkylineMatrixCoercibleConfig = 0
|
|
79
|
+
transmission_rates: cfg.SkylineMatrixCoercibleConfig = 0
|
|
80
|
+
removal_rates: cfg.SkylineVectorCoercibleConfig = 0
|
|
81
|
+
sampling_proportions: cfg.SkylineVectorCoercibleConfig = 0
|
|
82
82
|
|
|
83
|
-
def _generate_one(self, filename: str, rng: Generator, data: Data) -> None:
|
|
83
|
+
def _generate_one(self, filename: str, rng: Generator, data: pgt.Data) -> None:
|
|
84
84
|
self._generate_one_from_params(
|
|
85
85
|
filename,
|
|
86
86
|
rng,
|
|
87
87
|
data,
|
|
88
88
|
TreeParams(
|
|
89
89
|
populations=self.populations,
|
|
90
|
-
transition_rates=
|
|
90
|
+
transition_rates=skyline_matrix_coercible_factory(
|
|
91
91
|
self.transition_rates, data
|
|
92
92
|
),
|
|
93
|
-
transmission_rates=
|
|
93
|
+
transmission_rates=skyline_matrix_coercible_factory(
|
|
94
94
|
self.transmission_rates, data
|
|
95
95
|
),
|
|
96
|
-
removal_rates=
|
|
97
|
-
|
|
96
|
+
removal_rates=skyline_vector_coercible_factory(
|
|
97
|
+
self.removal_rates, data
|
|
98
|
+
),
|
|
99
|
+
sampling_proportions=skyline_vector_coercible_factory(
|
|
98
100
|
self.sampling_proportions, data
|
|
99
101
|
),
|
|
100
102
|
),
|
|
@@ -107,7 +109,7 @@ class BDTreeSimulatorGenerator(TreeSimulatorGenerator):
|
|
|
107
109
|
infectious_period: cfg.SkylineParameterLikeConfig = 0
|
|
108
110
|
sampling_proportion: cfg.SkylineParameterLikeConfig = 0
|
|
109
111
|
|
|
110
|
-
def _generate_one(self, filename: str, rng: Generator, data: Data) -> None:
|
|
112
|
+
def _generate_one(self, filename: str, rng: Generator, data: pgt.Data) -> None:
|
|
111
113
|
self._generate_one_from_params(
|
|
112
114
|
filename,
|
|
113
115
|
rng,
|
|
@@ -133,7 +135,7 @@ class BDEITreeSimulatorGenerator(TreeSimulatorGenerator):
|
|
|
133
135
|
incubation_period: cfg.SkylineParameterLikeConfig = 0
|
|
134
136
|
sampling_proportion: cfg.SkylineParameterLikeConfig = 0
|
|
135
137
|
|
|
136
|
-
def _generate_one(self, filename: str, rng: Generator, data: Data) -> None:
|
|
138
|
+
def _generate_one(self, filename: str, rng: Generator, data: pgt.Data) -> None:
|
|
137
139
|
self._generate_one_from_params(
|
|
138
140
|
filename,
|
|
139
141
|
rng,
|
phylogenie/core/typeguards.py
CHANGED
|
@@ -1,35 +1,27 @@
|
|
|
1
1
|
from typing import TypeGuard
|
|
2
2
|
|
|
3
3
|
import phylogenie.core.configs as cfg
|
|
4
|
-
import phylogenie.typeguards as tg
|
|
5
|
-
import phylogenie.typings as pgt
|
|
6
4
|
|
|
7
5
|
|
|
8
|
-
def
|
|
9
|
-
return
|
|
6
|
+
def is_list(x: object) -> TypeGuard[list[object]]:
|
|
7
|
+
return isinstance(x, list)
|
|
10
8
|
|
|
11
9
|
|
|
12
|
-
def
|
|
13
|
-
return
|
|
10
|
+
def is_list_of_scalar_configs(x: object) -> TypeGuard[list[cfg.ScalarConfig]]:
|
|
11
|
+
return is_list(x) and all(isinstance(v, cfg.ScalarConfig) for v in x)
|
|
14
12
|
|
|
15
13
|
|
|
16
|
-
def
|
|
17
|
-
return tg.is_many(x) and all(is_many_2D_scalar_configs(v) for v in x)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def is_many_skyline_parameter_like_configs(
|
|
14
|
+
def is_list_of_skyline_parameter_like_configs(
|
|
21
15
|
x: object,
|
|
22
|
-
) -> TypeGuard[
|
|
23
|
-
return
|
|
24
|
-
isinstance(v, cfg.SkylineParameterLikeConfig) for v in x
|
|
25
|
-
)
|
|
16
|
+
) -> TypeGuard[list[cfg.SkylineParameterLikeConfig]]:
|
|
17
|
+
return is_list(x) and all(isinstance(v, cfg.SkylineParameterLikeConfig) for v in x)
|
|
26
18
|
|
|
27
19
|
|
|
28
|
-
def
|
|
20
|
+
def is_list_of_skyline_vector_like_configs(
|
|
29
21
|
x: object,
|
|
30
|
-
) -> TypeGuard[
|
|
31
|
-
return
|
|
32
|
-
isinstance(v, str |
|
|
33
|
-
or
|
|
22
|
+
) -> TypeGuard[list[cfg.SkylineVectorLikeConfig]]:
|
|
23
|
+
return is_list(x) and all(
|
|
24
|
+
isinstance(v, str | cfg.SkylineVectorValueModel)
|
|
25
|
+
or is_list_of_skyline_parameter_like_configs(v)
|
|
34
26
|
for v in x
|
|
35
27
|
)
|
phylogenie/skyline/__init__.py
CHANGED
|
@@ -1,19 +1,29 @@
|
|
|
1
|
-
from phylogenie.skyline.matrix import
|
|
1
|
+
from phylogenie.skyline.matrix import (
|
|
2
|
+
SkylineMatrix,
|
|
3
|
+
SkylineMatrixCoercible,
|
|
4
|
+
skyline_matrix,
|
|
5
|
+
)
|
|
2
6
|
from phylogenie.skyline.parameter import (
|
|
3
7
|
SkylineParameter,
|
|
4
8
|
SkylineParameterLike,
|
|
5
9
|
skyline_parameter,
|
|
6
10
|
)
|
|
7
|
-
from phylogenie.skyline.vector import
|
|
11
|
+
from phylogenie.skyline.vector import (
|
|
12
|
+
SkylineVector,
|
|
13
|
+
SkylineVectorCoercible,
|
|
14
|
+
SkylineVectorLike,
|
|
15
|
+
skyline_vector,
|
|
16
|
+
)
|
|
8
17
|
|
|
9
18
|
__all__ = [
|
|
10
19
|
"skyline_matrix",
|
|
11
20
|
"skyline_parameter",
|
|
12
21
|
"skyline_vector",
|
|
22
|
+
"SkylineMatrix",
|
|
23
|
+
"SkylineMatrixCoercible",
|
|
13
24
|
"SkylineParameter",
|
|
14
25
|
"SkylineParameterLike",
|
|
15
26
|
"SkylineVector",
|
|
27
|
+
"SkylineVectorCoercible",
|
|
16
28
|
"SkylineVectorLike",
|
|
17
|
-
"SkylineMatrix",
|
|
18
|
-
"SkylineMatrixLike",
|
|
19
29
|
]
|
phylogenie/skyline/matrix.py
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
from collections.abc import Callable, Iterator
|
|
2
|
-
from typing import TypeGuard, Union
|
|
2
|
+
from typing import TypeGuard, Union
|
|
3
3
|
|
|
4
4
|
import phylogenie.typeguards as tg
|
|
5
5
|
import phylogenie.typings as pgt
|
|
6
6
|
from phylogenie.skyline.parameter import (
|
|
7
|
+
SkylineParameter,
|
|
7
8
|
SkylineParameterLike,
|
|
8
|
-
is_many_skyline_parameters_like,
|
|
9
9
|
is_skyline_parameter_like,
|
|
10
|
+
skyline_parameter,
|
|
10
11
|
)
|
|
11
12
|
from phylogenie.skyline.vector import (
|
|
12
13
|
SkylineVector,
|
|
@@ -18,51 +19,46 @@ from phylogenie.skyline.vector import (
|
|
|
18
19
|
skyline_vector,
|
|
19
20
|
)
|
|
20
21
|
|
|
21
|
-
SkylineVector2D = pgt.Many[pgt.Many[SkylineParameterLike] | SkylineVector]
|
|
22
|
-
SkylineMatrixParams = SkylineParameterLike | SkylineVector | SkylineVector2D
|
|
23
22
|
SkylineMatrixOperand = Union[SkylineVectorOperand, "SkylineMatrix"]
|
|
24
|
-
|
|
23
|
+
SkylineMatrixCoercible = Union[
|
|
24
|
+
SkylineParameterLike, pgt.Many[SkylineVectorLike], "SkylineMatrix"
|
|
25
|
+
]
|
|
25
26
|
|
|
26
27
|
|
|
27
|
-
def
|
|
28
|
-
return
|
|
29
|
-
isinstance(v, SkylineVector) or is_many_skyline_parameters_like(v)
|
|
30
|
-
for v in value
|
|
31
|
-
)
|
|
28
|
+
def is_skyline_matrix_operand(x: object) -> TypeGuard[SkylineMatrixOperand]:
|
|
29
|
+
return isinstance(x, SkylineMatrix) or is_skyline_vector_operand(x)
|
|
32
30
|
|
|
33
31
|
|
|
34
32
|
class SkylineMatrix:
|
|
35
33
|
def __init__(
|
|
36
34
|
self,
|
|
37
|
-
params:
|
|
38
|
-
value: pgt.
|
|
39
|
-
change_times: pgt.
|
|
35
|
+
params: pgt.Many[SkylineVectorLike] | None = None,
|
|
36
|
+
value: pgt.Many3DScalars | None = None,
|
|
37
|
+
change_times: pgt.ManyScalars | None = None,
|
|
40
38
|
):
|
|
41
39
|
if params is not None and value is None and change_times is None:
|
|
42
|
-
if
|
|
43
|
-
self.params = [skyline_vector(
|
|
44
|
-
elif is_skyline_vector2D(params):
|
|
45
|
-
self.params = [skyline_vector(param, N=len(params)) for param in params]
|
|
40
|
+
if is_many_skyline_vectors_like(params):
|
|
41
|
+
self.params = [skyline_vector(p, len(params)) for p in params]
|
|
46
42
|
else:
|
|
47
43
|
raise TypeError(
|
|
48
|
-
f"It is impossible to create a SkylineMatrix from `params` {params} of type {type(params)}.Please provide either
|
|
49
|
-
"- a SkylineParameterLike object (i.e., a SkylineParameter or a scalar),\n"
|
|
50
|
-
"- a SkylineVector,\n"
|
|
51
|
-
"- or a SkylineVector2D: a sequence containing SkylineVectors and/or sequences of SkylineParameterLike objects."
|
|
44
|
+
f"It is impossible to create a SkylineMatrix from `params` {params} of type {type(params)}. Please provide a sequence composed of SkylineVectorLike objects (a SkylineVectorLike object can either be a SkylineVector or a sequence of scalars and/or SkylineParameters)."
|
|
52
45
|
)
|
|
53
46
|
elif value is not None and change_times is not None:
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
47
|
+
if tg.is_many_3D_scalars(value):
|
|
48
|
+
matrix_lengths = {len(matrix) for matrix in value}
|
|
49
|
+
if any(ml != len(value[0]) for ml in matrix_lengths):
|
|
50
|
+
raise ValueError(
|
|
51
|
+
f"All matrices in the `value` of a SkylineMatrix must have the same length (got value={value} with matrix lengths={matrix_lengths})."
|
|
52
|
+
)
|
|
53
|
+
else:
|
|
54
|
+
raise TypeError(
|
|
55
|
+
f"It is impossible to create a SkylineMatrix from `value` {value} of type {type(value)}. Please provide a nested (3D) sequence of scalar values."
|
|
58
56
|
)
|
|
59
|
-
N = Ns.pop() if Ns else 1
|
|
60
|
-
value = [[[x] * N] * N if isinstance(x, pgt.Scalar) else x for x in value]
|
|
61
57
|
self.params = [
|
|
62
58
|
SkylineVector(
|
|
63
59
|
value=[matrix[i] for matrix in value], change_times=change_times
|
|
64
60
|
)
|
|
65
|
-
for i in range(
|
|
61
|
+
for i in range(len(value[0]))
|
|
66
62
|
]
|
|
67
63
|
else:
|
|
68
64
|
raise ValueError(
|
|
@@ -75,23 +71,27 @@ class SkylineMatrix:
|
|
|
75
71
|
|
|
76
72
|
@property
|
|
77
73
|
def change_times(self) -> pgt.Vector1D:
|
|
78
|
-
return
|
|
74
|
+
return sorted(set([t for row in self.params for t in row.change_times]))
|
|
79
75
|
|
|
80
76
|
@property
|
|
81
77
|
def value(self) -> pgt.Vector3D:
|
|
82
|
-
return
|
|
78
|
+
return [self.get_value_at_time(t) for t in (0, *self.change_times)]
|
|
83
79
|
|
|
84
80
|
def get_value_at_time(self, time: pgt.Scalar) -> pgt.Vector2D:
|
|
85
|
-
return
|
|
81
|
+
return [param.get_value_at_time(time) for param in self.params]
|
|
86
82
|
|
|
87
83
|
def operate(
|
|
88
84
|
self,
|
|
89
85
|
other: SkylineMatrixOperand,
|
|
90
|
-
func: Callable[
|
|
86
|
+
func: Callable[
|
|
87
|
+
[SkylineVector, SkylineVector | SkylineParameter], SkylineVector
|
|
88
|
+
],
|
|
91
89
|
) -> "SkylineMatrix":
|
|
92
90
|
if not is_skyline_matrix_operand(other):
|
|
93
91
|
return NotImplemented
|
|
94
|
-
|
|
92
|
+
if is_skyline_vector_operand(other):
|
|
93
|
+
other = skyline_vector(other, N=self.N)
|
|
94
|
+
assert isinstance(other, SkylineVector | SkylineMatrix)
|
|
95
95
|
return SkylineMatrix(
|
|
96
96
|
[func(p1, p2) for p1, p2 in zip(self.params, other.params)]
|
|
97
97
|
)
|
|
@@ -139,40 +139,34 @@ class SkylineMatrix:
|
|
|
139
139
|
def __len__(self) -> int:
|
|
140
140
|
return self.N
|
|
141
141
|
|
|
142
|
-
|
|
143
|
-
def __getitem__(self, item: int) -> SkylineVector: ...
|
|
144
|
-
@overload
|
|
145
|
-
def __getitem__(self, item: slice) -> "SkylineMatrix": ...
|
|
146
|
-
def __getitem__(self, item: int | slice) -> "SkylineVector | SkylineMatrix":
|
|
147
|
-
if isinstance(item, slice):
|
|
148
|
-
return SkylineMatrix(self.params[item])
|
|
142
|
+
def __getitem__(self, item: int) -> "SkylineVector":
|
|
149
143
|
return self.params[item]
|
|
150
144
|
|
|
151
145
|
def __setitem__(self, item: int, value: SkylineVectorLike) -> None:
|
|
152
146
|
if not is_skyline_vector_like(value):
|
|
153
|
-
raise TypeError(
|
|
147
|
+
raise TypeError(
|
|
148
|
+
f"It is impossible to set item {item} of SkylineMatrix with value {value} of type {type(value)}. Please provide a SkylineVectorLike object (i.e., a SkylineVector or a sequence of scalars and/or SkylineParameters)."
|
|
149
|
+
)
|
|
154
150
|
self.params[item] = skyline_vector(value, N=self.N)
|
|
155
151
|
|
|
156
152
|
|
|
157
153
|
def skyline_matrix(
|
|
158
|
-
x:
|
|
154
|
+
x: SkylineMatrixCoercible, N: int, zero_diagonal: bool = False
|
|
159
155
|
) -> SkylineMatrix:
|
|
160
|
-
if
|
|
161
|
-
x = SkylineMatrix([
|
|
156
|
+
if is_skyline_parameter_like(x):
|
|
157
|
+
x = SkylineMatrix([[skyline_parameter(x)] * N] * N)
|
|
162
158
|
if zero_diagonal:
|
|
163
159
|
for i in range(N):
|
|
164
160
|
x[i][i] = 0
|
|
165
|
-
return x
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
x = SkylineMatrix([skyline_vector(v, N) for v in x])
|
|
169
|
-
|
|
161
|
+
return x
|
|
162
|
+
elif is_many_skyline_vectors_like(x):
|
|
163
|
+
x = SkylineMatrix(x)
|
|
170
164
|
if not isinstance(x, SkylineMatrix):
|
|
171
165
|
raise TypeError(
|
|
172
166
|
f"It is impossible to coerce {x} of type {type(x)} into a SkylineMatrix. Please provide either:\n"
|
|
173
167
|
"- a SkylineMatrix,\n"
|
|
174
|
-
"- a
|
|
175
|
-
"- or a sequence of
|
|
168
|
+
"- a SkylineParameterLike object (i.e., a scalar or a SkylineParameter),\n"
|
|
169
|
+
"- a sequence of SkylineVectorLike objects (a SkylineVectorLike object can be a SkylineVector or a sequence of SkylineParameterLike objects)."
|
|
176
170
|
)
|
|
177
171
|
|
|
178
172
|
if x.N != N:
|
|
@@ -184,7 +178,3 @@ def skyline_matrix(
|
|
|
184
178
|
raise ValueError(f"Expected a SkylineMatrix with zero diagonal, but got {x}.")
|
|
185
179
|
|
|
186
180
|
return x
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
def is_skyline_matrix_operand(x: object) -> TypeGuard[SkylineMatrixOperand]:
|
|
190
|
-
return isinstance(x, SkylineMatrix) or is_skyline_vector_operand(x)
|
phylogenie/skyline/parameter.py
CHANGED
|
@@ -4,32 +4,51 @@ from typing import TypeGuard, Union
|
|
|
4
4
|
|
|
5
5
|
import phylogenie.typeguards as tg
|
|
6
6
|
import phylogenie.typings as pgt
|
|
7
|
-
from phylogenie.utils import vectorify1D
|
|
8
7
|
|
|
9
8
|
SkylineParameterLike = Union[pgt.Scalar, "SkylineParameter"]
|
|
10
9
|
|
|
11
10
|
|
|
11
|
+
def is_skyline_parameter_like(x: object) -> TypeGuard[SkylineParameterLike]:
|
|
12
|
+
return isinstance(x, pgt.Scalar | SkylineParameter)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def is_many_skyline_parameters_like(
|
|
16
|
+
x: object,
|
|
17
|
+
) -> TypeGuard[pgt.Many[SkylineParameterLike]]:
|
|
18
|
+
return tg.is_many(x) and all(is_skyline_parameter_like(v) for v in x)
|
|
19
|
+
|
|
20
|
+
|
|
12
21
|
class SkylineParameter:
|
|
13
22
|
def __init__(
|
|
14
23
|
self,
|
|
15
24
|
value: pgt.OneOrManyScalars,
|
|
16
|
-
change_times: pgt.
|
|
25
|
+
change_times: pgt.ManyScalars | None = None,
|
|
17
26
|
) -> None:
|
|
18
|
-
|
|
19
|
-
|
|
27
|
+
if isinstance(value, pgt.Scalar):
|
|
28
|
+
value = [value]
|
|
29
|
+
elif not tg.is_many_scalars(value):
|
|
30
|
+
raise TypeError(
|
|
31
|
+
f"It is impossible to create a SkylineParameter from `value` {value} of type {type(value)}. Please provide a scalar or a sequence of scalars."
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
if change_times is None:
|
|
35
|
+
change_times = []
|
|
36
|
+
elif not tg.is_many_scalars(change_times):
|
|
37
|
+
raise TypeError(
|
|
38
|
+
f"It is impossible to create a SkylineParameter from `change_times` {change_times} of type {type(change_times)}. Please provide a sequence of scalars."
|
|
39
|
+
)
|
|
40
|
+
|
|
20
41
|
if len(value) != len(change_times) + 1:
|
|
21
42
|
raise ValueError(
|
|
22
43
|
f"`value` must have exactly one more element than `change_times` (got value={value} of length {len(value)} and change_times={change_times} of length {len(change_times)})."
|
|
23
44
|
)
|
|
24
45
|
|
|
25
|
-
|
|
26
|
-
|
|
46
|
+
self.value = [value[0]]
|
|
47
|
+
self.change_times: list[pgt.Scalar] = []
|
|
27
48
|
for i in range(1, len(value)):
|
|
28
49
|
if value[i] != value[i - 1]:
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
self.value = tuple(value_)
|
|
32
|
-
self.change_times = tuple(change_times_)
|
|
50
|
+
self.value.append(value[i])
|
|
51
|
+
self.value.append(change_times[i - 1])
|
|
33
52
|
|
|
34
53
|
def get_value_at_time(self, t: pgt.Scalar) -> pgt.Scalar:
|
|
35
54
|
return self.value[bisect_right(self.change_times, t)]
|
|
@@ -85,13 +104,3 @@ class SkylineParameter:
|
|
|
85
104
|
|
|
86
105
|
def skyline_parameter(x: SkylineParameterLike) -> SkylineParameter:
|
|
87
106
|
return SkylineParameter(x) if isinstance(x, pgt.Scalar) else x
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
def is_skyline_parameter_like(x: object) -> TypeGuard[SkylineParameterLike]:
|
|
91
|
-
return isinstance(x, pgt.Scalar | SkylineParameter)
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
def is_many_skyline_parameters_like(
|
|
95
|
-
x: object,
|
|
96
|
-
) -> TypeGuard[pgt.Many[SkylineParameterLike]]:
|
|
97
|
-
return tg.is_many(x) and all(is_skyline_parameter_like(v) for v in x)
|