phylogenie 1.0.1__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 +3 -4
- 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 +3 -3
- 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 +55 -47
- phylogenie/core/trees/treesimulator.py +17 -15
- 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.1.dist-info → phylogenie-1.0.2.dist-info}/METADATA +2 -2
- phylogenie-1.0.2.dist-info/RECORD +39 -0
- phylogenie/core/typings.py +0 -10
- phylogenie/utils.py +0 -20
- phylogenie-1.0.1.dist-info/RECORD +0 -41
- {phylogenie-1.0.1.dist-info → phylogenie-1.0.2.dist-info}/LICENSE.txt +0 -0
- {phylogenie-1.0.1.dist-info → phylogenie-1.0.2.dist-info}/WHEEL +0 -0
- {phylogenie-1.0.1.dist-info → phylogenie-1.0.2.dist-info}/entry_points.txt +0 -0
|
@@ -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):
|
|
@@ -48,7 +48,7 @@ class ReMASTERGenerator(TreesGenerator):
|
|
|
48
48
|
trajectory_attrs: dict[str, str | int | float] = Field(default_factory=dict)
|
|
49
49
|
|
|
50
50
|
def _generate_one_from_extra_reactions(
|
|
51
|
-
self, filename: str, rng: Generator, data: Data, reactions: list[Reaction]
|
|
51
|
+
self, filename: str, rng: Generator, data: pgt.Data, reactions: list[Reaction]
|
|
52
52
|
) -> None:
|
|
53
53
|
generate_trees(
|
|
54
54
|
tree_file_name=f"{filename}.nwk",
|
|
@@ -67,7 +67,7 @@ class ReMASTERGenerator(TreesGenerator):
|
|
|
67
67
|
beast_path=self.beast_path,
|
|
68
68
|
)
|
|
69
69
|
|
|
70
|
-
def _generate_one(self, filename: str, rng: Generator, data: Data) -> None:
|
|
70
|
+
def _generate_one(self, filename: str, rng: Generator, data: pgt.Data) -> None:
|
|
71
71
|
self._generate_one_from_extra_reactions(filename, rng, data, reactions=[])
|
|
72
72
|
|
|
73
73
|
|
|
@@ -75,25 +75,27 @@ class CanonicalReMASTERGenerator(ReMASTERGenerator):
|
|
|
75
75
|
parameterization: Literal[ParameterizationType.CANONICAL] = (
|
|
76
76
|
ParameterizationType.CANONICAL
|
|
77
77
|
)
|
|
78
|
-
birth_rates: cfg.
|
|
79
|
-
death_rates: cfg.
|
|
80
|
-
sampling_rates: cfg.
|
|
81
|
-
removal_probabilities: cfg.
|
|
82
|
-
migration_rates: cfg.
|
|
83
|
-
birth_rates_among_demes: cfg.
|
|
84
|
-
|
|
85
|
-
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:
|
|
86
86
|
reactions = get_canonical_reactions(
|
|
87
87
|
populations=self.populations,
|
|
88
88
|
sample_population=self.sample_population,
|
|
89
|
-
birth_rates=
|
|
90
|
-
death_rates=
|
|
91
|
-
sampling_rates=
|
|
92
|
-
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(
|
|
93
93
|
self.removal_probabilities, data
|
|
94
94
|
),
|
|
95
|
-
migration_rates=
|
|
96
|
-
|
|
95
|
+
migration_rates=skyline_matrix_coercible_factory(
|
|
96
|
+
self.migration_rates, data
|
|
97
|
+
),
|
|
98
|
+
birth_rates_among_demes=skyline_matrix_coercible_factory(
|
|
97
99
|
self.birth_rates_among_demes, data
|
|
98
100
|
),
|
|
99
101
|
)
|
|
@@ -104,31 +106,33 @@ class EpidemiologicalReMASTERGenerator(ReMASTERGenerator):
|
|
|
104
106
|
parameterization: Literal[ParameterizationType.EPIDEMIOLOGICAL] = (
|
|
105
107
|
ParameterizationType.EPIDEMIOLOGICAL
|
|
106
108
|
)
|
|
107
|
-
reproduction_numbers: cfg.
|
|
108
|
-
become_uninfectious_rates: cfg.
|
|
109
|
-
sampling_proportions: cfg.
|
|
110
|
-
removal_probabilities: cfg.
|
|
111
|
-
migration_rates: cfg.
|
|
112
|
-
reproduction_numbers_among_demes: cfg.
|
|
113
|
-
|
|
114
|
-
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:
|
|
115
117
|
reactions = get_epidemiological_reactions(
|
|
116
118
|
populations=self.populations,
|
|
117
119
|
sample_population=self.sample_population,
|
|
118
|
-
reproduction_numbers=
|
|
120
|
+
reproduction_numbers=skyline_vector_coercible_factory(
|
|
119
121
|
self.reproduction_numbers, data
|
|
120
122
|
),
|
|
121
|
-
become_uninfectious_rates=
|
|
123
|
+
become_uninfectious_rates=skyline_vector_coercible_factory(
|
|
122
124
|
self.become_uninfectious_rates, data
|
|
123
125
|
),
|
|
124
|
-
sampling_proportions=
|
|
126
|
+
sampling_proportions=skyline_vector_coercible_factory(
|
|
125
127
|
self.sampling_proportions, data
|
|
126
128
|
),
|
|
127
|
-
removal_probabilities=
|
|
129
|
+
removal_probabilities=skyline_vector_coercible_factory(
|
|
128
130
|
self.removal_probabilities, data
|
|
129
131
|
),
|
|
130
|
-
migration_rates=
|
|
131
|
-
|
|
132
|
+
migration_rates=skyline_matrix_coercible_factory(
|
|
133
|
+
self.migration_rates, data
|
|
134
|
+
),
|
|
135
|
+
reproduction_numbers_among_demes=skyline_matrix_coercible_factory(
|
|
132
136
|
self.reproduction_numbers_among_demes, data
|
|
133
137
|
),
|
|
134
138
|
)
|
|
@@ -137,27 +141,31 @@ class EpidemiologicalReMASTERGenerator(ReMASTERGenerator):
|
|
|
137
141
|
|
|
138
142
|
class FBDReMASTERGenerator(ReMASTERGenerator):
|
|
139
143
|
parameterization: Literal[ParameterizationType.FBD] = ParameterizationType.FBD
|
|
140
|
-
diversification: cfg.
|
|
141
|
-
turnover: cfg.
|
|
142
|
-
sampling_proportions: cfg.
|
|
143
|
-
removal_probabilities: cfg.
|
|
144
|
-
migration_rates: cfg.
|
|
145
|
-
diversification_between_types: cfg.
|
|
146
|
-
|
|
147
|
-
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:
|
|
148
152
|
reactions = get_FBD_reactions(
|
|
149
153
|
populations=self.populations,
|
|
150
154
|
sample_population=self.sample_population,
|
|
151
|
-
diversification=
|
|
152
|
-
|
|
153
|
-
|
|
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(
|
|
154
160
|
self.sampling_proportions, data
|
|
155
161
|
),
|
|
156
|
-
removal_probabilities=
|
|
162
|
+
removal_probabilities=skyline_vector_coercible_factory(
|
|
157
163
|
self.removal_probabilities, data
|
|
158
164
|
),
|
|
159
|
-
migration_rates=
|
|
160
|
-
|
|
165
|
+
migration_rates=skyline_matrix_coercible_factory(
|
|
166
|
+
self.migration_rates, data
|
|
167
|
+
),
|
|
168
|
+
diversification_between_types=skyline_matrix_coercible_factory(
|
|
161
169
|
self.diversification_between_types, data
|
|
162
170
|
),
|
|
163
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):
|
|
@@ -43,7 +43,7 @@ class TreeSimulatorGenerator(TreesGenerator):
|
|
|
43
43
|
max_notified_contacts: cfg.IntConfig = 1
|
|
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)
|