From aec570d055dedbcf1b6a46983ab346edd51a6280 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Thu, 6 Feb 2020 00:24:24 +0100 Subject: [PATCH] WIP 2, to be cleaned and merged --- .gitignore | 1 + MANIFEST.in | 1 + README.md | 13 +- benchmark_out.py | 12 + build_gui.py | 6 +- pytest.ini | 3 +- rust/.cargo/config | 2 - rust/Cargo.lock | 482 ++++++--- rust/Cargo.toml | 31 +- rust/src/common.rs | 81 +- rust/src/lib.rs | 103 +- rust/src/preprocess.rs | 1 - rust/src/route.rs | 2220 ++++++++++++++++++++++------------------ setup.py | 19 +- tox.ini | 32 +- 15 files changed, 1826 insertions(+), 1181 deletions(-) create mode 100644 benchmark_out.py delete mode 100644 rust/.cargo/config diff --git a/.gitignore b/.gitignore index b435dd2..d5bb9d9 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ exe/ installer/Output/ workspace.code-workspace ed_lrr_gui/web/jobs.db +ed_lrr_gui/web/ed_lrr_web_ui.db diff --git a/MANIFEST.in b/MANIFEST.in index 2f28226..a159d6a 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,4 @@ include rust/Cargo.toml include rust/.cargo/config recursive-include rust/src * +recursive-include ed_lrr_gui * \ No newline at end of file diff --git a/README.md b/README.md index fbd5e96..db04633 100644 --- a/README.md +++ b/README.md @@ -52,13 +52,11 @@ pip install . then you can run `ed_lrr -h` from your command prompt to get help -# To do +# TODO -## Router +## Routing -- Caching wrapper for System - - Only fetch position once when building Spatial-Tree - - Fetch data on demand +- Custom weights and filtering for routing ## GUI @@ -79,4 +77,7 @@ then you can run `ed_lrr -h` from your command prompt to get help ## Misc -- Luigi based Task queue for distributed routing \ No newline at end of file +- Luigi based Task queue for distributed routing +- Full route tree computation + - overlap elimination + diff --git a/benchmark_out.py b/benchmark_out.py new file mode 100644 index 0000000..b089e73 --- /dev/null +++ b/benchmark_out.py @@ -0,0 +1,12 @@ +import ujson as json +from datetime import timedelta +data=json.load(open("benchmark.json")) + +times=[] + +for workers,results in data.items(): + t_total=sum([res['time'] for res in results])/len(results) + avg_len=sum([res['ret'] for res in results])/len(results) + times.append([int(workers),timedelta(seconds=t_total),avg_len]) +for k,v,l in sorted(times,key=lambda rec:rec[1]): + print(k,v,l) \ No newline at end of file diff --git a/build_gui.py b/build_gui.py index c7aba5e..831c09d 100644 --- a/build_gui.py +++ b/build_gui.py @@ -1,5 +1,4 @@ -import subprocess as SP -from glob import glob +from PyQt5 import uic import os @@ -13,4 +12,5 @@ for root, folders, files in os.walk(ui_path): if ext == ".ui": outfile = outfile + ".py" print(file, "->", outfile) - SP.check_call(["pyuic5", "--from-imports", "-o", outfile, file]) + with open(outfile, "w") as fh_out: + uic.compileUi(file, fh_out, from_imports=True) diff --git a/pytest.ini b/pytest.ini index 2c1a18a..c6c5435 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,2 +1,3 @@ [pytest] -qt_api=pyqt5 \ No newline at end of file +qt_api=pyqt5 +addopts = --cov=ed_lrr_gui --cov-report html \ No newline at end of file diff --git a/rust/.cargo/config b/rust/.cargo/config deleted file mode 100644 index a5af40a..0000000 --- a/rust/.cargo/config +++ /dev/null @@ -1,2 +0,0 @@ -[build] -rustflags = ["-C", "target-cpu=native"] diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 4dc2761..48bb1b3 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -1,11 +1,29 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "ahash" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "const-random 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "aho-corasick" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -14,13 +32,46 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "bincode" -version = "1.2.0" +name = "autocfg" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "backtrace" +version = "0.3.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "backtrace-sys" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "better-panic" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", + "console 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bincode" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -28,7 +79,7 @@ name = "block-buffer" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -36,7 +87,7 @@ dependencies = [ [[package]] name = "block-padding" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -44,13 +95,13 @@ dependencies = [ [[package]] name = "bstr" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -64,15 +115,86 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "csv" -version = "1.1.1" +name = "cc" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "clicolors-control" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "console" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "const-random" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "const-random-macro 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "const-random-macro" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-channel" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-utils" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "csv" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bstr 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -80,7 +202,7 @@ name = "csv-core" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -89,7 +211,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -102,27 +224,38 @@ dependencies = [ [[package]] name = "ed_lrr" -version = "0.0.0" +version = "0.2.0" dependencies = [ - "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "better-panic 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "csv 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "humantime 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "pyo3 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rstar 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "pyo3 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rstar 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", "sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "simd-json 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "either" -version = "1.5.3" +name = "encode_unicode" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "float-cmp" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "fnv" version = "1.0.6" @@ -136,23 +269,56 @@ dependencies = [ "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "getrandom" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ghost" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "halfbrown" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hashbrown 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hashbrown" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ahash 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hermit-abi" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "humantime" -version = "1.3.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "indoc" @@ -169,43 +335,35 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", "unindent 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "inventory" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ctor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "ghost 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "inventory-impl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "inventory-impl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "inventory-impl" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "itertools" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "itoa" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -220,23 +378,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.65" +version = "0.2.66" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "memchr" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-traits" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -259,9 +417,9 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -279,14 +437,14 @@ name = "proc-macro-hack" version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "proc-macro2" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -294,19 +452,19 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.8.1" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "indoc 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "inventory 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "inventory 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "pyo3cls 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "pyo3cls 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "unindent 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -314,47 +472,42 @@ dependencies = [ [[package]] name = "pyo3-derive-backend" -version = "0.8.1" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "pyo3cls" -version = "0.8.1" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "pyo3-derive-backend 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "pyo3-derive-backend 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "quick-error" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "quote" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex" -version = "1.3.1" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -367,19 +520,23 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.12" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rstar" -version = "0.5.1" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "pdqselect 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rustc-demangle" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "ryu" version = "1.0.2" @@ -387,30 +544,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.101" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.101" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.41" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -425,6 +582,19 @@ dependencies = [ "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "simd-json" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "float-cmp 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "halfbrown 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "spin" version = "0.5.2" @@ -432,22 +602,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "strsim" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syn" -version = "1.0.5" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "termios" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "thread_local" -version = "0.3.6" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -473,61 +651,109 @@ name = "version_check" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [metadata] +"checksum ahash 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "6f33b5018f120946c1dcf279194f238a9f146725593ead1c08fa47ff22b0b5d3" "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" +"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" -"checksum bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8ab639324e3ee8774d296864fbc0dbbb256cf1a41c490b94cba90c082915f92" +"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" +"checksum backtrace 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)" = "7f80256bc78f67e7df7e36d77366f636ed976895d91fe2ab9efa3973e8fe8c4f" +"checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491" +"checksum better-panic 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d12a680cc74d8c4a44ee08be4a00dedf671b089c2440b2e3fdaa776cd468476" +"checksum bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5753e2a71534719bf3f4e57006c3a4f0d2c672a4b676eec84161f763eca87dbf" "checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -"checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09" -"checksum bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6c2c5b58ab920a4f5aeaaca34b4488074e8cc7596af94e6f8c6ff247c60245" +"checksum block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +"checksum bstr 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "fe8a65814ca90dfc9705af76bb6ba3c6e2534489a72270e797e603783bb4990b" "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" -"checksum csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37519ccdfd73a75821cac9319d4fce15a81b9fcf75f951df5b9988aa3a0af87d" +"checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" +"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e" +"checksum console 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "45e0f3986890b3acbc782009e2629dfe2baa430ac091519ce3be26164a2ae6c0" +"checksum const-random 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "2f1af9ac737b2dd2d577701e59fd09ba34822f6f2ebdb30a7647405d9e55e16a" +"checksum const-random-macro 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "25e4c606eb459dd29f7c57b2e0879f2b6f14ee130918c2b78ccb58a9624e6c7a" +"checksum crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "acec9a3b0b3559f15aee4f90746c4e5e293b701c0f7d3925d24e01645267b68c" +"checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4" +"checksum csv 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "00affe7f6ab566df61b4be3ce8cf16bc2576bca0963ceb0955e45d514bf9a279" "checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c" "checksum ctor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd8ce37ad4184ab2ce004c33bf6379185d3b1c95801cab51026bd271bf68eedc" "checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" +"checksum encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +"checksum float-cmp 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75224bec9bfe1a65e2d34132933f2de7fe79900c96a0174307554244ece8150e" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" +"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" "checksum ghost 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a36606a68532b5640dc86bb1f33c64b45c4682aad4c50f3937b317ea387f3d6" -"checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +"checksum halfbrown 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "f28ee31ba5bb3a3251606db26de2e807552c5f295429d03f756bdc4e00f54c7a" +"checksum hashbrown 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8e6073d0ca812575946eb5f35ff68dbe519907b25c42530389ff946dc84c6ead" +"checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772" +"checksum humantime 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b9b6c53306532d3c8e8087b44e6580e10db51a023cf9b433cea2ac38066b92da" "checksum indoc 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3f9553c1e16c114b8b77ebeb329e5f2876eed62a8d51178c8bc6bff0d65f98f8" "checksum indoc-impl 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b714fc08d0961716390977cdff1536234415ac37b509e34e5a983def8340fb75" -"checksum inventory 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f4cece20baea71d9f3435e7bbe9adf4765f091c5fe404975f844006964a71299" -"checksum inventory-impl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2869bf972e998977b1cb87e60df70341d48e48dca0823f534feb91ea44adaf9" -"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" -"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" +"checksum inventory 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2bf98296081bd2cb540acc09ef9c97f22b7e487841520350293605db1b2c7a27" +"checksum inventory-impl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0a8e30575afe28eea36a9a39136b70b2fb6b0dd0a212a5bd1f30a498395c0274" +"checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" "checksum keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" -"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" -"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" +"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" +"checksum memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3197e20c7edb283f87c071ddfc7a2cca8f8e0b888c242959846a6fce03c72223" +"checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" "checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" "checksum paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "423a519e1c6e828f1e73b720f9d9ed2fa643dce8a7737fb43235ce0b41eeaa49" "checksum paste-impl 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4214c9e912ef61bf42b81ba9a47e8aad1b2ffaf739ab162bf96d1e011f54e6c5" "checksum pdqselect 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ec91767ecc0a0bbe558ce8c9da33c068066c57ecc8bb8477ef8c1ad3ef77c27" "checksum permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b687ff7b5da449d39e418ad391e5e08da53ec334903ddbb921db208908fc372c" "checksum proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "ecd45702f76d6d3c75a80564378ae228a85f0b59d2f3ed43c91b4a69eb2ebfc5" -"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" -"checksum pyo3 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a00f96312ebe4082db7d93ad062df1818f597660002541c1bbae6752ec583244" -"checksum pyo3-derive-backend 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1a7caa60cb986fca5b488e29d078fb25ae228e01dab080b855168ce061bbef0a" -"checksum pyo3cls 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5ccfa624ed9b5d805079f1ad64b3f1de5d551a946d4cf494f1f032b5572d39f" -"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" +"checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548" +"checksum pyo3 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e1bfe257586436fbe1296d917f14a167d4253d0873bf43e2c9b9bdd58a3f9f35" +"checksum pyo3-derive-backend 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4882d8237fd8c7373cc25cb802fe0dab9ff70830fd56f47ef6c7f3f287fcc057" +"checksum pyo3cls 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fdf321cfab555f7411298733c86d21e5136f5ded13f5872fabf9de3337beecda" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" -"checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" +"checksum regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b5508c1941e4e7cb19965abef075d35a9a8b5cdf0846f30b4050e9b55dc55e87" "checksum regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "92b73c2a1770c255c240eaa4ee600df1704a38dc3feaa6e949e7fcd4f8dc09f9" -"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" -"checksum rstar 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08c3cf91d6318ed050a8dda79bc857665f9c3d41524b6f70bbd0396c5d9d662d" +"checksum regex-syntax 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e734e891f5b408a29efbf8309e656876276f49ab6a6ac208600b4419bd893d90" +"checksum rstar 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0650eaaa56cbd1726fd671150fce8ac6ed9d9a25d1624430d7ee9d196052f6b6" +"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" "checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" -"checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd" -"checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e" -"checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2" +"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" +"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" +"checksum serde_json 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)" = "eab8f15f15d6c41a154c1b128a22f2dfabe350ef53c40953d84e36155c91192b" "checksum sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" +"checksum simd-json 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fb65296b57a8709ea32a87cefc0e1099cdd407ee3aed89114af11c74ab86f7bf" "checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" -"checksum strsim 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "032c03039aae92b350aad2e3779c352e104d919cb192ba2fabbd7b831ce4f0f6" -"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" -"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" +"checksum strsim 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" +"checksum syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5" +"checksum termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72b620c5ea021d75a735c943269bb07d30c9b77d6ac6b236bc8b5c496ef05625" +"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" "checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum unindent 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "63f18aa3b0e35fed5a0048f029558b1518095ffe2a0a31fb87c93dece93a4993" "checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" +"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index edeebf7..40f1ec1 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,26 +1,37 @@ [package] name = "ed_lrr" -version = "0.0.0" +version = "0.2.0" authors = ["Daniel Seiller "] edition = "2018" repository = "https://gitlab.com/Earthnuker/ed_lrr.git" license = "WTFPL" - [lib] crate-type = ["cdylib"] name = "_ed_lrr" + +[[bin]] +name = "galaxy_test" +path = "src/galaxy.rs" + +[profile.release] +codegen-units = 1 +lto = true + [dependencies] -pyo3 = { version = "0.8.0", features = ["extension-module"] } -csv = "1.1.1" -serde = { version = "1.0.101", features = ["derive"] } -humantime = "1.3.0" +pyo3 = { version = "0.8.5", features = ["extension-module"] } +csv = "1.1.3" +serde = { version = "1.0.104", features = ["derive"] } +humantime = "2.0.0" permutohedron = "0.2.4" -serde_json = "1.0.40" +serde_json = "1.0.45" fnv = "1.0.6" -bincode = "1.2.0" +bincode = "1.2.1" sha3 = "0.8.2" byteorder = "1.3.2" -strsim = "0.9.2" -rstar = "0.5.1" +strsim = "0.9.3" +rstar = "0.7.1" +crossbeam-channel = "0.4.0" +simd-json = "0.2.3" +better-panic = "0.2.0" diff --git a/rust/src/common.rs b/rust/src/common.rs index b8fa857..0d5f4fe 100644 --- a/rust/src/common.rs +++ b/rust/src/common.rs @@ -1,5 +1,60 @@ +use crate::route::Router; use serde::{Deserialize, Serialize}; use std::cmp::Ordering; +use std::collections::HashMap; +use std::path::PathBuf; + +pub fn find_matches( + path: &PathBuf, + names: Vec, + exact: bool +) -> Result)>, String> { + let mut best: HashMap)> = HashMap::new(); + for name in &names { + best.insert(name.to_string(), (0.0, None)); + } + let mut reader = match csv::ReaderBuilder::new().from_path(path) { + Ok(rdr) => rdr, + Err(e) => { + return Err(format!("Error opening {}: {}", path.to_str().unwrap(), e).to_string()); + } + }; + let systems = reader.deserialize::(); + for sys in systems { + let sys = sys.unwrap(); + for name in &names { + best.entry(name.clone()).and_modify(|ent| { + if (exact)&&(&sys.system==name) { + *ent = (1.0, Some(sys.clone().build())) + } else { + let d1 = strsim::normalized_levenshtein(&sys.system, &name); + let d2 = strsim::normalized_levenshtein(&sys.body, &name); + if d1 > ent.0 { + *ent = (d1, Some(sys.clone().build())) + } else if d2 > ent.0 { + *ent = (d2, Some(sys.clone().build())) + } + } + + }); + } + } + Ok(best) +} + +#[derive(Debug, Clone,Copy, Serialize, Deserialize)] +pub struct TreeNode { + pub id: u32, + pub pos: [f32; 3], + pub mult: f32, +} + +impl TreeNode { + pub fn get(&self,router:&Router) -> Option { + let mut cache = router.cache.as_ref().unwrap().lock().unwrap(); + cache.get(self.id) + } +} #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SystemSerde { @@ -15,17 +70,25 @@ pub struct SystemSerde { } impl SystemSerde { - pub fn build(&self) -> System { + pub fn build(self) -> System { System { id: self.id, - star_type: self.star_type.clone(), - system: self.system.clone(), - body: self.body.clone(), + star_type: self.star_type, + system: self.system, + body: self.body, mult: self.mult, distance: self.distance, pos: [self.x, self.y, self.z], } } + + pub fn to_node(&self) -> TreeNode { + TreeNode { + id: self.id, + pos: [self.x, self.y, self.z], + mult: self.mult, + } + } } #[derive(Debug, Clone, Deserialize, Serialize)] @@ -39,6 +102,16 @@ pub struct System { pub pos: [f32; 3], } +impl System { + pub fn to_node(&self) -> TreeNode { + TreeNode { + id: self.id, + pos: self.pos, + mult: self.mult, + } + } +} + impl Ord for System { fn cmp(&self, other: &Self) -> Ordering { self.id.cmp(&other.id) diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 3f64052..1508f8a 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -1,45 +1,58 @@ -extern crate strsim; +#![deny(warnings)] mod common; mod preprocess; mod route; -use common::{System, SystemSerde}; +use std::path::PathBuf; +use common::find_matches; use pyo3::exceptions::*; use pyo3::prelude::*; use pyo3::types::{PyDict, PyList}; -use std::collections::HashMap; -use std::path::PathBuf; -fn find_matches( - path: &PathBuf, - names: Vec, -) -> Result)>, String> { - let mut best: HashMap)> = HashMap::new(); - for name in &names { - best.insert(name.to_string(), (0.0, None)); +enum SysEntry { + ID(u32), + Name(String), +} + +impl From<&str> for SysEntry { + fn from(s: &str) -> SysEntry { + if let Ok(n) = s.parse() { + SysEntry::ID(n) + } else { + SysEntry::Name(s.to_owned()) + } } - let mut reader = match csv::ReaderBuilder::new().from_path(path) { - Ok(rdr) => rdr, - Err(e) => { - return Err(format!("Error opening {}: {}", path.to_str().unwrap(), e).to_string()); +} + +fn resolve(entries: &Vec, path: &PathBuf) -> Result,String> { + let mut names: Vec = Vec::new(); + let mut ids: Vec = Vec::new(); + let mut ret: Vec = Vec::new(); + for ent in entries { + match ent { + SysEntry::Name(name) => names.push(name.to_owned()), + SysEntry::ID(id) => ids.push(*id), } }; - let systems = reader.deserialize::(); - for sys in systems { - let sys = sys.unwrap(); - for name in &names { - best.entry(name.clone()).and_modify(|ent| { - let d1 = strsim::normalized_levenshtein(&sys.system, &name); - if d1 > ent.0 { - *ent = (d1, Some(sys.build())) + let name_ids = find_matches(path, names, false)?; + for ent in entries { + match ent { + SysEntry::Name(name) => { + let ent_res=name_ids.get(&name.to_owned()).ok_or(format!("System {} not found",name))?; + let sys=ent_res.1.as_ref().ok_or(format!("System {} not found",name))?; + if ent_res.0<0.75 { + println!("WARNING: {} match to {} with low confidence ({}%)",name,sys.system,ent_res.0*100.0); } - }); + ret.push(sys.id); + } + SysEntry::ID(id) => ret.push(*id), } } - Ok(best) + return Ok(ret); } #[pymodule] pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> { + better_panic::install(); /// preprocess(infile_systems, infile_bodies, outfile, callback) /// -- /// @@ -75,14 +88,14 @@ pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> { Ok(state.to_object(py)) } - ///find_sys(sys_names,sys_list) + ///find_sys(sys_names, sys_list_path) /// -- /// /// Find system by name #[pyfn(m, "find_sys")] fn find_sys(py: Python, sys_names: Vec, sys_list: String) -> PyResult { let path = PathBuf::from(sys_list); - match find_matches(&path, sys_names) { + match find_matches(&path, sys_names,false) { Ok(vals) => { let ret = PyDict::new(py); for (key, (diff, sys)) in vals { @@ -104,15 +117,15 @@ pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> { } } - /// route(infile, hops, range, radius_mult, mode,primary, greedyness, precomp, callback) + /// route(hops, range, prune, mode, primary, permute, keep_first, keep_last, greedyness, precomp, path, num_workers, callback) /// -- /// /// Compute a Route using the suplied parameters #[pyfn(m, "route")] #[allow(clippy::too_many_arguments)] - fn route( + fn py_route( py: Python<'static>, - hops: Vec, + hops: Vec<&str>, range: f32, prune: Option<(usize, f32)>, mode: String, @@ -123,9 +136,11 @@ pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> { greedyness: Option, precomp: Option, path: String, + num_workers: Option, callback: PyObject, ) -> PyResult { use route::*; + let num_workers=num_workers.unwrap_or(1); let mode = match Mode::parse(&mode) { Ok(val) => val, Err(e) => { @@ -133,7 +148,12 @@ pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> { } }; let state_dict = PyDict::new(py); - callback.call(py, (state_dict,), None).unwrap(); + { + let cb_res = callback.call(py, (state_dict,), None); + if cb_res.is_err() { + println!("Error: {:?}",cb_res); + } + } let callback_wrapped = move |state: &SearchState| { state_dict.set_item("mode", state.mode.clone())?; state_dict.set_item("system", state.system.clone())?; @@ -147,14 +167,22 @@ pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> { state_dict.set_item("prc_seen", state.prc_seen)?; state_dict.set_item("from", state.from.clone())?; state_dict.set_item("to", state.to.clone())?; - callback.call(py, (state_dict,), None) + let cb_res=callback.call(py, (state_dict,), None); + if cb_res.is_err() { + println!("Error: {:?}",cb_res); + } + cb_res + }; + let hops: Vec = hops.iter().cloned().map(SysEntry::from).collect(); + println!("Resolving systems..."); + let hops: Vec = match resolve(&hops,&PathBuf::from(&path)) { + Ok(ids) => ids, + Err(err_msg) => { + return Err(PyErr::new::(err_msg)); + } }; - let mut systems = Vec::new(); - for sys in hops { - systems.push(route::SysEntry::parse(&sys)) - } let opts = RouteOpts { - systems, + systems: hops, range: Some(range), file_path: PathBuf::from(path), precomp_file: precomp.map(PathBuf::from), @@ -167,6 +195,7 @@ pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> { keep_last, primary, prune, + workers: num_workers }; let none = ().to_object(py); match route(opts) { diff --git a/rust/src/preprocess.rs b/rust/src/preprocess.rs index 5474244..5363f2f 100644 --- a/rust/src/preprocess.rs +++ b/rust/src/preprocess.rs @@ -36,7 +36,6 @@ struct System { id64: i64, name: String, coords: Coords, - date: String, } #[derive(Debug)] diff --git a/rust/src/route.rs b/rust/src/route.rs index 03cf82a..3b5aab0 100644 --- a/rust/src/route.rs +++ b/rust/src/route.rs @@ -1,975 +1,1245 @@ -use crate::common::{System, SystemSerde}; -use core::cmp::Ordering; -use csv::StringRecord; -use fnv::{FnvHashMap, FnvHashSet}; -use humantime::format_duration; -use permutohedron::LexicalPermutation; -use pyo3::prelude::*; -use rstar::{PointDistance, RTree, RTreeObject, AABB}; -use sha3::{Digest, Sha3_256}; -use std::collections::VecDeque; -use std::fs::File; -use std::hash::{Hash, Hasher}; -use std::io::Seek; -use std::io::{BufRead, BufReader, BufWriter, Write}; -use std::path::PathBuf; -use std::time::Instant; - -#[derive(Debug)] -pub struct SearchState { - pub mode: String, - pub system: String, - pub body: String, - pub from: String, - pub to: String, - pub depth: usize, - pub queue_size: usize, - pub d_rem: f32, - pub d_total: f32, - pub prc_done: f32, - pub n_seen: usize, - pub prc_seen: f32, -} - -#[derive(Debug, Clone)] -pub enum SysEntry { - ID(u32), - Name(String), -} - -impl SysEntry { - pub fn parse(s: &str) -> SysEntry { - match s.parse() { - Ok(n) => SysEntry::ID(n), - _ => SysEntry::Name(s.to_owned()), - } - } -} - -pub struct RouteOpts { - pub range: Option, - pub file_path: PathBuf, - pub precomp_file: Option, - pub precompute: bool, - pub permute: bool, - pub primary: bool, - pub keep_first: bool, - pub keep_last: bool, - pub factor: Option, - pub mode: Mode, - pub prune: Option<(usize, f32)>, - pub systems: Vec, - pub callback: Box PyResult>, -} - -#[derive(Debug)] -pub enum Mode { - BFS, - Greedy, - AStar, -} - -impl Mode { - pub fn parse(s: &str) -> Result { - let s = s.to_lowercase(); - match s.as_ref() { - "bfs" => Ok(Mode::BFS), - "greedy" => Ok(Mode::Greedy), - "astar" => Ok(Mode::AStar), - _ => Err("Invalid Mode".to_string()), - } - } -} - -fn dist2(p1: &[f32; 3], p2: &[f32; 3]) -> f32 { - let dx = p1[0] - p2[0]; - let dy = p1[1] - p2[1]; - let dz = p1[2] - p2[2]; - - dx * dx + dy * dy + dz * dz -} - -fn dist(p1: &[f32; 3], p2: &[f32; 3]) -> f32 { - dist2(p1, p2).sqrt() -} - -fn fcmp(a: f32, b: f32) -> Ordering { - match (a, b) { - (x, y) if x.is_nan() && y.is_nan() => Ordering::Equal, - (x, _) if x.is_nan() => Ordering::Greater, - (_, y) if y.is_nan() => Ordering::Less, - (..) => a.partial_cmp(&b).unwrap(), - } -} - -impl System { - pub fn dist2(&self, p: &[f32; 3]) -> f32 { - dist2(&self.pos, p) - } - - pub fn distp(&self, p: &System) -> f32 { - dist(&self.pos, &p.pos) - } - pub fn distp2(&self, p: &System) -> f32 { - self.dist2(&p.pos) - } -} -impl PartialEq for System { - fn eq(&self, other: &Self) -> bool { - self.id == other.id - } -} - -impl Eq for System {} - -impl Hash for System { - fn hash(&self, state: &mut H) { - self.id.hash(state); - } -} - -impl RTreeObject for System { - type Envelope = AABB<[f32; 3]>; - - fn envelope(&self) -> Self::Envelope { - AABB::from_point(self.pos) - } -} - -impl PointDistance for System { - fn distance_2(&self, point: &[f32; 3]) -> f32 { - self.dist2(&point) - } -} - -fn hash_file(path: &PathBuf) -> Vec { - let mut hash_reader = BufReader::new(File::open(path).unwrap()); - let mut hasher = Sha3_256::new(); - std::io::copy(&mut hash_reader, &mut hasher).unwrap(); - hasher.result().iter().copied().collect() -} - -struct LineCache { - cache: Vec, - file: BufReader, - header: Option, -} - -impl LineCache { - pub fn new(path: &PathBuf) -> Option { - let idx_path = path.with_extension("idx"); - let cache = - bincode::deserialize_from(&mut BufReader::new(File::open(idx_path).ok()?)).ok()?; - let mut reader = BufReader::new(File::open(path).ok()?); - let header = Self::read_record(&mut reader); - let ret = Self { - file: reader, - cache, - header, - }; - Some(ret) - } - fn read_record(reader: &mut BufReader) -> Option { - let mut line = String::new(); - reader.read_line(&mut line).ok()?; - let v: Vec<_> = line.trim_end().split(',').collect(); - let rec = StringRecord::from(v); - Some(rec) - } - pub fn get(&mut self, id: u32) -> Option { - let pos = self.cache[id as usize]; - self.file.seek(std::io::SeekFrom::Start(pos)).ok()?; - let rec = Self::read_record(&mut self.file)?; - let sys: SystemSerde = rec.deserialize(self.header.as_ref()).unwrap(); - Some(sys.build()) - } -} - -pub struct Router { - tree: RTree, - scoopable: FnvHashSet, - pub route_tree: Option>, - cache: Option, - range: f32, - primary_only: bool, - path: PathBuf, - prune: Option<(usize, f32)>, - callback: Box PyResult>, -} - -impl Router { - pub fn new( - path: &PathBuf, - range: f32, - prune: Option<(usize, f32)>, - primary_only: bool, - callback: Box PyResult>, - ) -> Result { - let mut scoopable = FnvHashSet::default(); - let mut reader = match csv::ReaderBuilder::new().from_path(path) { - Ok(rdr) => rdr, - Err(e) => { - return Err(format!("Error opening {}: {}", path.to_str().unwrap(), e)); - } - }; - let t_load = Instant::now(); - println!("Loading {}...", path.to_str().unwrap()); - let systems: Vec = reader - .deserialize::() - .map(|res| res.unwrap()) - .filter(|sys| { - if primary_only { - sys.distance == 0 - } else { - true - } - }) - .map(|sys| { - if sys.mult > 1.0f32 { - scoopable.insert(sys.id); - } else { - for c in "KGBFOAM".chars() { - if sys.star_type.starts_with(c) { - scoopable.insert(sys.id); - break; - } - } - } - sys.build() - }) - .collect(); - let ret = Self { - tree: RTree::bulk_load(systems), - scoopable, - route_tree: None, - range, - primary_only, - cache: LineCache::new(path), - path: path.clone(), - callback, - prune, - }; - println!( - "{} Systems loaded in {}", - ret.tree.size(), - format_duration(t_load.elapsed()) - ); - Ok(ret) - } - - pub fn from_file( - filename: &PathBuf, - callback: Box PyResult>, - ) -> Result<(PathBuf, Self), String> { - let mut reader = BufReader::new(match File::open(&filename) { - Ok(fh) => fh, - Err(e) => { - return Err(format!( - "Error opening file {}: {}", - filename.to_str().unwrap(), - e - )) - } - }); - println!("Loading {}", filename.to_str().unwrap()); - let (primary, range, file_hash, path, route_tree): ( - bool, - f32, - Vec, - String, - FnvHashMap, - ) = match bincode::deserialize_from(&mut reader) { - Ok(res) => res, - Err(e) => { - return Err(format!( - "Error loading file {}: {}", - filename.to_str().unwrap(), - e - )) - } - }; - let path = PathBuf::from(path); - if hash_file(&path) != file_hash { - return Err("File hash mismatch!".to_string()); - } - let cache = LineCache::new(&path); - Ok(( - path.clone(), - Self { - tree: RTree::default(), - scoopable: FnvHashSet::default(), - route_tree: Some(route_tree), - range, - cache, - primary_only: primary, - path, - callback, - prune: None, - }, - )) - } - - fn points_in_sphere(&self, center: &[f32; 3], radius: f32) -> impl Iterator { - self.tree.locate_within_distance(*center, radius * radius) - } - - fn neighbours(&self, sys: &System, r: f32) -> impl Iterator { - self.points_in_sphere(&sys.pos, sys.mult * r) - } - - fn valid(&self, sys: &System) -> bool { - let scoopable = self.scoopable.contains(&sys.id); - return scoopable; - } - - pub fn best_multiroute( - &self, - waypoints: &[System], - range: f32, - keep: (bool, bool), - mode: Mode, - factor: f32, - ) -> Result, String> { - let mut best_score: f32 = std::f32::MAX; - let mut waypoints = waypoints.to_owned(); - let mut best_permutation_waypoints = waypoints.to_owned(); - let first = waypoints.first().cloned(); - let last = waypoints.last().cloned(); - println!("Finding best permutation of hops..."); - while waypoints.prev_permutation() {} - loop { - let c_first = waypoints.first().cloned(); - let c_last = waypoints.last().cloned(); - let valid = (keep.0 && (c_first == first)) && (keep.1 && (c_last == last)); - if valid { - let mut total_d = 0.0; - for pair in waypoints.windows(2) { - match pair { - [src, dst] => { - total_d += src.distp2(dst); - } - _ => return Err("Invalid routing parameters!".to_string()), - } - } - if total_d < best_score { - best_score = total_d; - best_permutation_waypoints = waypoints.to_owned(); - } - } - if !waypoints.next_permutation() { - break; - } - } - println!("Best permutation: {:?}", best_permutation_waypoints); - self.multiroute(&best_permutation_waypoints, range, mode, factor) - } - - pub fn multiroute( - &self, - waypoints: &[System], - range: f32, - mode: Mode, - factor: f32, - ) -> Result, String> { - let mut route: Vec = Vec::new(); - for pair in waypoints.windows(2) { - match pair { - [src, dst] => { - let d_total=dist(&src.pos,&dst.pos); - println!("Plotting route from [{}] to [{}]...", src.system, dst.system); - println!( - "Jump Range: {} Ly, Distance: {} Ly, Estimated Jumps: {}", - range, - d_total, - d_total / range - ); - let block = match mode { - Mode::BFS => self.route_bfs(&src, &dst, range)?, - Mode::Greedy => self.route_greedy(&src, &dst, range)?, - Mode::AStar => self.route_astar(&src, &dst, range, factor)?, - }; - if route.is_empty() { - for sys in block.iter() { - route.push(sys.clone()); - } - } else { - for sys in block.iter().skip(1) { - route.push(sys.clone()); - } - } - } - _ => { - return Err("Invalid routing parameters!".to_owned()); - } - } - } - Ok(route) - } - - fn resolve_systems(&self, systems: &[SysEntry]) -> Result, String> { - let mut ret = Vec::new(); - let mut sys_by_id: FnvHashMap = FnvHashMap::default(); - let mut sys_by_name: FnvHashMap = FnvHashMap::default(); - for sys in &self.tree { - for ent in systems { - match ent { - SysEntry::ID(i) => { - let i = *i; - if sys.id == i { - sys_by_id.insert(i, sys); - } - } - SysEntry::Name(n) => { - if &sys.body == n || &sys.system == n { - sys_by_name.insert(n.to_string(), sys); - } - } - } - } - } - for ent in systems { - match ent { - SysEntry::ID(i) => match sys_by_id.get(i) { - Some(sys) => ret.push((*sys).clone()), - None => { - return Err(format!("System: {:?} not found", ent)); - } - }, - SysEntry::Name(n) => match sys_by_name.get(n) { - Some(sys) => ret.push((*sys).clone()), - None => { - return Err(format!("System: {:?} not found", ent)); - } - }, - } - } - Ok(ret) - } - - pub fn route_astar( - &self, - src: &System, - dst: &System, - range: f32, - factor: f32, - ) -> Result, String> { - if factor == 0.0 { - return self.route_bfs(src, dst, range); - } - let src_name = src.system.clone(); - let dst_name = dst.system.clone(); - let start_sys = src; - let goal_sys = dst; - let d_total = dist(&start_sys.pos, &goal_sys.pos); - let mut d_rem = d_total; - - let mut state = SearchState { - mode: "A-Star".into(), - depth: 0, - queue_size: 0, - d_rem: d_total, - d_total, - prc_done: 0.0, - n_seen: 0, - prc_seen: 0.0, - from: src_name.clone(), - to: dst_name.clone(), - body: start_sys.body.clone(), - system: start_sys.system.clone(), - }; - let total = self.tree.size() as f32; - let mut t_last = Instant::now(); - let mut prev = FnvHashMap::default(); - let mut seen = FnvHashSet::default(); - let mut found = false; - let mut queue: Vec<(usize, usize, &System)> = Vec::new(); - queue.push(( - 0, // depth - (start_sys.distp(goal_sys) / range) as usize, // h - &start_sys, - )); - seen.insert(start_sys.id); - while !found { - while let Some((depth, _, sys)) = queue.pop() { - if t_last.elapsed().as_millis() > 100 { - t_last = Instant::now(); - state.depth = depth; - state.queue_size = queue.len(); - state.prc_done = ((d_total - d_rem) * 100f32) / d_total; - state.d_rem = d_rem; - state.n_seen = seen.len(); - state.prc_seen = ((seen.len() * 100) as f32) / total; - state.body = sys.body.clone(); - state.system = sys.system.clone(); - match (self.callback)(&state) { - Ok(_) => (), - Err(e) => { - return Err(format!("{:?}", e).to_string()); - } - }; - } - if sys.id == goal_sys.id { - found = true; - break; - } - queue.extend( - self.neighbours(&sys, range) - .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))) - .filter(|&nb| seen.insert(nb.id)) - .map(|nb| { - prev.insert(nb.id, sys); - let d_g = nb.distp(goal_sys); - if d_g < d_rem { - d_rem = d_g; - } - (depth + 1, (d_g / range) as usize, nb) - }), - ); - queue.sort_by(|b, a| { - let (a_0, a_1) = (a.0 as f32, a.1 as f32); - let (b_0, b_1) = (b.0 as f32, b.1 as f32); - let v_a = a_0 + a_1 * factor; - let v_b = b_0 + b_1 * factor; - fcmp(v_a, v_b) - }); - // queue.reverse(); - } - if queue.is_empty() { - break; - } - } - println!(); - - println!(); - if !found { - return Err(format!("No route from {} to {} found!", src_name, dst_name)); - } - let mut v: Vec = Vec::new(); - let mut curr_sys = goal_sys; - loop { - v.push(curr_sys.clone()); - match prev.get(&curr_sys.id) { - Some(sys) => curr_sys = *sys, - None => { - break; - } - } - } - v.reverse(); - Ok(v) - } - - pub fn route_greedy( - &self, - src: &System, - dst: &System, - range: f32, - ) -> Result, String> { - let src_name = src.system.clone(); - let dst_name = dst.system.clone(); - let start_sys = src; - let goal_sys = dst; - let d_total = dist(&start_sys.pos, &goal_sys.pos); - let mut d_rem = d_total; - let mut state = SearchState { - mode: "Greedy".into(), - depth: 0, - queue_size: 0, - d_rem: d_total, - d_total, - prc_done: 0.0, - n_seen: 0, - prc_seen: 0.0, - from: src_name.clone(), - to: dst_name.clone(), - body: start_sys.body.clone(), - system: start_sys.system.clone(), - }; - let total = self.tree.size() as f32; - let mut t_last = Instant::now(); - let mut prev = FnvHashMap::default(); - let mut seen = FnvHashSet::default(); - let mut found = false; - let mut queue: Vec<(f32, usize, &System)> = Vec::new(); - queue.push((start_sys.distp(goal_sys), 0, &start_sys)); - seen.insert(start_sys.id); - while !found { - while let Some((_, depth, sys)) = queue.pop() { - if t_last.elapsed().as_millis() > 100 { - t_last = Instant::now(); - state.depth = depth; - state.queue_size = queue.len(); - state.prc_done = ((d_total - d_rem) * 100f32) / d_total; - state.d_rem = d_rem; - state.n_seen = seen.len(); - state.prc_seen = ((seen.len() * 100) as f32) / total; - state.body = sys.body.clone(); - state.system = sys.system.clone(); - match (self.callback)(&state) { - Ok(_) => (), - Err(e) => { - return Err(format!("{:?}", e).to_string()); - } - }; - } - if sys.id == goal_sys.id { - found = true; - break; - } - queue.extend( - self.neighbours(&sys, range) - .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id))) - .filter(|&nb| seen.insert(nb.id)) - .map(|nb| { - prev.insert(nb.id, sys); - let d_g = nb.distp(goal_sys); - if d_g < d_rem { - d_rem = d_g; - } - (d_g, depth + 1, nb) - }), - ); - queue.sort_by(|a, b| fcmp(a.0, b.0).then(a.1.cmp(&b.1))); - queue.reverse(); - } - if queue.is_empty() { - break; - } - } - if !found { - return Err(format!("No route from {} to {} found!", src_name, dst_name)); - } - let mut v: Vec = Vec::new(); - let mut curr_sys = goal_sys; - loop { - v.push(curr_sys.clone()); - match prev.get(&curr_sys.id) { - Some(sys) => curr_sys = *sys, - None => { - break; - } - } - } - v.reverse(); - Ok(v) - } - - pub fn precompute(&mut self, src: &System) -> Result<(), String> { - let total = self.tree.size() as f32; - let t_start = Instant::now(); - let mut prev = FnvHashMap::default(); - let mut seen = FnvHashSet::default(); - let mut depth = 0; - let mut queue: VecDeque<(usize, &System)> = VecDeque::new(); - let mut queue_next: VecDeque<(usize, &System)> = VecDeque::new(); - queue.push_front((0, &src)); - seen.insert(src.id); - while !queue.is_empty() { - print!( - "[{}] Depth: {}, Queue: {}, Seen: {} ({:.02}%) \r", - format_duration(t_start.elapsed()), - depth, - queue.len(), - seen.len(), - ((seen.len() * 100) as f32) / total - ); - std::io::stdout().flush().unwrap(); - while let Some((d, sys)) = queue.pop_front() { - queue_next.extend( - self.neighbours(&sys, self.range) - // .filter(|&nb| self.valid(nb)) - .filter(|&nb| seen.insert(nb.id)) - .map(|nb| { - prev.insert(nb.id, sys.id); - (d + 1, nb) - }), - ); - } - std::mem::swap(&mut queue, &mut queue_next); - depth += 1; - } - self.route_tree = Some(prev); - let ofn = format!( - "{}_{}{}.router", - src.system.replace("*", "").replace(" ", "_"), - self.range, - if self.primary_only { "_primary" } else { "" } - ); - let mut out_fh = BufWriter::new(File::create(&ofn).unwrap()); - let data = ( - self.primary_only, - self.range, - hash_file(&self.path), - String::from(self.path.to_str().unwrap()), - self.route_tree.as_ref().unwrap(), - ); - match bincode::serialize_into(&mut out_fh, &data) { - Ok(_) => Ok(()), - Err(e) => Err(format!("Error: {}", e).to_string()), - } - } - - fn get_systems_by_ids( - &mut self, - path: &PathBuf, - ids: &[u32], - ) -> Result, String> { - let mut ret = FnvHashMap::default(); - if let Some(c) = &mut self.cache.as_mut() { - let mut missing = false; - for id in ids { - match c.get(*id) { - Some(sys) => { - ret.insert(*id, sys); - } - None => { - missing = true; - break; - } - } - } - if !missing { - return Ok(ret); - } - } - let mut reader = match csv::ReaderBuilder::new().from_path(path) { - Ok(reader) => reader, - Err(e) => { - return Err(format!("Error opening {}: {}", path.to_str().unwrap(), e)); - } - }; - reader - .deserialize::() - .map(|res| res.unwrap()) - .filter(|sys| ids.contains(&sys.id)) - .map(|sys| { - ret.insert(sys.id, sys.build()); - }) - .count(); - for id in ids { - if !ret.contains_key(&id) { - return Err(format!("ID {} not found", id)); - } - } - Ok(ret) - } - - pub fn route_to( - &mut self, - dst: &System, - systems_path: &PathBuf, - ) -> Result, String> { - let prev = self.route_tree.as_ref().unwrap(); - if !prev.contains_key(&dst.id) { - return Err(format!("System-ID {} not found", dst.id).to_string()); - }; - let mut v_ids: Vec = Vec::new(); - let mut v: Vec = Vec::new(); - let mut curr_sys: u32 = dst.id; - loop { - v_ids.push(curr_sys); - match prev.get(&curr_sys) { - Some(sys_id) => curr_sys = *sys_id, - None => { - break; - } - } - } - v_ids.reverse(); - let id_map = self.get_systems_by_ids(&systems_path, &v_ids)?; - for sys_id in v_ids { - let sys = match id_map.get(&sys_id) { - Some(sys) => sys, - None => { - return Err(format!("System-ID {} not found!", sys_id)); - } - }; - v.push(sys.clone()) - } - Ok(v) - } - - pub fn route_bfs( - &self, - start_sys: &System, - goal_sys: &System, - range: f32, - ) -> Result, String> { - println!("Running BFS"); - let min_improvement = self.prune.map(|v| (v.0,v.1*range)).unwrap_or_else(|| (0,0.0)); - let src_name = start_sys.system.clone(); - let dst_name = goal_sys.system.clone(); - let d_total = dist(&start_sys.pos, &goal_sys.pos); - let mut d_rem = d_total; - let mut state = SearchState { - mode: "BFS".into(), - depth: 0, - queue_size: 0, - d_rem, - d_total, - prc_done: 0.0, - n_seen: 0, - prc_seen: 0.0, - from: src_name.clone(), - to: dst_name.clone(), - system: start_sys.system.clone(), - body: start_sys.body.clone(), - }; - let total = self.tree.size() as f32; - let mut prev: FnvHashMap = FnvHashMap::default(); - let mut prune_map: FnvHashMap = FnvHashMap::default(); - let mut seen = FnvHashSet::default(); - let mut depth = 0; - let mut found = false; - let mut t_last = Instant::now(); - let mut queue: VecDeque<(usize, &System)> = VecDeque::new(); - let mut queue_next: VecDeque<(usize, &System)> = VecDeque::new(); - queue.push_front((0, &start_sys)); - seen.insert(start_sys.id); - while !found { - while let Some((d, sys)) = queue.pop_front() { - if sys.id == goal_sys.id { - found = true; - break; - } - if t_last.elapsed().as_millis() > 100 { - state.depth = depth; - state.queue_size = queue.len(); - state.prc_done = ((d_total - d_rem) * 100f32) / d_total; - state.d_rem = d_rem; - state.n_seen = seen.len(); - state.prc_seen = ((seen.len() * 100) as f32) / total; - { - let s = queue.get(0).unwrap().1; - state.system = s.system.clone(); - state.body = s.body.clone(); - } - match (self.callback)(&state) { - Ok(_) => (), - Err(e) => { - return Err(format!("{:?}", e).to_string()); - } - }; - t_last = Instant::now(); - } - if self.prune.is_some() { - let best_dist = if let Some(p_sys) = prev.get(&sys.id) { - dist2(&p_sys.pos, &goal_sys.pos).min( - prune_map - .get(&p_sys.id) - .map(|v| v.1) - .unwrap_or(std::f32::MAX), - ) - } else { - dist2(&sys.pos, &goal_sys.pos) - }; - prune_map.insert(sys.id, (depth, best_dist)); - } - // TODO: check improvement, if too small: continue - queue_next.extend( - self.neighbours(&sys, range) - .filter(|&nb| { - (self.valid(nb) || (nb.id == goal_sys.id)) - }) - .filter(|&nb| seen.insert(nb.id)) - .map(|nb| { - prev.insert(nb.id, sys); - let dist = nb.distp(goal_sys); - if dist < d_rem { - d_rem = dist; - } - (d + 1, nb) - }), - ); - } - std::mem::swap(&mut queue, &mut queue_next); - if queue.is_empty() { - break; - } - depth += 1; - } - println!(); - println!(); - if !found { - return Err(format!("No route from {} to {} found!", src_name, dst_name)); - } - let mut v: Vec = Vec::new(); - let mut curr_sys = goal_sys; - loop { - v.push(curr_sys.clone()); - match prev.get(&curr_sys.id) { - Some(sys) => curr_sys = *sys, - None => { - break; - } - } - } - v.reverse(); - Ok(v) - } -} -pub fn route(opts: RouteOpts) -> Result>, String> { - // TODO: implement pruning (check if dist to target improved by at least $n*jump_range$ Ly in the last $m$ steps) - if opts.systems.is_empty() { - if opts.precomp_file.is_some() { - return Err("Error: Please specify exatly one system".to_owned()); - } else if opts.precompute { - return Err("Error: Please specify at least one system".to_owned()); - } else { - return Err("Error: Please specify at least two systems".to_owned()); - }; - } - let mut path = opts.file_path; - let mut router: Router = if opts.precomp_file.is_some() { - let (path_, ret) = - Router::from_file(&opts.precomp_file.clone().unwrap(), Box::new(opts.callback))?; - path = path_; - ret - } else if opts.range.is_some() { - Router::new( - &path, - opts.range.unwrap(), - opts.prune, - opts.primary, - Box::new(opts.callback), - )? - } else { - Router::new( - &path, - opts.range.unwrap(), - opts.prune, - opts.primary, - opts.callback, - )? - }; - let systems: Vec = router.resolve_systems(&opts.systems)?.to_vec(); - if opts.precompute { - for sys in systems { - router.route_tree = None; - router.precompute(&sys)?; - } - return Ok(None); - } - let route = if router.route_tree.is_some() { - router.route_to(systems.first().unwrap(), &path)? - } else if opts.permute { - router.best_multiroute( - &systems, - opts.range.unwrap(), - (opts.keep_first, opts.keep_last), - opts.mode, - opts.factor.unwrap_or(1.0), - )? - } else { - router.multiroute( - &systems, - opts.range.unwrap(), - opts.mode, - opts.factor.unwrap_or(1.0), - )? - }; - if route.is_empty() { - return Err("No route found!".to_string()); - } - Ok(Some(route)) -} +use crate::common::{System, SystemSerde, TreeNode}; +use core::cmp::Ordering; +use crossbeam_channel::{ + bounded, unbounded, Receiver, SendError, Sender, TryIter, +}; +use fnv::{FnvHashMap, FnvHashSet}; +use humantime::format_duration; +use permutohedron::LexicalPermutation; +use pyo3::prelude::*; +use rstar::{PointDistance, RStarInsertionStrategy, RTree, RTreeObject, RTreeParams, AABB}; +use sha3::{Digest, Sha3_256}; +use std::collections::VecDeque; +use std::fs::File; +use std::hash::{Hash, Hasher}; +use std::io::{BufReader, BufWriter, Write}; +use std::path::PathBuf; +use std::sync::{Arc, Mutex}; +use std::thread; +use std::thread::JoinHandle; +use std::time::Instant; + +const STATUS_INVERVAL: u128 = 500; //ms + +#[derive(Debug)] +pub struct SearchState { + pub mode: String, + pub system: String, + pub body: String, + pub from: String, + pub to: String, + pub depth: usize, + pub queue_size: usize, + pub d_rem: f32, + pub d_total: f32, + pub prc_done: f32, + pub n_seen: usize, + pub prc_seen: f32, +} + +pub struct RouteOpts { + pub range: Option, + pub file_path: PathBuf, + pub precomp_file: Option, + pub precompute: bool, + pub permute: bool, + pub primary: bool, + pub keep_first: bool, + pub keep_last: bool, + pub factor: Option, + pub mode: Mode, + pub prune: Option<(usize, f32)>, + pub systems: Vec, + pub callback: Box PyResult>, + pub workers: usize, +} + +#[derive(Debug)] +#[allow(non_camel_case_types)] +pub enum Mode { + BFS, + BFS_old, + Greedy, + AStar, +} + +impl Mode { + pub fn parse(s: &str) -> Result { + let s = s.to_lowercase(); + match s.as_ref() { + "bfs" => Ok(Mode::BFS), + "bfs_old" => Ok(Mode::BFS_old), + "greedy" => Ok(Mode::Greedy), + "astar" => Ok(Mode::AStar), + val => Err(format!("Invalid Mode: {}", val)), + } + } +} + +fn dist2(p1: &[f32; 3], p2: &[f32; 3]) -> f32 { + let dx = p1[0] - p2[0]; + let dy = p1[1] - p2[1]; + let dz = p1[2] - p2[2]; + + dx * dx + dy * dy + dz * dz +} + +fn dist(p1: &[f32; 3], p2: &[f32; 3]) -> f32 { + dist2(p1, p2).sqrt() +} + +fn fcmp(a: f32, b: f32) -> Ordering { + match (a, b) { + (x, y) if x.is_nan() && y.is_nan() => Ordering::Equal, + (x, _) if x.is_nan() => Ordering::Greater, + (_, y) if y.is_nan() => Ordering::Less, + (..) => a.partial_cmp(&b).unwrap(), + } +} + +impl System { + pub fn dist2(&self, p: &[f32; 3]) -> f32 { + dist2(&self.pos, p) + } + + pub fn distp(&self, p: &System) -> f32 { + dist(&self.pos, &p.pos) + } + pub fn distp2(&self, p: &System) -> f32 { + self.dist2(&p.pos) + } +} + +impl TreeNode { + pub fn dist2(&self, p: &[f32; 3]) -> f32 { + dist2(&self.pos, p) + } + + pub fn distp(&self, p: &System) -> f32 { + dist(&self.pos, &p.pos) + } +} + +impl PartialEq for System { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + } +} + +impl Eq for System {} + +impl Hash for System { + fn hash(&self, state: &mut H) { + self.id.hash(state); + } +} + +impl RTreeObject for TreeNode { + type Envelope = AABB<[f32; 3]>; + + fn envelope(&self) -> Self::Envelope { + AABB::from_point(self.pos) + } +} + +impl PointDistance for TreeNode { + fn distance_2(&self, point: &[f32; 3]) -> f32 { + self.dist2(&point) + } +} + +fn hash_file(path: &PathBuf) -> Vec { + let mut hash_reader = BufReader::new(File::open(path).unwrap()); + let mut hasher = Sha3_256::new(); + std::io::copy(&mut hash_reader, &mut hasher).unwrap(); + hasher.result().iter().copied().collect() +} + +pub struct LineCache { + cache: Vec, + reader: csv::Reader, +} + +impl LineCache { + pub fn new(path: &PathBuf) -> Option>> { + let idx_path = path.with_extension("idx"); + let cache = + bincode::deserialize_from(&mut BufReader::new(File::open(idx_path).ok()?)).ok()?; + let reader = csv::Reader::from_path(path).ok()?; + let ret = Self { reader, cache }; + Some(Arc::new(Mutex::new(ret))) + } + + fn read_sys(&mut self) -> Option { + Some( + self.reader + .deserialize() + .next() + .expect("Failed to read SystemSerde") + .expect("Failed to parse SystemSerde"), + ) + } + + pub fn get(&mut self, id: u32) -> Option { + let mut pos = csv::Position::new(); + pos.set_byte(self.cache[id as usize]); + self.reader.seek(pos).ok()?; + let sys = self.read_sys().map(SystemSerde::build); + // println!("{} {:?}",id,&sys); + sys + } +} + +pub struct LargeNodeParameters; +impl RTreeParams for LargeNodeParameters { + const MIN_SIZE: usize = 200; + const MAX_SIZE: usize = 400; + const REINSERTION_COUNT: usize = 100; + type DefaultInsertionStrategy = RStarInsertionStrategy; +} + +// Optional but helpful: Define a type alias for the new r-tree +pub type LargeNodeRTree = RTree; + +#[derive(Debug, Clone)] +struct WorkUnit { + node: TreeNode, + depth: usize, + parent_id: Option, +} + +#[derive(Debug)] +enum WorkerSet { + Empty, + Workers { + handles: Vec>, + tx: Sender>, + rx: Receiver, + }, +} + +fn neighbor_worker( + tree: &LargeNodeRTree, + search_range: f32, + rx: Receiver>, + tx: Sender, +) { + while let Ok(Some(unit)) = rx.recv() { + let range=search_range*unit.node.mult; + tree.locate_within_distance(unit.node.pos, range*range) + .cloned() + .for_each(|nb| { + let wu = WorkUnit { + node: nb, + depth: unit.depth + 1, + parent_id: Some(unit.node.id), + }; + tx.send(wu).unwrap(); + }); + } + drop(tx); +} + +impl WorkerSet { + fn new(tree: Arc>, search_range: f32, num_workers: usize) -> Self { + if num_workers == 0 { + return WorkerSet::Empty; + } + let (jobs_tx, jobs_rx) = unbounded(); + let (result_tx, result_rx) = bounded(100_000); + let handles = (0..num_workers) + .map(|_| { + thread::spawn({ + let rx = jobs_rx.clone(); + let tx = result_tx.clone(); + let tree = tree.clone(); + move || { + neighbor_worker(&tree, search_range, rx, tx); + } + }) + }) + .collect(); + return WorkerSet::Workers { + handles, + tx: jobs_tx, + rx: result_rx, + }; + } + + fn close(self) -> Result<(),String> { + if let WorkerSet::Workers{mut handles,tx,rx} = self { + let t_start=Instant::now(); + loop { + if (rx.len()==0) && (tx.len()==0) { + break; + } + rx.try_iter().for_each(|_| {}); + }; + for _ in &handles { + match tx.send(None) { + Ok(_) => {}, + Err(e) => { + return Err(format!("{:?}",e)); + } + } + }; + drop(tx); + while let Some(handle)= handles.pop() { + handle.join().unwrap(); + } + drop(rx); + println!("cleared in {}",format_duration(t_start.elapsed())); + } + return Ok(()); + } + + fn queue_size(&self) -> usize { + match self { + WorkerSet::Empty => 0, + WorkerSet::Workers{rx,tx,..} => tx.len() + rx.len() + } + } + + fn queue_empty(&self) -> bool { + return self.queue_size()==0; + } + + fn send(&self, wu: WorkUnit) -> Result<(), SendError>> { + match self { + WorkerSet::Empty => { + panic!("send() on empty WorkerSet"); + } + WorkerSet::Workers { tx, .. } => { + return tx.send(Some(wu)); + } + } + } + + fn num(&self) -> usize { + match self { + WorkerSet::Empty => 1, + WorkerSet::Workers { handles, .. } => handles.len(), + } + } + + fn is_empty(&self) -> bool { + match self { + WorkerSet::Empty => true, + WorkerSet::Workers { handles, .. } => handles.len() == 0, + } + } + + // impl Iterator + + fn iter(&self) -> Result,String> { + match self { + WorkerSet::Empty => { + Err("can't iterate on empty WorkerSet".to_string()) + } + WorkerSet::Workers { rx, .. } => { + Ok(rx.try_iter()) + } + } + } + + // fn join(mut self) -> thread::Result<()> { + // drop(self.tx); + // drop(self.rx); + // let ret: thread::Result> = self.handles.drain(..).map(|v| v.join()).collect(); + // ret?; + // return Ok(()); + // } +} + +pub struct Router { + tree: Arc>, + scoopable: FnvHashSet, + pub route_tree: Option>, + pub cache: Option>>, + range: f32, + primary_only: bool, + path: PathBuf, + prune: Option<(usize, f32)>, + workers: WorkerSet, + callback: Box PyResult>, +} + +impl Router { + pub fn new( + path: &PathBuf, + range: f32, + prune: Option<(usize, f32)>, + primary_only: bool, + num_workers: usize, + callback: Box PyResult>, + ) -> Result { + let mut scoopable = FnvHashSet::default(); + let mut reader = match csv::ReaderBuilder::new().from_path(path) { + Ok(rdr) => rdr, + Err(e) => { + return Err(format!("Error opening {}: {}", path.display(), e)); + } + }; + let t_load = Instant::now(); + println!("Loading {}...", path.display()); + let systems: Vec = reader + .deserialize::() + .filter_map(|res| { + let sys = res.expect("Failed to read"); + if primary_only && sys.distance != 0 { + return None; + }; + if sys.mult > 1.0f32 { + scoopable.insert(sys.id); + } else { + for c in "KGBFOAM".chars() { + if sys.star_type.starts_with(c) { + scoopable.insert(sys.id); + break; + } + } + } + Some(sys.to_node()) + }) + .collect(); + println!( + "{} Systems loaded in {}", + systems.len(), + format_duration(t_load.elapsed()) + ); + let t_load = Instant::now(); + let tree = Arc::new(LargeNodeRTree::bulk_load_with_params(systems)); + let workers = WorkerSet::new(Arc::clone(&tree), range, num_workers); + println!("R*-Tree built in {}", format_duration(t_load.elapsed())); + let ret = Self { + tree, + scoopable, + route_tree: None, + range, + primary_only, + cache: LineCache::new(path), + path: path.clone(), + callback, + prune, + workers, + }; + Ok(ret) + } + + pub fn from_file( + filename: &PathBuf, + callback: Box PyResult>, + ) -> Result<(PathBuf, Self), String> { + let mut reader = BufReader::new(match File::open(&filename) { + Ok(fh) => fh, + Err(e) => { + return Err(format!( + "Error opening file {}: {}", + filename.display(), + e + )) + } + }); + println!("Loading {}", filename.display()); + let (primary, range, file_hash, path, route_tree): ( + bool, + f32, + Vec, + PathBuf, + FnvHashMap, + ) = match bincode::deserialize_from(&mut reader) { + Ok(res) => res, + Err(e) => { + return Err(format!( + "Error loading file {}: {}", + filename.display(), + e + )) + } + }; + if hash_file(&path) != file_hash { + return Err("File hash mismatch!".to_string()); + } + let cache = LineCache::new(&path); + Ok(( + path.clone(), + Self { + tree: Arc::new(RTree::default()), + scoopable: FnvHashSet::default(), + route_tree: Some(route_tree), + range, + cache, + primary_only: primary, + path, + callback, + prune: None, + workers: WorkerSet::Empty, + }, + )) + } + + fn points_in_sphere(&self, center: &[f32; 3], radius: f32) -> impl Iterator { + self.tree.locate_within_distance(*center, radius * radius) + } + + fn neighbours(&self, node: &TreeNode) -> impl Iterator { + self.points_in_sphere(&node.pos, node.mult * self.range) + } + + fn valid(&self, id: u32) -> bool { + let scoopable = self.scoopable.contains(&id); + return scoopable; + } + + pub fn best_multiroute( + &self, + waypoints: &[System], + keep: (bool, bool), + mode: Mode, + factor: f32, + ) -> Result, String> { + let mut best_score: f32 = std::f32::MAX; + let mut waypoints = waypoints.to_owned(); + let mut best_permutation_waypoints = waypoints.to_owned(); + let first = waypoints.first().cloned(); + let last = waypoints.last().cloned(); + println!("Finding best permutation of hops..."); + while waypoints.prev_permutation() {} + loop { + let c_first = waypoints.first().cloned(); + let c_last = waypoints.last().cloned(); + let valid = (keep.0 && (c_first == first)) && (keep.1 && (c_last == last)); + if valid { + let mut total_d = 0.0; + for pair in waypoints.windows(2) { + match pair { + [src, dst] => { + total_d += src.distp2(dst); + } + _ => return Err("Invalid routing parameters!".to_string()), + } + } + if total_d < best_score { + best_score = total_d; + best_permutation_waypoints = waypoints.to_owned(); + } + } + if !waypoints.next_permutation() { + break; + } + } + println!("Best permutation: {:?}", best_permutation_waypoints); + self.multiroute(&best_permutation_waypoints, mode, factor) + } + + pub fn multiroute( + &self, + waypoints: &[System], + mode: Mode, + factor: f32, + ) -> Result, String> { + let mut route: Vec = Vec::new(); + for pair in waypoints.windows(2) { + match pair { + [src, dst] => { + let d_total = dist(&src.pos, &dst.pos); + println!( + "Plotting route from [{}] to [{}]...", + src.system, dst.system + ); + println!( + "Jump Range: {} Ly, Distance: {} Ly, Estimated Jumps: {}", + self.range, + d_total, + d_total / self.range + ); + let block = match mode { + Mode::BFS => self.route_bfs(&src, &dst)?, + Mode::BFS_old => self.route_bfs_old(&src, &dst)?, + Mode::Greedy => self.route_greedy(&src, &dst)?, + Mode::AStar => self.route_astar(&src, &dst, factor)?, + }; + if route.is_empty() { + for sys in block.iter() { + route.push(sys.clone()); + } + } else { + for sys in block.iter().skip(1) { + route.push(sys.clone()); + } + } + } + _ => { + return Err("Invalid routing parameters!".to_owned()); + } + } + } + Ok(route) + } + + pub fn route_astar( + &self, + src: &System, + dst: &System, + factor: f32, + ) -> Result, String> { + if factor == 0.0 { + return self.route_bfs(src, dst); + } + let src_name = src.system.clone(); + let dst_name = dst.system.clone(); + let start_sys = src; + let goal_sys = dst; + let d_total = dist(&start_sys.pos, &goal_sys.pos); + let mut d_rem = d_total; + + let mut state = SearchState { + mode: "A-Star".into(), + depth: 0, + queue_size: 0, + d_rem: d_total, + d_total, + prc_done: 0.0, + n_seen: 0, + prc_seen: 0.0, + from: src_name.clone(), + to: dst_name.clone(), + body: start_sys.body.clone(), + system: start_sys.system.clone(), + }; + let total = self.tree.size() as f32; + let mut t_last = Instant::now(); + let mut prev = FnvHashMap::default(); + let mut seen = FnvHashSet::default(); + let mut found = false; + let mut queue: Vec<(usize, usize, TreeNode)> = Vec::new(); + queue.push(( + 0, // depth + (start_sys.distp(goal_sys) / self.range) as usize, // h + start_sys.to_node(), + )); + seen.insert(start_sys.id); + while !found { + while let Some((depth, _, node)) = queue.pop() { + if t_last.elapsed().as_millis() > STATUS_INVERVAL { + let sys = node + .get(&self) + .expect(&format!("System-ID {} not found!", node.id)); + t_last = Instant::now(); + state.depth = depth; + state.queue_size = queue.len(); + state.prc_done = ((d_total - d_rem) * 100f32) / d_total; + state.d_rem = d_rem; + state.n_seen = seen.len(); + state.prc_seen = ((seen.len() * 100) as f32) / total; + state.body = sys.body.clone(); + state.system = sys.system.clone(); + match (self.callback)(&state) { + Ok(_) => (), + Err(e) => { + return Err(format!("{:?}", e).to_string()); + } + }; + } + if node.id == goal_sys.id { + queue.clear(); + found = true; + break; + } + queue.extend( + self.neighbours(&node) + .filter(|nb| (self.valid(nb.id) || (nb.id == goal_sys.id))) + .filter(|nb| seen.insert(nb.id)) + .map(|nb| { + prev.insert(nb.id, node); + let d_g = nb.distp(goal_sys); + if d_g < d_rem { + d_rem = d_g; + } + (depth + 1, (d_g / self.range) as usize, *nb) + }), + ); + queue.sort_by(|b, a| { + let (a_0, a_1) = (a.0 as f32, a.1 as f32); + let (b_0, b_1) = (b.0 as f32, b.1 as f32); + let v_a = a_0 + a_1 * factor; + let v_b = b_0 + b_1 * factor; + fcmp(v_a, v_b) + }); + // queue.reverse(); + } + if queue.is_empty() { + break; + } + } + println!(); + + println!(); + if !found { + return Err(format!("No route from {} to {} found!", src_name, dst_name)); + } + let mut v: Vec = Vec::new(); + let mut curr_sys = goal_sys.clone(); + loop { + v.push(curr_sys.clone()); + match prev.get(&curr_sys.id) { + Some(sys) => curr_sys = sys.get(&self).unwrap(), + None => { + break; + } + } + } + v.reverse(); + Ok(v) + } + + pub fn route_greedy(&self, src: &System, dst: &System) -> Result, String> { + let src_name = src.system.clone(); + let dst_name = dst.system.clone(); + let start_sys = src; + let goal_sys = dst; + let d_total = dist(&start_sys.pos, &goal_sys.pos); + let mut d_rem = d_total; + let mut state = SearchState { + mode: "Greedy".into(), + depth: 0, + queue_size: 0, + d_rem: d_total, + d_total, + prc_done: 0.0, + n_seen: 0, + prc_seen: 0.0, + from: src_name.clone(), + to: dst_name.clone(), + body: start_sys.body.clone(), + system: start_sys.system.clone(), + }; + let total = self.tree.size() as f32; + let mut t_last = Instant::now(); + let mut prev = FnvHashMap::default(); + let mut seen = FnvHashSet::default(); + let mut found = false; + let mut queue: Vec<(f32, usize, TreeNode)> = Vec::new(); + queue.push((start_sys.distp(goal_sys), 0, start_sys.to_node())); + seen.insert(start_sys.id); + while !found { + while let Some((_, depth, node)) = queue.pop() { + if t_last.elapsed().as_millis() > STATUS_INVERVAL { + let sys = node + .get(&self) + .expect(&format!("System-ID {} does not exist!", &node.id)); + t_last = Instant::now(); + state.depth = depth; + state.queue_size = queue.len(); + state.prc_done = ((d_total - d_rem) * 100f32) / d_total; + state.d_rem = d_rem; + state.n_seen = seen.len(); + state.prc_seen = ((seen.len() * 100) as f32) / total; + state.body = sys.body.clone(); + state.system = sys.system.clone(); + match (self.callback)(&state) { + Ok(_) => (), + Err(e) => { + return Err(format!("{:?}", e).to_string()); + } + }; + } + if node.id == goal_sys.id { + queue.clear(); + found = true; + break; + } + queue.extend( + self.neighbours(&node) + .filter(|nb| (self.valid(nb.id) || (nb.id == goal_sys.id))) + .filter(|nb| seen.insert(nb.id)) + .map(|nb| { + prev.insert(nb.id, node); + let d_g = nb.distp(goal_sys); + if d_g < d_rem { + d_rem = d_g; + } + (d_g, depth + 1, nb.clone()) + }), + ); + queue.sort_by(|a, b| fcmp(a.0, b.0).then(a.1.cmp(&b.1))); + queue.reverse(); + } + if queue.is_empty() { + break; + } + } + if !found { + return Err(format!("No route from {} to {} found!", src_name, dst_name)); + } + let mut v: Vec = Vec::new(); + let mut curr_sys = goal_sys.clone(); + loop { + v.push(curr_sys.clone()); + match prev.get(&curr_sys.id) { + Some(sys) => curr_sys = sys.get(&self).unwrap(), + None => { + break; + } + } + } + v.reverse(); + Ok(v) + } + + pub fn precompute(&mut self, src: &System) -> Result<(), String> { + let total = self.tree.size() as f32; + let t_start = Instant::now(); + let mut prev = FnvHashMap::default(); + let mut seen = FnvHashSet::default(); + let mut depth = 0; + let mut queue: VecDeque<(usize, TreeNode)> = VecDeque::new(); + let mut queue_next: VecDeque<(usize, TreeNode)> = VecDeque::new(); + queue.push_front((0, src.to_node())); + seen.insert(src.id); + while !queue.is_empty() { + print!( + "[{}] Depth: {}, Queue: {}, Seen: {} ({:.02}%) \r", + format_duration(t_start.elapsed()), + depth, + queue.len(), + seen.len(), + ((seen.len() * 100) as f32) / total + ); + std::io::stdout().flush().unwrap(); + while let Some((d, sys)) = queue.pop_front() { + queue_next.extend( + self.neighbours(&sys) + // .filter(|&nb| self.valid(nb)) + .filter(|&nb| seen.insert(nb.id)) + .map(|nb| { + prev.insert(nb.id, sys.id); + (d + 1, nb.clone()) + }), + ); + } + std::mem::swap(&mut queue, &mut queue_next); + depth += 1; + } + self.route_tree = Some(prev); + let ofn = format!( + "{}_{}{}.router", + src.system.replace("*", "").replace(" ", "_"), + self.range, + if self.primary_only { "_primary" } else { "" } + ); + let mut out_fh = BufWriter::new(File::create(&ofn).unwrap()); + let data = ( + self.primary_only, + self.range, + hash_file(&self.path), + self.path.clone(), + self.route_tree.as_ref().unwrap(), + ); + match bincode::serialize_into(&mut out_fh, &data) { + Ok(_) => Ok(()), + Err(e) => Err(format!("Error: {}", e).to_string()), + } + } + + fn get_sys(&self, id: u32) -> Result, String> { + let path = &self.path; + if let Some(c) = &self.cache { + let mut c = c.lock().unwrap(); + match c.get(id) { + Some(sys) => { + return Ok(Some(sys)); + } + None => {} + } + } + let mut reader = match csv::ReaderBuilder::new().from_path(path) { + Ok(reader) => reader, + Err(e) => { + return Err(format!("Error opening {}: {}", path.display(), e)); + } + }; + println!("Running serial search for ID: {:?}", id); + return Ok(reader + .deserialize::() + .map(|res| res.unwrap()) + .filter(|sys| sys.id == id) + .map(|sys| sys.build()) + .last()); + } + + fn get_systems_by_ids(&self, ids: &[u32]) -> Result, String> { + let path = &self.path; + let mut ret = FnvHashMap::default(); + if let Some(c) = &self.cache { + let mut c = c.lock().unwrap(); + let mut missing = false; + for id in ids { + match c.get(*id) { + Some(sys) => { + ret.insert(*id, sys); + } + None => { + missing = true; + break; + } + } + } + if !missing { + return Ok(ret); + } + } + let mut reader = match csv::ReaderBuilder::new().from_path(path) { + Ok(reader) => reader, + Err(e) => { + return Err(format!("Error opening {}: {}", path.display(), e)); + } + }; + println!("Running serial search for IDs: {:?}", ids); + reader + .deserialize::() + .map(|res| res.unwrap()) + .filter(|sys| ids.contains(&sys.id)) + .map(|sys| { + ret.insert(sys.id, sys.build()); + }) + .count(); + for id in ids { + if !ret.contains_key(&id) { + return Err(format!("ID {} not found", id)); + } + } + Ok(ret) + } + + pub fn route_to(&self, dst: &System) -> Result, String> { + let prev = self.route_tree.as_ref().unwrap(); + if !prev.contains_key(&dst.id) { + return Err(format!("System-ID {} not found", dst.id).to_string()); + }; + let mut v_ids: Vec = Vec::new(); + let mut v: Vec = Vec::new(); + let mut curr_sys: u32 = dst.id; + loop { + v_ids.push(curr_sys); + match prev.get(&curr_sys) { + Some(sys_id) => curr_sys = *sys_id, + None => { + break; + } + } + } + v_ids.reverse(); + let id_map = self.get_systems_by_ids(&v_ids)?; + for sys_id in v_ids { + let sys = match id_map.get(&sys_id) { + Some(sys) => sys, + None => { + return Err(format!("System-ID {} not found!", sys_id)); + } + }; + v.push(sys.clone()) + } + Ok(v) + } + + pub fn route_bfs(&self, start_sys: &System, goal_sys: &System) -> Result, String> { + if self.workers.is_empty() { + return self.route_bfs_old(start_sys, goal_sys); + } + println!("Running BFS with {} worker(s)", self.workers.num()); + let t_start = Instant::now(); + let mut t_last = Instant::now(); + let mut prev = FnvHashMap::default(); + let mut seen = FnvHashSet::default(); + let src_name = start_sys.system.clone(); + let dst_name = goal_sys.system.clone(); + let workers = &self.workers; + let wu = WorkUnit { + node: start_sys.to_node(), + parent_id: None, + depth: 0, + }; + if wu.node.id==goal_sys.id { + return Ok(vec![goal_sys.clone()]); + } + let mut found = false; + let total = self.tree.size() as f32; + let d_total = dist(&start_sys.pos, &goal_sys.pos); + let mut d_rem = d_total; + let mut state = SearchState { + mode: "BFS".into(), + depth: 0, + queue_size: 0, + d_rem, + d_total, + prc_done: 0.0, + n_seen: 0, + prc_seen: 0.0, + from: src_name.clone(), + to: dst_name.clone(), + system: start_sys.system.clone(), + body: start_sys.body.clone(), + }; + seen.insert(wu.node.id); + workers.send(wu).unwrap(); + loop { + if found { + break; + } + let num_seen = seen.len(); + let mut nbs: Vec<_> = workers + .iter()? + .filter(|wu| !found && seen.insert(wu.node.id)) + .filter(|wu| wu.parent_id.is_some()) + .inspect(|wu| { + if t_last.elapsed().as_millis() > STATUS_INVERVAL { + let dist = wu.node.distp(goal_sys); + if dist < d_rem { + d_rem = dist; + }; + state.depth = wu.depth; + state.queue_size = workers.queue_size(); + state.prc_done = ((d_total - d_rem) * 100f32) / d_total; + state.d_rem = d_rem; + state.n_seen = num_seen; + state.prc_seen = ((num_seen * 100) as f32) / total; + { + let s = wu.node.get(&self).unwrap(); + state.system = s.system.clone(); + state.body = s.body.clone(); + } + match (self.callback)(&state) { + Ok(_) => (), + Err(e) => { + println!("CB_ERROR: {:?}", e); + } + }; + t_last = Instant::now(); + } + }) + .collect(); + if nbs.is_empty() && workers.queue_empty() && seen.len()>1 { + break; + } + // nbs.sort_by(|a, b| { + // let d_a=a.node.dist2(&goal_sys.pos); + // let d_b=b.node.dist2(&goal_sys.pos); + // return a.depth.cmp(&b.depth).then(fcmp(d_a,d_b)); + // }); + while let Some(wu) = nbs.pop() { + if let Some(parent_id) = wu.parent_id { + prev.insert(wu.node.id, parent_id); + } + if wu.node.id == goal_sys.id { + found = true; + println!("FOUND!"); + break; + } + workers.send(wu).unwrap(); + } + } + println!(); + println!(); + println!("Took: {}", format_duration(t_start.elapsed())); + if !found { + return Err(format!("No route from {} to {} found!", src_name, dst_name)); + } + + let mut v: Vec = Vec::new(); + let mut curr_sys = goal_sys.clone(); + loop { + v.push(curr_sys.clone()); + match prev.get(&curr_sys.id) { + Some(sys) => { + curr_sys = self + .get_sys(*sys)? + .ok_or(format!("System id {} not found", sys))? + } + None => { + break; + } + } + } + v.reverse(); + Ok(v) + } + + pub fn route_bfs_old( + &self, + start_sys: &System, + goal_sys: &System, + ) -> Result, String> { + if start_sys.id==goal_sys.id { + return Ok(vec![goal_sys.clone()]); + } + let t_start = Instant::now(); + println!("Running BFS"); + if self.prune.is_some() { + println!("WARNING: search pruning is not implemented!"); + } + let src_name = start_sys.system.clone(); + let dst_name = goal_sys.system.clone(); + let d_total = dist(&start_sys.pos, &goal_sys.pos); + let mut d_rem = d_total; + let mut state = SearchState { + mode: "BFS_old".into(), + depth: 0, + queue_size: 0, + d_rem, + d_total, + prc_done: 0.0, + n_seen: 0, + prc_seen: 0.0, + from: src_name.clone(), + to: dst_name.clone(), + system: start_sys.system.clone(), + body: start_sys.body.clone(), + }; + let total = self.tree.size() as f32; + let mut prev = FnvHashMap::default(); + let mut seen = FnvHashSet::default(); + let mut depth = 0; + let mut found = false; + let mut t_last = Instant::now(); + let mut queue: VecDeque = VecDeque::new(); + let mut queue_next: VecDeque = VecDeque::new(); + queue.push_front(start_sys.to_node()); + seen.insert(start_sys.id); + while !found { + while let Some(node) = queue.pop_front() { + if node.id == goal_sys.id { + queue.clear(); + found = true; + break; + } + if t_last.elapsed().as_millis() > STATUS_INVERVAL { + state.depth = depth; + state.queue_size = queue.len() + queue_next.len(); + state.prc_done = ((d_total - d_rem) * 100f32) / d_total; + state.d_rem = d_rem; + state.n_seen = seen.len(); + state.prc_seen = ((seen.len() * 100) as f32) / total; + { + let s = queue.get(0).unwrap().get(&self).unwrap(); + state.system = s.system.clone(); + state.body = s.body.clone(); + } + match (self.callback)(&state) { + Ok(_) => (), + Err(e) => { + return Err(format!("{:?}", e).to_string()); + } + }; + t_last = Instant::now(); + } + let valid_nbs = self + .neighbours(&node) + .filter(|nb| (self.valid(nb.id) || (nb.id == goal_sys.id))) + .filter(|nb| seen.insert(nb.id)) + .map(|nb| { + prev.insert(nb.id, node); + let dist = nb.distp(goal_sys); + if dist < d_rem { + d_rem = dist; + }; + nb.clone() + }); + queue_next.extend(valid_nbs); + } + std::mem::swap(&mut queue, &mut queue_next); + if found { + break; + } + if queue.is_empty() { + break; + } + depth += 1; + } + println!(); + println!(); + println!("Took: {}", format_duration(t_start.elapsed())); + if !found { + return Err(format!("No route from {} to {} found!", src_name, dst_name)); + } + + let mut v: Vec = Vec::new(); + let mut curr_sys = goal_sys.clone(); + loop { + v.push(curr_sys.clone()); + match prev.get(&curr_sys.id) { + Some(sys) => curr_sys = sys.get(&self).unwrap(), + None => { + break; + } + } + } + v.reverse(); + Ok(v) + } +} + +pub fn route(opts: RouteOpts) -> Result>, String> { + // TODO: implement pruning (check if dist to target improved by at least $n*jump_range$ Ly in the last $m$ steps) + if opts.systems.is_empty() { + if opts.precomp_file.is_some() { + return Err("Error: Please specify exatly one system".to_owned()); + } else if opts.precompute { + return Err("Error: Please specify at least one system".to_owned()); + } else { + return Err("Error: Please specify at least two systems".to_owned()); + }; + } + let mut router: Router = if opts.precomp_file.is_some() { + let (_, ret) = + Router::from_file(&opts.precomp_file.clone().unwrap(), Box::new(opts.callback))?; + ret + } else if opts.range.is_some() { + Router::new( + &opts.file_path, + opts.range.unwrap(), + opts.prune, + opts.primary, + opts.workers, + Box::new(opts.callback), + )? + } else { + Router::new( + &opts.file_path, + opts.range.unwrap(), + opts.prune, + opts.primary, + opts.workers, + opts.callback, + )? + }; + let mut systems: Vec = Vec::new(); + let sys_ht = router.get_systems_by_ids(&opts.systems)?; + for sys in opts.systems { + systems.push(sys_ht.get(&sys).unwrap().clone()); + } + if opts.precompute { + for sys in systems { + router.route_tree = None; + router.precompute(&sys)?; + } + return Ok(None); + } + let route = if router.route_tree.is_some() { + router.route_to(systems.first().unwrap())? + } else if opts.permute { + router.best_multiroute( + &systems, + (opts.keep_first, opts.keep_last), + opts.mode, + opts.factor.unwrap_or(1.0), + )? + } else { + router.multiroute(&systems, opts.mode, opts.factor.unwrap_or(1.0))? + }; + router.workers.close()?; + if route.is_empty() { + return Err("No route found!".to_string()); + } + Ok(Some(route)) +} diff --git a/setup.py b/setup.py index 705d8d8..e1c9f3a 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,6 @@ from setuptools_rust import Binding, RustExtension, Strip with open("README.md", "r") as fh: long_description = fh.read() - setup( name="ed_lrr_gui", version_format="{tag}.dev{commitcount}+{gitsha}", @@ -22,6 +21,7 @@ setup( "_ed_lrr", path="rust/Cargo.toml", binding=Binding.PyO3, + rustc_flags=["--emit=asm"], strip=Strip.No, debug=False, native=True, @@ -40,6 +40,7 @@ setup( "PyQt5", "click-default-group", "profig", + "ujson", "colorama", "svgwrite", ], @@ -47,19 +48,25 @@ setup( "setuptools", "setuptools-rust", "wheel", - "pyinstaller", "pytest-runner", "setuptools-git-version", ], - tests_require=["pytest", "pytest-pep8", "pytest-cov"], extras_require={ - "dev": ["black", "pyinstaller", "jinja2", "tsp"], + "test": ["pytest", "pytest-cov", "pytest-dependency"], + "dev": ["black", "jinja2", "tsp"], "web": [ "flask", - "sqlalchemy", + "gevent", "webargs", + "flask-executor", + "flask-wtf", + "flask-user", + "flask-debugtoolbar", + "flask-bootstrap4", "flask-sqlalchemy", - "sqlalchemy-utils", + "flask-nav", + "flask-admin", + "sqlalchemy_utils[password]", ], }, classifiers=[ diff --git a/tox.ini b/tox.ini index 8bd1caa..5fbf146 100644 --- a/tox.ini +++ b/tox.ini @@ -1,18 +1,22 @@ [tox] -envlist = py35,py36,py37 -requires = tox-conda +envlist = py35-build,py36-build,py37-build,py38-build +requires = + tox-conda [testenv] +platform = win32 description = Build ED_LRR recreate = True skip_install = True skipsdist = True -deps = +deps = PyQt5 setuptools_rust + build: https://github.com/Nuitka/Nuitka/archive/develop.zip conda_deps = pycrypto - nuitka + ujson + dev: ipython passenv = CARGO_HOME RUSTUP_HOME @@ -24,11 +28,23 @@ whitelist_externals = cargo iscc cmd + powershell + conda conda_channels = conda-forge commands = python build_gui.py - pip install . - python -m nuitka --plugin-enable=multiprocessing --remove-output --plugin-enable=qt-plugins --standalone --assume-yes-for-downloads --follow-imports --output-dir=exe ed_lrr_gui\__main__.py - cmd /c rename exe\__main__.dist\__main__.exe ED_LRR.exe - iscc /F"ED_LRR_{envname}" /Qp installer/ED_LRR.iss \ No newline at end of file + + build: python -m pip install .[web] + build: python -m nuitka --remove-output --plugin-enable=multiprocessing --plugin-enable=qt-plugins --plugin-enable=gevent --standalone --assume-yes-for-downloads --follow-imports --output-dir=exe ed_lrr_gui\__main__.py + build: cmd /c rename exe\__main__.dist\__main__.exe ED_LRR.exe + build: iscc /F"ED_LRR_{envname}" /Qp installer/ED_LRR.iss + + install: python -m pip install -e .[dev,web,test] + + dev: python -m pip install -e .[dev,web,test] + dev: cmd /c echo install done now run "conda activate {envdir}" + + test: python -m pip install .[dev,web,test] + test: cargo test + test: pytest \ No newline at end of file