rsspolymlp 0.4.2__tar.gz → 0.4.3__tar.gz
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.
- {rsspolymlp-0.4.2/src/rsspolymlp.egg-info → rsspolymlp-0.4.3}/PKG-INFO +24 -20
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/README.md +23 -19
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/pyproject.toml +1 -1
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/analysis/rss_summarize.py +9 -12
- rsspolymlp-0.4.3/src/rsspolymlp/analysis/struct_matcher/assignment_algo.py +181 -0
- rsspolymlp-0.4.3/src/rsspolymlp/analysis/struct_matcher/gen_struct_rep.py +371 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/analysis/struct_matcher/identify_uniqstr.py +77 -38
- rsspolymlp-0.4.3/src/rsspolymlp/analysis/struct_matcher/redrep_lattice.py +144 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/analysis/struct_matcher/redrep_position.py +174 -115
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/analysis/struct_matcher/struct_match.py +25 -10
- rsspolymlp-0.4.3/src/rsspolymlp/analysis/struct_matcher/test/gen_lattice.py +53 -0
- rsspolymlp-0.4.3/src/rsspolymlp/analysis/struct_matcher/test/time_measure.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/api/cli_rsspolymlp_utils.py +34 -28
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/api/rsspolymlp_utils.py +69 -38
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/rss/eliminate_duplicates.py +5 -4
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3/src/rsspolymlp.egg-info}/PKG-INFO +24 -20
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp.egg-info/SOURCES.txt +2 -0
- rsspolymlp-0.4.2/src/rsspolymlp/analysis/struct_matcher/assignment_algo.py +0 -112
- rsspolymlp-0.4.2/src/rsspolymlp/analysis/struct_matcher/gen_struct_rep.py +0 -325
- rsspolymlp-0.4.2/src/rsspolymlp/analysis/struct_matcher/redrep_lattice.py +0 -541
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/LICENSE +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/setup.cfg +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/__init__.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/analysis/__init__.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/analysis/eos.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/analysis/ghost_minima.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/analysis/phase_analysis.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/analysis/struct_matcher/__init__.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/analysis/struct_matcher/chiral_spg.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/api/__init__.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/api/cli_rsspolymlp.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/api/cli_rsspolymlp_devkit.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/api/cli_rsspolymlp_plot.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/api/rsspolymlp.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/api/rsspolymlp_devkit.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/api/rsspolymlp_plot.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/common/__init__.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/common/atomic_energy.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/common/composition.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/common/convert_dict.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/common/interface_vasp.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/common/property.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/mlp_dev/dataset/compress_vasprun.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/mlp_dev/dataset/gen_mlp_dataset.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/mlp_dev/dataset/split_dataset.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/mlp_dev/estimate_cost.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/mlp_dev/model_selection/binary/gen_single_model.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/mlp_dev/model_selection/elemental/gen_hybrid_model.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/mlp_dev/model_selection/elemental/gen_single_model.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/mlp_dev/model_selection/n_feature.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/mlp_dev/model_selection/pypolymlp_gridsearch.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/mlp_dev/model_selection/reduce_grid.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/mlp_dev/pareto_opt_mlp.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/mlp_dev/polymlp_dev.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/rss/__init__.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/rss/load_logfile.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/rss/optimization_mlp.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/rss/random_struct.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/__init__.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/lammps_utils.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/matplot_util/__init__.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/matplot_util/custom_plt.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/matplot_util/examples/__init__.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/matplot_util/examples/example.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/matplot_util/examples/template.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/matplot_util/make_plot.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/opt_sscha/opt_geometry_sscha.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/opt_sscha/opt_position_sscha.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/opt_sscha/run_opt_sscha.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/opt_sscha/sscha_property.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/pymatgen_utils.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/spglib_utils.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/vasp_util/__init__.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/vasp_util/api.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/vasp_util/gen_incar.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/vasp_util/gen_script.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp/utils/vasp_util/write_poscar.py +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp.egg-info/dependency_links.txt +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp.egg-info/entry_points.txt +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp.egg-info/requires.txt +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/src/rsspolymlp.egg-info/top_level.txt +0 -0
- {rsspolymlp-0.4.2 → rsspolymlp-0.4.3}/tests/test_cli_help.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rsspolymlp
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.3
|
|
4
4
|
Summary: A framework for random structure search using polynomial MLPs
|
|
5
5
|
Author-email: Hayato Wakai <wakai@cms.mtl.kyoto-u.ac.jp>
|
|
6
6
|
Maintainer-email: Hayato Wakai <wakai@cms.mtl.kyoto-u.ac.jp>
|
|
@@ -31,25 +31,9 @@ Dynamic: license-file
|
|
|
31
31
|
|
|
32
32
|
# Framework for random structure search using polynomial machine learning potentials
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
- Initial structure generation
|
|
38
|
-
- Global RSS with polynomial MLPs
|
|
39
|
-
- Unique structure identification and RSS result summarization
|
|
40
|
-
- Phase stability analysis
|
|
41
|
-
- [Development kit for polynomial MLPs](docs/rsspolymlp_dev.md)
|
|
42
|
-
- MLP dataset generation
|
|
43
|
-
- DFT dataset division
|
|
44
|
-
- Polynomial MLP development
|
|
45
|
-
- Pareto-optimal MLP selection
|
|
46
|
-
- Python API
|
|
47
|
-
- [RSS workflow](docs/api_rsspolymlp.md)
|
|
48
|
-
- [VASP calculation utilities](src/rsspolymlp/utils/vasp_util/readme.md)
|
|
49
|
-
- Single-point calculation
|
|
50
|
-
- Local geometry optimization
|
|
51
|
-
- [Matplotlib utilities](src/rsspolymlp/utils/matplot_util/readme.md)
|
|
52
|
-
|
|
34
|
+
`rsspolymlp` is a Python code designed to conduct random structure searches (RSS) using polynomial machine learning potentials (MLPs).
|
|
35
|
+
The code provides functionalities for generating initial random structures, performing geometry optimization using polynomial MLPs, and eliminating duplicate structures.
|
|
36
|
+
The formulation and development of polynomial MLPs are detailed in [`pypolymlp`](https://github.com/sekocha/pypolymlp).
|
|
53
37
|
|
|
54
38
|
## Installation
|
|
55
39
|
|
|
@@ -88,6 +72,26 @@ pip install rsspolymlp
|
|
|
88
72
|
```
|
|
89
73
|
|
|
90
74
|
|
|
75
|
+
## How to use rsspolymlp
|
|
76
|
+
|
|
77
|
+
- [Workflow of RSS with polynomial MLPs](docs/rsspolymlp.md)
|
|
78
|
+
- Initial structure generation
|
|
79
|
+
- Global RSS with polynomial MLPs
|
|
80
|
+
- Unique structure identification and RSS result summarization
|
|
81
|
+
- Phase stability analysis
|
|
82
|
+
- [Development kit for polynomial MLPs](docs/rsspolymlp_dev.md)
|
|
83
|
+
- MLP dataset generation
|
|
84
|
+
- DFT dataset division
|
|
85
|
+
- Polynomial MLP development
|
|
86
|
+
- Pareto-optimal MLP selection
|
|
87
|
+
- Python API
|
|
88
|
+
- [RSS workflow](docs/api_rsspolymlp.md)
|
|
89
|
+
- [VASP calculation utilities](src/rsspolymlp/utils/vasp_util/readme.md)
|
|
90
|
+
- Single-point calculation
|
|
91
|
+
- Local geometry optimization
|
|
92
|
+
- [Matplotlib utilities](src/rsspolymlp/utils/matplot_util/readme.md)
|
|
93
|
+
|
|
94
|
+
|
|
91
95
|
## Citation of rsspolymlp
|
|
92
96
|
|
|
93
97
|
If you use `rsspolymlp` in your study, please cite the following articles.
|
|
@@ -1,24 +1,8 @@
|
|
|
1
1
|
# Framework for random structure search using polynomial machine learning potentials
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
- Initial structure generation
|
|
7
|
-
- Global RSS with polynomial MLPs
|
|
8
|
-
- Unique structure identification and RSS result summarization
|
|
9
|
-
- Phase stability analysis
|
|
10
|
-
- [Development kit for polynomial MLPs](docs/rsspolymlp_dev.md)
|
|
11
|
-
- MLP dataset generation
|
|
12
|
-
- DFT dataset division
|
|
13
|
-
- Polynomial MLP development
|
|
14
|
-
- Pareto-optimal MLP selection
|
|
15
|
-
- Python API
|
|
16
|
-
- [RSS workflow](docs/api_rsspolymlp.md)
|
|
17
|
-
- [VASP calculation utilities](src/rsspolymlp/utils/vasp_util/readme.md)
|
|
18
|
-
- Single-point calculation
|
|
19
|
-
- Local geometry optimization
|
|
20
|
-
- [Matplotlib utilities](src/rsspolymlp/utils/matplot_util/readme.md)
|
|
21
|
-
|
|
3
|
+
`rsspolymlp` is a Python code designed to conduct random structure searches (RSS) using polynomial machine learning potentials (MLPs).
|
|
4
|
+
The code provides functionalities for generating initial random structures, performing geometry optimization using polynomial MLPs, and eliminating duplicate structures.
|
|
5
|
+
The formulation and development of polynomial MLPs are detailed in [`pypolymlp`](https://github.com/sekocha/pypolymlp).
|
|
22
6
|
|
|
23
7
|
## Installation
|
|
24
8
|
|
|
@@ -57,6 +41,26 @@ pip install rsspolymlp
|
|
|
57
41
|
```
|
|
58
42
|
|
|
59
43
|
|
|
44
|
+
## How to use rsspolymlp
|
|
45
|
+
|
|
46
|
+
- [Workflow of RSS with polynomial MLPs](docs/rsspolymlp.md)
|
|
47
|
+
- Initial structure generation
|
|
48
|
+
- Global RSS with polynomial MLPs
|
|
49
|
+
- Unique structure identification and RSS result summarization
|
|
50
|
+
- Phase stability analysis
|
|
51
|
+
- [Development kit for polynomial MLPs](docs/rsspolymlp_dev.md)
|
|
52
|
+
- MLP dataset generation
|
|
53
|
+
- DFT dataset division
|
|
54
|
+
- Polynomial MLP development
|
|
55
|
+
- Pareto-optimal MLP selection
|
|
56
|
+
- Python API
|
|
57
|
+
- [RSS workflow](docs/api_rsspolymlp.md)
|
|
58
|
+
- [VASP calculation utilities](src/rsspolymlp/utils/vasp_util/readme.md)
|
|
59
|
+
- Single-point calculation
|
|
60
|
+
- Local geometry optimization
|
|
61
|
+
- [Matplotlib utilities](src/rsspolymlp/utils/matplot_util/readme.md)
|
|
62
|
+
|
|
63
|
+
|
|
60
64
|
## Citation of rsspolymlp
|
|
61
65
|
|
|
62
66
|
If you use `rsspolymlp` in your study, please cite the following articles.
|
|
@@ -9,15 +9,14 @@ from time import time
|
|
|
9
9
|
from typing import Optional
|
|
10
10
|
|
|
11
11
|
import numpy as np
|
|
12
|
-
|
|
13
12
|
from pypolymlp.utils.vasp_utils import write_poscar_file
|
|
13
|
+
|
|
14
14
|
from rsspolymlp.analysis.ghost_minima import detect_ghost_minima
|
|
15
15
|
from rsspolymlp.analysis.struct_matcher.gen_struct_rep import (
|
|
16
|
+
StructRepGenerator,
|
|
16
17
|
StructReps,
|
|
17
|
-
generate_struct_reps_parallel,
|
|
18
18
|
)
|
|
19
19
|
from rsspolymlp.analysis.struct_matcher.identify_uniqstr import (
|
|
20
|
-
UniqueStructIdentifier,
|
|
21
20
|
identify_unique_structure,
|
|
22
21
|
)
|
|
23
22
|
from rsspolymlp.common.composition import compute_composition
|
|
@@ -58,7 +57,7 @@ class RSSResultSummarizer:
|
|
|
58
57
|
self.update_parent = update_parent
|
|
59
58
|
|
|
60
59
|
self.pressure = None
|
|
61
|
-
self.analyzer =
|
|
60
|
+
self.analyzer = None
|
|
62
61
|
|
|
63
62
|
def run_summarize(self):
|
|
64
63
|
os.makedirs("json", exist_ok=True)
|
|
@@ -92,8 +91,6 @@ class RSSResultSummarizer:
|
|
|
92
91
|
|
|
93
92
|
for comp_tag, res_paths in json_paths_c.items():
|
|
94
93
|
print(f"Composition {comp_tag}: summarizing...")
|
|
95
|
-
self.analyzer = UniqueStructIdentifier()
|
|
96
|
-
|
|
97
94
|
time_start = time()
|
|
98
95
|
|
|
99
96
|
processed_paths = set()
|
|
@@ -196,8 +193,6 @@ class RSSResultSummarizer:
|
|
|
196
193
|
|
|
197
194
|
for comp_tag, res_paths in json_paths_c.items():
|
|
198
195
|
print(f"Composition {comp_tag}: summarizing...")
|
|
199
|
-
self.analyzer = UniqueStructIdentifier()
|
|
200
|
-
|
|
201
196
|
if not self.parse_vasp:
|
|
202
197
|
axis_tol = 0.03
|
|
203
198
|
pos_tol = 0.03
|
|
@@ -210,7 +205,7 @@ class RSSResultSummarizer:
|
|
|
210
205
|
print(f" - Processing result file (parent): {res_path}")
|
|
211
206
|
self.analyzer = identify_unique_structure(
|
|
212
207
|
rss_results_c[comp_tag][res_path],
|
|
213
|
-
|
|
208
|
+
normalize_axis=True,
|
|
214
209
|
keep_unique=True,
|
|
215
210
|
axis_tol=axis_tol,
|
|
216
211
|
pos_tol=pos_tol,
|
|
@@ -264,11 +259,13 @@ class RSSResultSummarizer:
|
|
|
264
259
|
r["dupstr_paths"] = set(r["dupstr_paths"])
|
|
265
260
|
|
|
266
261
|
print(" - Converting reduced crystal structure representation...")
|
|
267
|
-
|
|
268
|
-
rss_results,
|
|
262
|
+
generator = StructRepGenerator(
|
|
269
263
|
num_process=self.num_process,
|
|
270
264
|
backend=self.backend,
|
|
271
|
-
|
|
265
|
+
primitive_symprecs=self.primitive_symprecs,
|
|
266
|
+
)
|
|
267
|
+
struct_reps_list = generator.generate_struct_reps_parallel(
|
|
268
|
+
rss_results,
|
|
272
269
|
)
|
|
273
270
|
if self.update_parent:
|
|
274
271
|
print(" - Eliminating duplicate structures...")
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import time
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
from scipy.sparse import csr_array
|
|
5
|
+
from scipy.sparse.csgraph import maximum_bipartite_matching
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def sort_match_screen(
|
|
9
|
+
pos_reps1: np.ndarray,
|
|
10
|
+
pos_reps2: np.ndarray,
|
|
11
|
+
elements1: np.ndarray,
|
|
12
|
+
elements2: np.ndarray,
|
|
13
|
+
axis_abc: np.ndarray,
|
|
14
|
+
pos_tol: float,
|
|
15
|
+
verbose: bool = False,
|
|
16
|
+
):
|
|
17
|
+
# pos1: (N1, n_atoms, 3)
|
|
18
|
+
# pos2: (N2, n_atoms, 3)
|
|
19
|
+
if len(elements1) != len(elements2):
|
|
20
|
+
return np.zeros((len(pos_reps1), len(pos_reps2)), dtype=bool)
|
|
21
|
+
unique_elements = np.unique(elements1)
|
|
22
|
+
|
|
23
|
+
def sort_positions_axis(pos_reps, elements, axis):
|
|
24
|
+
pos_reps = np.asarray(pos_reps)
|
|
25
|
+
sorted_reps = np.empty_like(pos_reps[:, :, axis])
|
|
26
|
+
start = 0
|
|
27
|
+
for el in unique_elements:
|
|
28
|
+
idx = np.flatnonzero(elements == el)
|
|
29
|
+
n = len(idx)
|
|
30
|
+
sorted_reps[:, start : start + n] = np.sort(
|
|
31
|
+
pos_reps[:, idx, axis],
|
|
32
|
+
axis=1,
|
|
33
|
+
)
|
|
34
|
+
start += n
|
|
35
|
+
return sorted_reps
|
|
36
|
+
|
|
37
|
+
matched = np.ones(
|
|
38
|
+
(len(pos_reps1), len(pos_reps2)),
|
|
39
|
+
dtype=bool,
|
|
40
|
+
)
|
|
41
|
+
for axis in range(3):
|
|
42
|
+
rows, cols = np.where(matched)
|
|
43
|
+
if len(rows) == 0:
|
|
44
|
+
break
|
|
45
|
+
|
|
46
|
+
t_start_s = time.time()
|
|
47
|
+
pos1_axis = sort_positions_axis(pos_reps1, elements1, axis)
|
|
48
|
+
pos2_axis = sort_positions_axis(pos_reps2, elements2, axis)
|
|
49
|
+
if verbose:
|
|
50
|
+
print(f"code: sort_match_screen (axis {axis})")
|
|
51
|
+
print(f" Sorting: {round((time.time() - t_start_s) * 1000, 2)} ms")
|
|
52
|
+
|
|
53
|
+
t_start_m = time.time()
|
|
54
|
+
diff = pos1_axis[rows] - pos2_axis[cols]
|
|
55
|
+
diff -= axis_abc[axis] * np.round(diff / axis_abc[axis])
|
|
56
|
+
matched[rows, cols] = np.all(np.abs(diff) <= pos_tol, axis=1)
|
|
57
|
+
if verbose:
|
|
58
|
+
print(f" Matching: {round((time.time() - t_start_m) * 1000, 2)} ms")
|
|
59
|
+
print(f" Candidate matches: {np.count_nonzero(matched)}")
|
|
60
|
+
return matched
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def greedy_match(
|
|
64
|
+
pos1: np.ndarray,
|
|
65
|
+
pos2: np.ndarray,
|
|
66
|
+
elements1: np.ndarray,
|
|
67
|
+
elements2: np.ndarray,
|
|
68
|
+
axis_abc: np.ndarray,
|
|
69
|
+
pos_tol: float,
|
|
70
|
+
verbose: bool = False,
|
|
71
|
+
):
|
|
72
|
+
judge = True
|
|
73
|
+
inv_axis_abc = 1 / axis_abc
|
|
74
|
+
|
|
75
|
+
t_start_g = time.time()
|
|
76
|
+
for el in np.unique(elements1):
|
|
77
|
+
if not judge:
|
|
78
|
+
break
|
|
79
|
+
targets1 = np.where(elements1 == el)[0]
|
|
80
|
+
targets2 = np.where(elements2 == el)[0]
|
|
81
|
+
used = np.zeros(len(targets1), dtype=bool)
|
|
82
|
+
for i in targets1:
|
|
83
|
+
diff = np.abs(pos2[targets2] - pos1[i])
|
|
84
|
+
diff -= axis_abc * np.round(inv_axis_abc * diff)
|
|
85
|
+
diff_max = np.max(np.abs(diff), axis=1)
|
|
86
|
+
diff[used] = np.inf
|
|
87
|
+
j = np.argmin(diff_max)
|
|
88
|
+
if diff_max[j] >= pos_tol:
|
|
89
|
+
judge = False
|
|
90
|
+
break
|
|
91
|
+
used[j] = True
|
|
92
|
+
if verbose:
|
|
93
|
+
print("code: greedy_match")
|
|
94
|
+
print(f" Matching: {round((time.time() - t_start_g) * 1000, 2)} ms")
|
|
95
|
+
|
|
96
|
+
if judge:
|
|
97
|
+
return True
|
|
98
|
+
else:
|
|
99
|
+
return False
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def bottleneck_assignment(
|
|
103
|
+
pos1: np.ndarray,
|
|
104
|
+
pos2: np.ndarray,
|
|
105
|
+
elements1: np.ndarray,
|
|
106
|
+
elements2: np.ndarray,
|
|
107
|
+
axis_abc: np.ndarray,
|
|
108
|
+
pos_tol: float,
|
|
109
|
+
best_matching: bool = False,
|
|
110
|
+
verbose: bool = False,
|
|
111
|
+
):
|
|
112
|
+
inv_axis_abc = 1 / axis_abc
|
|
113
|
+
for el in np.unique(elements1):
|
|
114
|
+
targets1 = np.where(elements1 == el)[0]
|
|
115
|
+
targets2 = np.where(elements2 == el)[0]
|
|
116
|
+
pos1_sub = pos1[targets1]
|
|
117
|
+
pos2_sub = pos2[targets2]
|
|
118
|
+
|
|
119
|
+
t_start_d = time.time()
|
|
120
|
+
diff = pos1_sub[:, None, :] - pos2_sub[None, :, :]
|
|
121
|
+
diff -= axis_abc * np.round(diff * inv_axis_abc)
|
|
122
|
+
pos_d = np.max(np.abs(diff), axis=2)
|
|
123
|
+
n = pos_d.shape[0]
|
|
124
|
+
if verbose:
|
|
125
|
+
print("code: bottleneck_assignment")
|
|
126
|
+
print(
|
|
127
|
+
f" Difference Calc.: {round((time.time() - t_start_d) * 1000, 2)} ms"
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
t_start_m = time.time()
|
|
131
|
+
if best_matching:
|
|
132
|
+
# Sort distinct candidate distances
|
|
133
|
+
values = np.unique(pos_d)
|
|
134
|
+
left, right = 0, len(values) - 1
|
|
135
|
+
while left < right:
|
|
136
|
+
mid = (left + right) // 2
|
|
137
|
+
rows, cols = np.where(pos_d <= values[mid])
|
|
138
|
+
graph = csr_array(
|
|
139
|
+
(
|
|
140
|
+
np.ones(len(rows), dtype=np.int8),
|
|
141
|
+
(rows, cols),
|
|
142
|
+
),
|
|
143
|
+
shape=pos_d.shape,
|
|
144
|
+
)
|
|
145
|
+
matching = maximum_bipartite_matching(graph, perm_type="column")
|
|
146
|
+
if np.all(matching >= 0):
|
|
147
|
+
right = mid
|
|
148
|
+
else:
|
|
149
|
+
left = mid + 1
|
|
150
|
+
|
|
151
|
+
threshold = values[left]
|
|
152
|
+
rows, cols = np.where(pos_d <= threshold)
|
|
153
|
+
graph = csr_array(
|
|
154
|
+
(
|
|
155
|
+
np.ones(len(rows), dtype=np.int8),
|
|
156
|
+
(rows, cols),
|
|
157
|
+
),
|
|
158
|
+
shape=pos_d.shape,
|
|
159
|
+
)
|
|
160
|
+
matching = maximum_bipartite_matching(graph, perm_type="column")
|
|
161
|
+
pos_max_diffs = pos_d[np.arange(n), matching].tolist()
|
|
162
|
+
if verbose:
|
|
163
|
+
print(f" Matching: {round((time.time() - t_start_m) * 1000, 2)} ms")
|
|
164
|
+
if max(pos_max_diffs) > pos_tol:
|
|
165
|
+
return False
|
|
166
|
+
else:
|
|
167
|
+
t_start_m = time.time()
|
|
168
|
+
rows, cols = np.where(pos_d <= pos_tol)
|
|
169
|
+
graph = csr_array(
|
|
170
|
+
(
|
|
171
|
+
np.ones(len(rows), dtype=np.int8),
|
|
172
|
+
(rows, cols),
|
|
173
|
+
),
|
|
174
|
+
shape=pos_d.shape,
|
|
175
|
+
)
|
|
176
|
+
matching = maximum_bipartite_matching(graph, perm_type="column")
|
|
177
|
+
if verbose:
|
|
178
|
+
print(f" Matching: {round((time.time() - t_start_m) * 1000, 2)} ms")
|
|
179
|
+
if not np.all(matching >= 0):
|
|
180
|
+
return False
|
|
181
|
+
return True
|