pathfinding-4.14.0/.cargo_vcs_info.json0000644000000001360000000000100134150ustar { "git": { "sha1": "ce4702c5795125218fdd10d523010d509d36713d" }, "path_in_vcs": "" }pathfinding-4.14.0/.github/renovate.json000064400000000000000000000001151046102023000162600ustar 00000000000000{ "extends": ["config:recommended", ":automergeMinor", ":automergePr"] } pathfinding-4.14.0/.github/stale.yml000064400000000000000000000012541046102023000154020ustar 00000000000000# Number of days of inactivity before an issue becomes stale daysUntilStale: 60 # Number of days of inactivity before a stale issue is closed daysUntilClose: 7 # Issues with these labels will never be considered stale exemptLabels: - pinned - security # Label to use when marking an issue as stale staleLabel: wontfix # Comment to post when marking an issue as stale. Set to `false` to disable markComment: > This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. # Comment to post when closing a stale issue. Set to `false` to disable closeComment: false pathfinding-4.14.0/.github/workflows/codspeed.yml000064400000000000000000000017051046102023000201160ustar 00000000000000name: CodSpeed Benchmarks on: push: branches: - main pull_request: jobs: benchmarks: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 name: Checkout - uses: actions/cache@v4 with: path: | ~/.cargo/registry ~/.cargo/git target key: ${{ runner.os }}-cargo-stable-${{ hashFiles('Cargo.toml') }} - uses: actions-rs/toolchain@v1 name: Install Rust toolchain with: profile: minimal toolchain: stable override: true - uses: baptiste0928/cargo-install@v3 name: Install cargo-codspeed (with cache) with: crate: cargo-codspeed - uses: actions-rs/cargo@v1 name: Build benchmarks with: command: codspeed args: build - uses: CodSpeedHQ/action@v3 name: Run benchmarks with: run: cargo codspeed run pathfinding-4.14.0/.github/workflows/pre-commit.yaml000064400000000000000000000003371046102023000205450ustar 00000000000000name: pre-commit on: pull_request: merge_group: jobs: pre-commit: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 - uses: pre-commit/action@v3.0.1 pathfinding-4.14.0/.github/workflows/tests.yml000064400000000000000000000056611046102023000174770ustar 00000000000000on: pull_request: merge_group: name: Continuous integration jobs: check: name: Check runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: sh tests/check-msrv-consistency.sh - run: | rustup install --profile minimal stable rustup default stable - uses: Swatinem/rust-cache@v2 - run: cargo check --all-targets cargo-deny: name: cargo deny runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: embarkStudios/cargo-deny-action@v2 test: name: Test suite runs-on: ubuntu-latest needs: check strategy: matrix: toolchain: [stable, beta, nightly, msrv] steps: - uses: actions/checkout@v4 name: Checkout - name: Install Rust toolchain run: | if [ ${{ matrix.toolchain }} = msrv ]; then toolchain=$(awk -F '"' '/^rust-version =/ {print $2}' Cargo.toml) else toolchain=${{ matrix.toolchain }} fi rustup install --profile minimal $toolchain rustup default $toolchain - uses: Swatinem/rust-cache@v2 - name: Test documentation in debug mode run: cargo test --doc - name: Test in debug mode run: cargo test --tests --benches test-release: name: Extra tests in release mode runs-on: ubuntu-latest needs: check steps: - uses: actions/checkout@v4 name: Checkout - run: | rustup install --profile minimal nightly rustup default nightly name: Install Rust toolchain - uses: Swatinem/rust-cache@v2 - name: Test documentation in release mode run: cargo test --doc --release - name: Test in release mode run: cargo test --release --tests --benches test-minimal-versions: name: Test with minimal versions runs-on: ubuntu-latest needs: check steps: - uses: actions/checkout@v4 name: Checkout - name: Install nightly (for -Z) and stable Rust toolchains run: | rustup install --profile minimal nightly rustup install --profile minimal stable rustup default stable - name: Set dependencies to the minimal version allowed run: cargo +nightly update -Zminimal-versions - uses: Swatinem/rust-cache@v2 - name: Test with minimal version dependencies and stable compiler run: cargo +stable test --tests --benches fmt: name: Rustfmt runs-on: ubuntu-latest needs: check steps: - uses: actions/checkout@v4 - run: rustup install --profile default stable - run: cargo +stable fmt --all -- --check clippy: name: Clippy runs-on: ubuntu-latest needs: check steps: - uses: actions/checkout@v4 - run: | rustup install --profile default nightly rustup default nightly - uses: Swatinem/rust-cache@v2 - run: cargo clippy --all-targets pathfinding-4.14.0/.gitignore000064400000000000000000000000711046102023000141730ustar 00000000000000target Cargo.lock mutants.out* flamegraph.svg perf.data* pathfinding-4.14.0/.gitlab-ci.yml000064400000000000000000000011511046102023000146370ustar 00000000000000image: rust stages: - lint - test cache: key: "$CI_JOB_NAME" paths: - /usr/local/rustup untracked: true .test_template: &cargo_test stage: test before_script: - rustup install $RUST script: - cargo +$RUST test --tests --examples stable: <<: *cargo_test variables: RUST: stable beta: <<: *cargo_test variables: RUST: beta nightly: <<: *cargo_test variables: RUST: nightly nightly_fmt: <<: *cargo_test stage: lint variables: RUST: nightly script: - rustup component add --toolchain $RUST rustfmt-preview - cargo +$RUST fmt --all -- --check pathfinding-4.14.0/.pre-commit-config.yaml000064400000000000000000000016211046102023000164660ustar 00000000000000default_language_version: python: python3 # Defaults to python2, so override it. repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.4.0 hooks: - id: check-added-large-files - id: check-byte-order-marker - id: check-case-conflict - id: check-merge-conflict - id: check-symlinks - id: check-toml - id: check-yaml - id: detect-private-key - id: end-of-file-fixer - id: forbid-submodules - id: mixed-line-ending args: ['--fix=lf'] - id: trailing-whitespace - repo: https://github.com/codespell-project/codespell rev: v2.2.2 hooks: - id: codespell args: ['--ignore-words-list', 'crate'] - repo: https://github.com/compilerla/conventional-pre-commit rev: v3.0.0 hooks: - id: conventional-pre-commit stages: [commit-msg] args: [feat, fix, chore, test] pathfinding-4.14.0/CHANGELOG.md000064400000000000000000000243071046102023000140240ustar 00000000000000 v4.14.0 / 2025-01-25 ================== * feat: implement bidirectional BFS * fix(dijkstra)!: remove unneeded partial cost parameter. This is a BREAKING CHANGE in `dijkstra_reach()` parameters, but fortunately very easy to fix for users. * chore: reorganize `rand` imports v4.13.1 / 2025-01-15 ================== * fix(perf): back out commit 808b951c5a9eb5dd25adbd46a5887525d0a0913d which causes a severe performance regression in Dijkstra algorithm * style: use `usize::div_ceil()` * feat(gitignore): ignore flame graph files * docs: cleanup some first line * chore(deps): update rust crate itertools to 0.14.0 * fix(clippy): put test module last in file * feat: accept `&(usize, usize)` as `Matrix` index * fix(style): use a less convoluted test v4.13.0 / 2024-12-29 ================== * feat: implement Bron-Kerbosch algorithm, thanks to @gzsombor * fix(style): use `unwrap_or_else` when appropriate * fix(style): use `Self` instead of the type name * fix(style): make some functions `const` v4.12.0 / 2024-12-10 ================== * fix(doc): reference `count_paths` from top-level documentation * fix(tests): remove `test_` prefix in tests * chore(Cargo): update fake regex dependency message * fix(deps): update rust crate thiserror to v2 * fix: use proper pattern binding * fix(deps): update codspeed-criterion-compat to get rid of advisory * fix(tests): new test for `utils` module * fix(ui): adapt UI tests to Rust 1.84 * chore(gitignore): ignore `cargo mutants` output * fix(tests): `gen` will be a keyword in Rust 2024 * fix(kruskal): accept owned data into the method * fix: remove or move `allow` attributes * style(matrix): remove unneeded bounds on `DoubleEndedIterator` impl * style: replace `let _ =` by `_ =` * docs: remove empty lines in comments * Add test for Yen's algorithm * Add precision on development process * feat(tests): test Edmonds-Karp failure in sparse mode * feat(dfs): use a non-recursive version * fix(benches): reinstate regular benches for DFS * fix!(dfs): never visit the same node twice * feat(benches): add restricted DFS benchmarks * style: use Iterator::inspect() when the value does not change * chore(deps): update rust crate codspeed-criterion-compat to v2 * fix!(msrv): update MSRV to 1.77.2 * Generic variant of connected_components * fix(doc): refer to `usize::MAX` instead of `std::usize::MAX` * chore(Cargo.toml): allow `clippy::too_long_first_doc_paragraph` v4.11.0 / 2024-08-31 ================== * feat(prim): add Prim's algorithm for finding MST * docs(astar): add documentation for SmallestCostHolder * fix(README): Broken link in the README.md * test: add more tests for `Grid` and `Matrix` * fix(cargo-deny): update configuration v4.10.0 / 2024-06-18 ================== * feat: replace `FixedBitSet` by `IndexSet` for better performances * chore(deps): update many dependencies for better performances * feat(tests): add new aoc-2023-17 test * fix(tests): do not build useless vector * fix: remove redundant imports v4.9.1 / 2024-02-12 ================== * fix(README): inline documentation to fix inner links to modules * fix(deps): update rust crate indexmap to 2.2.3 * fix(deps): update rust crate thiserror to 1.0.57 v4.9.0 / 2024-02-11 ================== * feat(matrix): add in-place matrix transposition for non-square matrix * feat(bench): add bench for matrix transposition * feat(tests): add a test for transposing an empty matrix * fix(deps): add priority to clippy lints for lint_groups_priority * chore(grid): replace deprecated IndexMap remove() method by swap_remove() * fix(deps): update rust crate num-traits to 0.2.18 * fix(deps): update rust crate indexmap to 2.2.2 * chore(deps): update rust crate itertools to 0.12.1 v4.8.2 / 2024-01-14 ================== * fix(dfs_reach): visit nodes in the documented order v4.8.1 / 2024-01-07 ================== * fix(yen): revert "Routes are already sorted by cost and path len" * test(yen): add test for checking Yen algorithm output ordering * chore(pre-commit): add conventional commit check * chore: use deprecate_until attribute instead of deprecated v4.8.0 / 2023-12-22 ================== * feat(matrix): add `Matrix::transpose()` * feat(matrix): add `Matrix::column_iter()` v4.7.0 / 2023-12-21 ================== * feat(grid): add `Grid::constrain()` * feat(matrix): add `Matrix::constrain()` * feat(utils): add `constrain()` v4.6.0 / 2023-12-14 ================== * feat(matrix): implement DoubleEndedIterator for RowIterator v4.5.0 / 2023-12-14 ================== * feat(matrix): add swap method * chore(msrv): update minimum required Rust version to 1.70.0 * chore: use bool::is_some_and v4.4.0 / 2023-11-30 ================== * feat: new `dijkstra_reach()` function * fix(doc): remove useless explicit links v4.3.4 / 2023-11-29 ================== * fix(edmondskarp): better panic messages * fix(matrix): better panic messages * fix(style): apply clippy fixes * fix(doc): typo v4.3.3 / 2023-11-13 ================== * fix(yen): return all loopless paths * chore(cargo deny): fix warning in configuration file * chore(deps): update rust crate indexmap to 2.1.0 * chore(deps): update rust crate thiserror to 1.0.50 * chore(deps): update rust crate regex to 1.10.2 * chore(deps): update rust crate num-traits to 0.2.17 v4.3.2 / 2023-09-22 ================== * New remaining_low_bounds() method for {Bfs,Dfs}Reachable * Migrate to the evenfurther GitHub organization * fix(deps): update rust crate thiserror to 1.0.48 * Use or_default() in test v4.3.1 / 2023-08-02 ================== * Move `cycle_detection` module into `directed` and deprecate the former * Update indexmap requirement from 1.9.2 to 2.0.0 * Style: use `or_default()` rather than `or_insert_with()` with default value * Style: do not use `bool::then()` in `filter_map()` * Style: make `partial_cmp` use `cmp` * Style: reformat with let/else support * Use codspeed-criterion-compat everywhere, do not require criterion v4.3.0 / 2023-05-30 ================== * Allow creating a Matrix based on a function from position to value * Make method cancel_flow of edmondskarp only cancel the minimum amount of flow among all edges along a path, instead of the maximum, in order to avoid negative flows * Use sort_unstable_by() instead of sort_unstable_by_key() * New Grid example for from_coordinates() method * Use RemSP and path splitting * Remove optimization which gives worst benchmark results * Integrate CodSpeed * Update criterion requirement from 0.4.0 to 0.5.1 * Make Kuhn-Munkres benchmarks reproducible v4.2.1 / 2023-01-17 ================== * Document that A*/Dijkstra/Fringe/idA* costs must be non-negative * Upgrade dependencies * Use new clippy lint name * Add bench for separate_components * Bench Kuhn-Munkres algorithm * Remove itertools dependency * Remove unnecessary .into_iter() in tests v4.2.0 / 2022-12-25 ================== * Add Grid::from_coordinates() * Add the possibility to display the grid with reversed line order * Add more Grid documentation v4.1.1 / 2022-12-14 ================== * Better performances in Grid, Kruskal and Edmonds-Karp v4.1.0 / 2022-12-14 ================== * Add Matrix::items() and Matrix::items_mut() * Rename Matrix::indices() as Matrix::keys() and deprecate Matrix::indices() * Clarify the ordering of coordinate tuples in Matrix * Add more Grid documentation * Enable clippy pedantic mode by default v4.0.1 / 2022-12-12 ================== * Improve bfs performance * Add documentation for possible errors and panics v4.0.0 / 2022-11-30 ================== * Add move_in_direction and in_direction to utils * Make some function const * Cleanups * Count paths * Add minimum_cut capability to EdmondsKarp * Bump MSRV to 1.65.0 * Update dependencies v3.0.14 / 2022-10-03 ================== * Use into_keys() where appropriate * Add fake regex dev dependency * Use boolean::then_some() * Update criterion requirement from 0.3.4 to 0.4.0 * Optimize Yen's algorithm * Routes are already sorted by cost and path len v3.0.13 / 2022-06-16 ================== * Document possibility of looping endlessly in kuhn_munkres related functions * Use matches!() to simplify expression v3.0.12 / 2022-04-13 ================== * Add two algorithms (Floyd and Brent) to detect cycles * Deprecate absdiff() in favor of Rust 1.60 abs_diff() * Remove double must-use v3.0.11 / 2022-03-11 ================== * Introduce `Grid::{bfs,dfs}_reachable()` and `deprecate Grid::reachable()` * Remove `Copy` bound on predicate of `Matrix::{bfs,dfs}_reachable()` * Use anonymous lifetimes when appropriate * Add example for `kuhn_munkres()` v3.0.10 / 2022-02-14 ==================== * Remove unused `Matrix::uninit`/`Matrix::assume_init()` * Remove remaining `debug_assert!()` calls v3.0.9 / 2022-02-02 =================== * Add conversion from `Matrix` to `Grid` * Add `Grid` equality * Add `Matrix::map()` v3.0.8 / 2022-01-24 =================== * Add `Matrix::new_uninit()` and `Matrix::assume_init()` * Forbid all missing or partially missing docs * Mark iterators as fused v3.0.7 / 2022-01-23 =================== * Deprecate `Matrix::reachable()` for `Matrix::bfs_reachable(`) and `Matrix::dfs_reachable()` * Add `dfs_reach()` * Use an enumeration to represent `MatrixFormatError` v3.0.6 / 2022-01-12 =================== * Add MSRV and check for consistency * Add `#[must_use]` on `Weights` trait * Use thiserror crate to build `MatrixFormatError` * Add an example for `Grid` as `Debug` v3.0.5 / 2021-12-13 =================== * Alternate `Grid` debug mode v3.0.4 / 2021-12-12 =================== * Add `Grid::reachable()` * Add `Matrix::get()` and `Matrix::get_mut()` v3.0.3 / 2021-12-09 =================== * Add `Matrix::reachable()` * Better `Matrix` corner cases documentation v3.0.2 / 2021-12-09 =================== * Remove references in `Grid` methods * Remove more references in `Matrix` methods v3.0.1 / 2021-12-09 =================== * Remove unnecessary `Clone` bounds v3.0.0 / 2021-12-09 =================== * Use tuples instead of tuples reference for `Matrix` index pathfinding-4.14.0/Cargo.lock0000644000000644000000000000100113740ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "aho-corasick" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5bce8d450891e3b36f85a2230cec441fddd60e0c455b61b15bb3ffba955ca85" dependencies = [ "memchr", ] [[package]] name = "anes" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5e04b263cb24d859f06563beb27213c7bbfff2c61513763578eba297f4314e4" [[package]] name = "anstyle" version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "autocfg" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" [[package]] name = "bumpalo" version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12ae9db68ad7fac5fe51304d20f016c911539251075a214f8e663babefa35187" [[package]] name = "cast" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cfg-if" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "ciborium" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0c137568cc60b904a7724001b35ce2630fd00d5d84805fbb608ab89509d788f" dependencies = [ "ciborium-io", "ciborium-ll", "serde", ] [[package]] name = "ciborium-io" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "346de753af073cc87b52b2083a506b38ac176a44cfb05497b622e27be899b369" [[package]] name = "ciborium-ll" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213030a2b5a4e0c0892b6652260cf6ccac84827b83a85a534e178e3906c4cf1b" dependencies = [ "ciborium-io", "half", ] [[package]] name = "clap" version = "4.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" version = "4.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73" dependencies = [ "anstyle", "clap_lex", ] [[package]] name = "clap_lex" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "codspeed" version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "450a0e9df9df1c154156f4344f99d8f6f6e69d0fc4de96ef6e2e68b2ec3bce97" dependencies = [ "colored", "libc", "serde_json", ] [[package]] name = "codspeed-criterion-compat" version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eb1a6cb9c20e177fde58cdef97c1c7c9264eb1424fe45c4fccedc2fb078a569" dependencies = [ "codspeed", "colored", "criterion", ] [[package]] name = "colored" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" dependencies = [ "lazy_static", "windows-sys 0.48.0", ] [[package]] name = "criterion" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" dependencies = [ "anes", "cast", "ciborium", "clap", "criterion-plot", "is-terminal", "itertools 0.10.5", "num-traits", "once_cell", "oorandom", "plotters", "rayon", "regex", "serde", "serde_derive", "serde_json", "tinytemplate", "walkdir", ] [[package]] name = "criterion-plot" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" dependencies = [ "cast", "itertools 0.10.5", ] [[package]] name = "crossbeam-deque" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "deprecate-until" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a3767f826efbbe5a5ae093920b58b43b01734202be697e1354914e862e8e704" dependencies = [ "proc-macro2", "quote", "semver", "syn 2.0.89", ] [[package]] name = "either" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5845bf77d497f79416df39462df26d4a8b71dd6440246848ee63709476dbb9a6" [[package]] name = "equivalent" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" [[package]] name = "getrandom" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee8025cf36f917e6a52cce185b7c7177689b838b7ec138364e50cc2277a56cf4" dependencies = [ "cfg-if 0.1.2", "libc", "wasi", ] [[package]] name = "glob" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "half" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d36fab90f82edc3c747f9d438e06cf0a491055896f2a279638bb5beed6c40177" [[package]] name = "hashbrown" version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" [[package]] name = "hermit-abi" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" [[package]] name = "indexmap" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", "hashbrown", ] [[package]] name = "integer-sqrt" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "276ec31bcb4a9ee45f58bec6f9ec700ae4cf4f4f8f2fa7e06cb406bd5ffdd770" dependencies = [ "num-traits", ] [[package]] name = "is-terminal" version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" dependencies = [ "hermit-abi", "libc", "windows-sys 0.52.0", ] [[package]] name = "itertools" version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] [[package]] name = "itertools" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" dependencies = [ "either", ] [[package]] name = "itoa" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2f3e61cf687687b30c9e6ddf0fc36cf15f035e66d491e6da968fa49ffa9a378" [[package]] name = "js-sys" version = "0.3.51" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83bdfbace3a0e81a4253f73b49e960b053e396a11012cbd49b9b74d6a2b67062" dependencies = [ "wasm-bindgen", ] [[package]] name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" version = "0.2.133" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0f80d65747a3e43d1596c7c5492d95d5edddaabd45a7fcdb02b95f644164966" [[package]] name = "log" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3a89a0c46ba789b8a247d4c567aed4d7c68e624672d238b45cc3ec20dc9f940" dependencies = [ "cfg-if 0.1.2", ] [[package]] name = "memchr" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76fc44e2588d5b436dbc3c6cf62aef290f90dab6235744a93dfe1cc18f451e2c" [[package]] name = "movingai" version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46532e7ddd9118e14913587872478478a9aca541a8c993a4d61449e98127914" [[package]] name = "noisy_float" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978fe6e6ebc0bf53de533cd456ca2d9de13de13856eda1518a285d7705a213af" dependencies = [ "num-traits", ] [[package]] name = "num-traits" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "once_cell" version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ea5043e58958ee56f3e15a90aee535795cd7dfd319846288d93c5b57d85cbe" [[package]] name = "oorandom" version = "11.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebcec7c9c2a95cacc7cd0ecb89d8a8454eca13906f6deb55258ffff0adeb9405" [[package]] name = "pathfinding" version = "4.14.0" dependencies = [ "codspeed-criterion-compat", "deprecate-until", "indexmap", "integer-sqrt", "itertools 0.14.0", "lazy_static", "movingai", "noisy_float", "num-traits", "rand", "rand_xorshift", "regex", "rustc-hash", "thiserror", "trybuild", "version_check", ] [[package]] name = "plotters" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a" dependencies = [ "num-traits", "plotters-backend", "plotters-svg", "wasm-bindgen", "web-sys", ] [[package]] name = "plotters-backend" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b07fffcddc1cb3a1de753caa4e4df03b79922ba43cf882acc1bdd7e8df9f4590" [[package]] name = "plotters-svg" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b38a02e23bd9604b842a812063aec4ef702b57989c37b655254bb61c471ad211" dependencies = [ "plotters-backend", ] [[package]] name = "ppv-lite86" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" [[package]] name = "proc-macro2" version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] [[package]] name = "rand" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", ] [[package]] name = "rand_chacha" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" dependencies = [ "ppv-lite86", "rand_core", ] [[package]] name = "rand_core" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" dependencies = [ "getrandom", ] [[package]] name = "rand_xorshift" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" dependencies = [ "rand_core", ] [[package]] name = "rayon" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", ] [[package]] name = "rayon-core" version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ "crossbeam-deque", "crossbeam-utils", ] [[package]] name = "regex" version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "rustc-hash" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" [[package]] name = "ryu" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" [[package]] name = "same-file" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3257af0472da4b8b8902102a57bafffd9991f0f43772a8af6153d597e6e4ae2" dependencies = [ "winapi", ] [[package]] name = "semver" version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" dependencies = [ "proc-macro2", "quote", "syn 2.0.89", ] [[package]] name = "serde_json" version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", "memchr", "ryu", "serde", ] [[package]] name = "serde_spanned" version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" dependencies = [ "serde", ] [[package]] name = "syn" version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6498a9efc342871f91cc2d0d694c674368b4ceb40f62b65a7a08c3792935e702" dependencies = [ "proc-macro2", "quote", "unicode-xid", ] [[package]] name = "syn" version = "2.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "termcolor" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" dependencies = [ "wincolor", ] [[package]] name = "thiserror" version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" dependencies = [ "proc-macro2", "quote", "syn 2.0.89", ] [[package]] name = "tinytemplate" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d3dc76004a03cec1c5932bca4cdc2e39aaa798e3f82363dd94f9adf6098c12f" dependencies = [ "serde", "serde_json", ] [[package]] name = "toml" version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", "toml_datetime", "toml_edit", ] [[package]] name = "toml_datetime" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] [[package]] name = "toml_edit" version = "0.22.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", "winnow", ] [[package]] name = "trybuild" version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "207aa50d36c4be8d8c6ea829478be44a372c6a77669937bb39c698e52f1491e8" dependencies = [ "glob", "serde", "serde_derive", "serde_json", "termcolor", "toml", ] [[package]] name = "unicode-ident" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" [[package]] name = "unicode-xid" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" [[package]] name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "walkdir" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11f4ebb15cedacc4a9f5c3469ca29787482d0b7502ff5a4a47ed1f55b987c9b4" dependencies = [ "same-file", "winapi", "winapi-util", ] [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasm-bindgen" version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900" dependencies = [ "bumpalo", "lazy_static", "log", "proc-macro2", "quote", "syn 1.0.67", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97" dependencies = [ "proc-macro2", "quote", "syn 1.0.67", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f" [[package]] name = "web-sys" version = "0.3.51" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e828417b379f3df7111d3a2a9e5753706cae29c41f7c4029ee9fd77f3e09e582" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] name = "winapi" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3ad91d846a4a5342c1fb7008d26124ee6cf94a3953751618577295373b32117" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a16a8e2ebfc883e2b1771c6482b1fb3c6831eab289ba391619a2d93a7356220f" [[package]] name = "winapi-util" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab" dependencies = [ "winapi", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ca29cb03c8ceaf20f8224a18a530938305e9872b1478ea24ff44b4f503a1d1d" [[package]] name = "wincolor" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9dc3aa9dcda98b5a16150c54619c1ead22e3d3a5d458778ae914be760aa981a" dependencies = [ "winapi", ] [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ "windows-targets 0.48.5", ] [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets 0.52.6", ] [[package]] name = "windows-targets" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm 0.48.5", "windows_aarch64_msvc 0.48.5", "windows_i686_gnu 0.48.5", "windows_i686_msvc 0.48.5", "windows_x86_64_gnu 0.48.5", "windows_x86_64_gnullvm 0.48.5", "windows_x86_64_msvc 0.48.5", ] [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" dependencies = [ "memchr", ] pathfinding-4.14.0/Cargo.toml0000644000000114320000000000100114140ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.77.2" name = "pathfinding" version = "4.14.0" authors = ["Samuel Tardieu "] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "Pathfinding, flow, and graph algorithms" homepage = "https://rfc1149.net/devel/pathfinding.html" documentation = "https://docs.rs/pathfinding/" readme = "README.md" keywords = [ "shortest-path", "astar", "dijkstra", "flow", "graph", ] categories = ["algorithms"] license = "Apache-2.0/MIT" repository = "https://github.com/evenfurther/pathfinding" [package.metadata.release] sign-commit = true sign-tag = true [[package.metadata.release.pre-release-replacements]] exactly = 1 file = "README.md" replace = 'pathfinding = "{{version}}"' search = 'pathfinding = ".*"' [[package.metadata.release.pre-release-replacements]] exactly = 1 file = "CHANGELOG.md" replace = "{{tag_name}}" search = 'n\.n\.n' [lib] name = "pathfinding" path = "src/lib.rs" [[example]] name = "bfs_bidirectional" path = "examples/bfs_bidirectional.rs" [[example]] name = "sliding-puzzle" path = "examples/sliding-puzzle.rs" [[test]] name = "aoc-2017-12-12" path = "tests/aoc-2017-12-12.rs" [[test]] name = "aoc-2020-10" path = "tests/aoc-2020-10.rs" [[test]] name = "aoc-2021-12" path = "tests/aoc-2021-12.rs" [[test]] name = "aoc-2023-17" path = "tests/aoc-2023-17.rs" [[test]] name = "astar_bag" path = "tests/astar_bag.rs" [[test]] name = "cliques" path = "tests/cliques.rs" [[test]] name = "codejam-2017-a" path = "tests/codejam-2017-a.rs" [[test]] name = "connected-components" path = "tests/connected-components.rs" [[test]] name = "count_paths" path = "tests/count_paths.rs" [[test]] name = "cycle_detection" path = "tests/cycle_detection.rs" [[test]] name = "dfs-reach" path = "tests/dfs-reach.rs" [[test]] name = "dijkstra-all" path = "tests/dijkstra-all.rs" [[test]] name = "dijkstra-reach" path = "tests/dijkstra-reach.rs" [[test]] name = "edmondskarp" path = "tests/edmondskarp.rs" [[test]] name = "gps" path = "tests/gps.rs" [[test]] name = "grid" path = "tests/grid.rs" [[test]] name = "kruskal" path = "tests/kruskal.rs" [[test]] name = "kuhn_munkres" path = "tests/kuhn_munkres.rs" [[test]] name = "matrix" path = "tests/matrix.rs" [[test]] name = "pathfinding" path = "tests/pathfinding.rs" [[test]] name = "prim" path = "tests/prim.rs" [[test]] name = "r299" path = "tests/r299.rs" [[test]] name = "strongly_connected_components" path = "tests/strongly_connected_components.rs" [[test]] name = "topological_sort" path = "tests/topological_sort.rs" [[test]] name = "ui" path = "tests/ui.rs" [[test]] name = "utils" path = "tests/utils.rs" [[test]] name = "version" path = "tests/version.rs" [[test]] name = "yen" path = "tests/yen.rs" [[test]] name = "yen-issue-507" path = "tests/yen-issue-507.rs" [[bench]] name = "algos" path = "benches/algos.rs" harness = false [[bench]] name = "algos-fill" path = "benches/algos-fill.rs" harness = false [[bench]] name = "edmondskarp" path = "benches/edmondskarp.rs" harness = false [[bench]] name = "kuhn_munkres" path = "benches/kuhn_munkres.rs" harness = false [[bench]] name = "matrices" path = "benches/matrices.rs" harness = false [[bench]] name = "movingai" path = "benches/movingai.rs" harness = false [[bench]] name = "separate_components" path = "benches/separate_components.rs" harness = false [dependencies.deprecate-until] version = "0.1.1" [dependencies.indexmap] version = "2.5.0" [dependencies.integer-sqrt] version = "0.1.5" [dependencies.num-traits] version = "0.2.19" [dependencies.rustc-hash] version = "2.0.0" [dependencies.thiserror] version = "2.0.0" [dev-dependencies.codspeed-criterion-compat] version = "2.7.2" [dev-dependencies.itertools] version = "0.14.0" [dev-dependencies.lazy_static] version = "1.5.0" [dev-dependencies.movingai] version = "1.3.1" [dev-dependencies.noisy_float] version = "0.2.0" [dev-dependencies.rand] version = "0.8.5" [dev-dependencies.rand_xorshift] version = "0.3.0" [dev-dependencies.regex] version = "1.10.6" [dev-dependencies.trybuild] version = "1.0.99" [dev-dependencies.version_check] version = "0.9.5" [lints.clippy.module_name_repetitions] level = "allow" priority = 1 [lints.clippy.pedantic] level = "deny" priority = 0 [lints.clippy.too_long_first_doc_paragraph] level = "allow" priority = 1 pathfinding-4.14.0/Cargo.toml.orig0000644000000034750000000000100123630ustar [package] name = "pathfinding" description = "Pathfinding, flow, and graph algorithms" repository = "https://github.com/evenfurther/pathfinding" keywords = ["shortest-path", "astar", "dijkstra", "flow", "graph"] license = "Apache-2.0/MIT" homepage = "https://rfc1149.net/devel/pathfinding.html" documentation = "https://docs.rs/pathfinding/" version = "4.14.0" authors = ["Samuel Tardieu "] categories = ["algorithms"] readme = "README.md" edition = "2021" rust-version = "1.77.2" [package.metadata.release] sign-commit = true sign-tag = true pre-release-replacements = [ {file = "README.md", search = "pathfinding = \".*\"", replace = "pathfinding = \"{{version}}\"", exactly = 1}, {file = "CHANGELOG.md", search = "n\\.n\\.n", replace = "{{tag_name}}", exactly = 1} ] [dependencies] num-traits = "0.2.19" indexmap = "2.5.0" rustc-hash = "2.0.0" integer-sqrt = "0.1.5" thiserror = "2.0.0" deprecate-until = "0.1.1" [dev-dependencies] codspeed-criterion-compat = "2.7.2" itertools = "0.14.0" lazy_static = "1.5.0" movingai = "1.3.1" noisy_float = "0.2.0" rand = "0.8.5" rand_xorshift = "0.3.0" # Not a real dependency, but needed since criterion 0.4.0 # does not compile anymore as of 2022-10-03. This is still # needed on 2024-11-24. regex = "1.10.6" trybuild = "1.0.99" version_check = "0.9.5" [lints.clippy] module_name_repetitions = { level = "allow", priority = 1 } too_long_first_doc_paragraph = { level = "allow", priority = 1 } # Temporary pedantic = { level = "deny", priority = 0 } [[bench]] name = "algos" harness = false [[bench]] name = "algos-fill" harness = false [[bench]] name = "movingai" harness = false [[bench]] name = "edmondskarp" harness = false [[bench]] name = "kuhn_munkres" harness = false [[bench]] name = "separate_components" harness = false [[bench]] name = "matrices" harness = false pathfinding-4.14.0/Cargo.toml.orig000064400000000000000000000034751046102023000151050ustar 00000000000000[package] name = "pathfinding" description = "Pathfinding, flow, and graph algorithms" repository = "https://github.com/evenfurther/pathfinding" keywords = ["shortest-path", "astar", "dijkstra", "flow", "graph"] license = "Apache-2.0/MIT" homepage = "https://rfc1149.net/devel/pathfinding.html" documentation = "https://docs.rs/pathfinding/" version = "4.14.0" authors = ["Samuel Tardieu "] categories = ["algorithms"] readme = "README.md" edition = "2021" rust-version = "1.77.2" [package.metadata.release] sign-commit = true sign-tag = true pre-release-replacements = [ {file = "README.md", search = "pathfinding = \".*\"", replace = "pathfinding = \"{{version}}\"", exactly = 1}, {file = "CHANGELOG.md", search = "n\\.n\\.n", replace = "{{tag_name}}", exactly = 1} ] [dependencies] num-traits = "0.2.19" indexmap = "2.5.0" rustc-hash = "2.0.0" integer-sqrt = "0.1.5" thiserror = "2.0.0" deprecate-until = "0.1.1" [dev-dependencies] codspeed-criterion-compat = "2.7.2" itertools = "0.14.0" lazy_static = "1.5.0" movingai = "1.3.1" noisy_float = "0.2.0" rand = "0.8.5" rand_xorshift = "0.3.0" # Not a real dependency, but needed since criterion 0.4.0 # does not compile anymore as of 2022-10-03. This is still # needed on 2024-11-24. regex = "1.10.6" trybuild = "1.0.99" version_check = "0.9.5" [lints.clippy] module_name_repetitions = { level = "allow", priority = 1 } too_long_first_doc_paragraph = { level = "allow", priority = 1 } # Temporary pedantic = { level = "deny", priority = 0 } [[bench]] name = "algos" harness = false [[bench]] name = "algos-fill" harness = false [[bench]] name = "movingai" harness = false [[bench]] name = "edmondskarp" harness = false [[bench]] name = "kuhn_munkres" harness = false [[bench]] name = "separate_components" harness = false [[bench]] name = "matrices" harness = false pathfinding-4.14.0/README.md000064400000000000000000000055641046102023000134760ustar 00000000000000# pathfinding [![Current Version](https://img.shields.io/crates/v/pathfinding.svg)](https://crates.io/crates/pathfinding) [![Documentation](https://docs.rs/pathfinding/badge.svg)](https://docs.rs/pathfinding) [![License: Apache-2.0/MIT](https://img.shields.io/crates/l/pathfinding.svg)](#license) This crate implements several pathfinding, flow, and graph algorithms in [Rust](https://rust-lang.org/). The algorithms are generic over their arguments. See [the documentation](https://docs.rs/pathfinding) for more information about the various algorithms. ## Using this crate In your `Cargo.toml`, put: ``` ini [dependencies] pathfinding = "4.14.0" ``` You can then pull your preferred algorithm (BFS in this example) using: ``` rust use pathfinding::prelude::bfs; ``` ## Example We will search the shortest path on a chess board to go from (1, 1) to (4, 6) doing only knight moves. ``` rust use pathfinding::prelude::bfs; #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] struct Pos(i32, i32); impl Pos { fn successors(&self) -> Vec { let &Pos(x, y) = self; vec![Pos(x+1,y+2), Pos(x+1,y-2), Pos(x-1,y+2), Pos(x-1,y-2), Pos(x+2,y+1), Pos(x+2,y-1), Pos(x-2,y+1), Pos(x-2,y-1)] } } static GOAL: Pos = Pos(4, 6); let result = bfs(&Pos(1, 1), |p| p.successors(), |p| *p == GOAL); assert_eq!(result.expect("no path found").len(), 5); ``` ## License This code is released under a dual Apache 2.0 / MIT free software license. ## Contributing You are welcome to contribute by opening [issues](https://github.com/evenfurther/pathfinding/issues) or submitting [pull requests](https://github.com/evenfurther/pathfinding/pulls). Please open an issue before implementing a new feature, in case it is a work in progress already or it is fit for this repository. In order to pass the continuous integration tests, your code must be formatted using the latest `rustfmt` with the nightly rust toolchain, and pass `cargo clippy` and [`pre-commit`](https://pre-commit.com/) checks. Those will run automatically when you submit a pull request. You can install `pre-commit` to your checked out version of the repository by running: ```bash $ pre-commit install --hook-type commit-msg ``` This repository uses the [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) commit message style, such as: - feat(matrix): add `Matrix::transpose()` - fix(tests): remove unused imports Each commit must be self-sufficient and clean. If during inspection or code review you need to make further changes to a commit, please squash it. You may use `git rebase -i`, or more convenient tools such as [`jj`](https://martinvonz.github.io/jj/latest/) or [`git-branchless`](https://github.com/arxanas/git-branchless), in order to manipulate your git commits. If a pull-request should automatically close an open issue, please include "Fix #xxx# or "Close #xxx" in the pull-request cover-letter. pathfinding-4.14.0/deny.toml000064400000000000000000000252731046102023000140520ustar 00000000000000# This template contains all of the possible sections and their default values # Note that all fields that take a lint level have these possible values: # * deny - An error will be produced and the check will fail # * warn - A warning will be produced, but the check will not fail # * allow - No warning or error will be produced, though in some cases a note # will be # The values provided in this template are the default values that will be used # when any section or field is not specified in your own configuration [graph] # If 1 or more target triples (and optionally, target_features) are specified, # only the specified targets will be checked when running `cargo deny check`. # This means, if a particular package is only ever used as a target specific # dependency, such as, for example, the `nix` crate only being used via the # `target_family = "unix"` configuration, that only having windows targets in # this list would mean the nix crate, as well as any of its exclusive # dependencies not shared by any other crates, would be ignored, as the target # list here is effectively saying which targets you are building for. targets = [ # The triple can be any string, but only the target triples built in to # rustc (as of 1.40) can be checked against actual config expressions #{ triple = "x86_64-unknown-linux-musl" }, # You can also specify which target_features you promise are enabled for a # particular target. target_features are currently not validated against # the actual valid features supported by the target architecture. #{ triple = "wasm32-unknown-unknown", features = ["atomics"] }, ] # When creating the dependency graph used as the source of truth when checks are # executed, this field can be used to prune crates from the graph, removing them # from the view of cargo-deny. This is an extremely heavy hammer, as if a crate # is pruned from the graph, all of its dependencies will also be pruned unless # they are connected to another crate in the graph that hasn't been pruned, # so it should be used with care. The identifiers are [Package ID Specifications] # (https://doc.rust-lang.org/cargo/reference/pkgid-spec.html) #exclude = [] # If true, metadata will be collected with `--all-features`. Note that this can't # be toggled off if true, if you want to conditionally enable `--all-features` it # is recommended to pass `--all-features` on the cmd line instead all-features = false # If true, metadata will be collected with `--no-default-features`. The same # caveat with `all-features` applies no-default-features = false # If set, these feature will be enabled when collecting metadata. If `--features` # is specified on the cmd line they will take precedence over this option. #features = [] [output] # When outputting inclusion graphs in diagnostics that include features, this # option can be used to specify the depth at which feature edges will be added. # This option is included since the graphs can be quite large and the addition # of features from the crate(s) to all of the graph roots can be far too verbose. # This option can be overridden via `--feature-depth` on the cmd line feature-depth = 1 # This section is considered when running `cargo deny check advisories` # More documentation for the advisories section can be found here: # https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html [advisories] # The path where the advisory database is cloned/fetched into db-path = "~/.cargo/advisory-db" # The url(s) of the advisory databases to use db-urls = ["https://github.com/rustsec/advisory-db"] # The lint level for crates that have been yanked from their source registry yanked = "warn" # A list of advisory IDs to ignore. Note that ignored advisories will still # output a note when they are encountered. ignore = [] # Threshold for security vulnerabilities, any vulnerability with a CVSS score # lower than the range specified will be ignored. Note that ignored advisories # will still output a note when they are encountered. # * None - CVSS Score 0.0 # * Low - CVSS Score 0.1 - 3.9 # * Medium - CVSS Score 4.0 - 6.9 # * High - CVSS Score 7.0 - 8.9 # * Critical - CVSS Score 9.0 - 10.0 #severity-threshold = # If this is true, then cargo deny will use the git executable to fetch advisory database. # If this is false, then it uses a built-in git library. # Setting this to true can be helpful if you have special authentication requirements that cargo-deny does not support. # See Git Authentication for more information about setting up git authentication. #git-fetch-with-cli = true # This section is considered when running `cargo deny check licenses` # More documentation for the licenses section can be found here: # https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html [licenses] # List of explicitly allowed licenses # See https://spdx.org/licenses/ for list of possible licenses # [possible values: any SPDX 3.11 short identifier (+ optional exception)]. allow = [ "MIT", "Apache-2.0", "Unicode-3.0", ] # The confidence threshold for detecting a license from license text. # The higher the value, the more closely the license text must be to the # canonical license text of a valid SPDX license file. # [possible values: any between 0.0 and 1.0]. confidence-threshold = 0.8 # Allow 1 or more licenses on a per-crate basis, so that particular licenses # aren't accepted for every possible crate as with the normal allow list exceptions = [ # Each entry is the crate and version constraint, and its specific allow # list #{ allow = ["Zlib"], name = "adler32", version = "*" }, ] # Some crates don't have (easily) machine readable licensing information, # adding a clarification entry for it allows you to manually specify the # licensing information #[[licenses.clarify]] # The name of the crate the clarification applies to #name = "ring" # The optional version constraint for the crate #version = "*" # The SPDX expression for the license requirements of the crate #expression = "MIT AND ISC AND OpenSSL" # One or more files in the crate's source used as the "source of truth" for # the license expression. If the contents match, the clarification will be used # when running the license check, otherwise the clarification will be ignored # and the crate will be checked normally, which may produce warnings or errors # depending on the rest of your configuration #license-files = [ # Each entry is a crate relative path, and the (opaque) hash of its contents #{ path = "LICENSE", hash = 0xbd0eed23 } #] [licenses.private] # If true, ignores workspace crates that aren't published, or are only # published to private registries. # To see how to mark a crate as unpublished (to the official registry), # visit https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field. ignore = false # One or more private registries that you might publish crates to, if a crate # is only published to private registries, and ignore is true, the crate will # not have its license(s) checked registries = [ #"https://sekretz.com/registry ] # This section is considered when running `cargo deny check bans`. # More documentation about the 'bans' section can be found here: # https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html [bans] # Lint level for when multiple versions of the same crate are detected multiple-versions = "warn" # Lint level for when a crate version requirement is `*` wildcards = "allow" # The graph highlighting used when creating dotgraphs for crates # with multiple versions # * lowest-version - The path to the lowest versioned duplicate is highlighted # * simplest-path - The path to the version with the fewest edges is highlighted # * all - Both lowest-version and simplest-path are used highlight = "all" # The default lint level for `default` features for crates that are members of # the workspace that is being checked. This can be overridden by allowing/denying # `default` on a crate-by-crate basis if desired. workspace-default-features = "allow" # The default lint level for `default` features for external crates that are not # members of the workspace. This can be overridden by allowing/denying `default` # on a crate-by-crate basis if desired. external-default-features = "allow" # List of crates that are allowed. Use with care! allow = [ #{ name = "ansi_term", version = "=0.11.0" }, ] # List of crates to deny deny = [ # Each entry the name of a crate and a version range. If version is # not specified, all versions will be matched. #{ name = "ansi_term", version = "=0.11.0" }, # # Wrapper crates can optionally be specified to allow the crate when it # is a direct dependency of the otherwise banned crate #{ name = "ansi_term", version = "=0.11.0", wrappers = [] }, ] # List of features to allow/deny # Each entry the name of a crate and a version range. If version is # not specified, all versions will be matched. #[[bans.features]] #name = "reqwest" # Features to not allow #deny = ["json"] # Features to allow #allow = [ # "rustls", # "__rustls", # "__tls", # "hyper-rustls", # "rustls", # "rustls-pemfile", # "rustls-tls-webpki-roots", # "tokio-rustls", # "webpki-roots", #] # If true, the allowed features must exactly match the enabled feature set. If # this is set there is no point setting `deny` #exact = true # Certain crates/versions that will be skipped when doing duplicate detection. #skip = [ # { name = "hermit-abi" }, # #{ name = "ansi_term", version = "=0.11.0" }, #] # Similarly to `skip` allows you to skip certain crates during duplicate # detection. Unlike skip, it also includes the entire tree of transitive # dependencies starting at the specified crate, up to a certain depth, which is # by default infinite. skip-tree = [ #{ name = "ansi_term", version = "=0.11.0", depth = 20 }, ] # This section is considered when running `cargo deny check sources`. # More documentation about the 'sources' section can be found here: # https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html [sources] # Lint level for what to happen when a crate from a crate registry that is not # in the allow list is encountered unknown-registry = "warn" # Lint level for what to happen when a crate from a git repository that is not # in the allow list is encountered unknown-git = "warn" # List of URLs for allowed crate registries. Defaults to the crates.io index # if not specified. If it is specified but empty, no registries are allowed. allow-registry = ["https://github.com/rust-lang/crates.io-index"] # List of URLs for allowed Git repositories allow-git = [] [sources.allow-org] # 1 or more github.com organizations to allow git sources for #github = [""] # 1 or more gitlab.com organizations to allow git sources for #gitlab = [""] # 1 or more bitbucket.org organizations to allow git sources for #bitbucket = [""] pathfinding-4.14.0/examples/bfs_bidirectional.rs000064400000000000000000000176361046102023000200500ustar 00000000000000//! This example demonstrates the BFS bidirectional algorithm, //! and compares it with the regular BFS algorithm. use pathfinding::prelude::{bfs, bfs_bidirectional}; use std::ops::Add; use std::time::Instant; const SIZE: isize = 64; const BOTTOM_LEFT: P = P(0, 0); const TOP_RIGHT: P = P(SIZE, SIZE); const CENTER: P = P(SIZE / 2, SIZE / 2); #[derive(Debug, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)] struct P(isize, isize); impl Add for P { type Output = Self; fn add(self, other: Self) -> Self { P(self.0 + other.0, self.1 + other.1) } } fn successors(p: &P) -> Vec

{ [P(0, 1), P(0, -1), P(1, 0), P(-1, 0)] .into_iter() .map(|delta| p.clone() + delta) .filter(|p| p.0 >= 0 && p.0 <= SIZE && p.1 >= 0 && p.1 <= SIZE) .collect() } fn main() { run_corner_to_corner(); run_center_to_corner(); } /// Corner to corner: /// ================= /// /// In this case both algorithms will perform similarly. /// In fact, regular BFS will perform slightly better, since the algorithm is slightly simpler. /// /// We can understand this in terms of the number of points that need to be searched in order to reach /// the goal. In the below diagrams this corresponds to the area covered in the final snapshot. /// /// In both cases every point gets searched - the entire area is filled. For this reason we can intuitively see that /// regular BFS and bidirectional BFS will perform similarly. /// /// Regular BFS: /// ============ /// /// $---------$ $---------$ $---------$ $---------$ $---------$ $---------$ /// | G| | G| | G| | G| |FFFFFFF G| |FFFFFFFFG| /// | | | | | | | | |FFFFFFFF | |FFFFFFFFF| /// | | | | | | | | |FFFFFFFFF| |FFFFFFFFF| /// | | | | | | | | |FFFFFFFFF| |FFFFFFFFF| /// | | => | | => | | => | | => ... => |FFFFFFFFF| => |FFFFFFFFF| /// | | | | | | |F | |FFFFFFFFF| |FFFFFFFFF| /// | | | | |F | |FF | |FFFFFFFFF| |FFFFFFFFF| /// | | |F | |FF | |FFF | |FFFFFFFFF| |FFFFFFFFF| /// |S | |SF | |SFF | |SFFF | |SFFFFFFFF| |SFFFFFFFF| /// $---------$ $---------$ $---------$ $---------$ $---------$ $---------$ /// /// Bidirectional BFS: /// ================== /// /// $---------$ $---------$ $---------$ $---------$ $---------$ $---------$ /// | G| | BG| | BBG| | BBBG| | BBBBBBBG| |FBBBBBBBG| /// | | | B| | BB| | BBB| |F BBBBBBB| |FFBBBBBBB| /// | | | | | B| | BB| |FF BBBBBB| |FFFBBBBBB| /// | | | | | | | B| |FFF BBBBB| |FFFFBBBBB| /// | | => | | => | | => | | => ... => |FFFF BBBB| => |FFFFFBBBB| /// | | | | | | |F | |FFFFF BBB| |FFFFFFBBB| /// | | | | |F | |FF | |FFFFFF BB| |FFFFFFFBB| /// | | |F | |FF | |FFF | |FFFFFFF B| |FFFFFFFFB| /// |S | |SF | |SFF | |SFFF | |SFFFFFFF | |SFFFFFFFF| /// $---------$ $---------$ $---------$ $---------$ $---------$ $---------$ fn run_corner_to_corner() { let instant = Instant::now(); bfs(&BOTTOM_LEFT, &successors, |p| *p == TOP_RIGHT); let duration_bfs = instant.elapsed(); let instant = Instant::now(); bfs_bidirectional(&BOTTOM_LEFT, &TOP_RIGHT, successors, successors); let duration_bfs_bidirectional = instant.elapsed(); print!( " Corner to Corner ================ BFS took {duration_bfs:?} Bidirectional BFS took {duration_bfs_bidirectional:?} " ); } /// Center to corner: /// ================= /// /// In this case bidirectional BFS will outperform regular BFS. /// /// We can understand this in terms of the number of points that need to be searched in order to reach /// the goal. In the below diagrams this corresponds to the area covered in the final snapshot. /// /// In this case for the regular BFS every point still needs to be searched - again, the entire area is filled. /// However, for the bidirectional BFS some points remain unsearched - the entire area is not filled. For this /// reason we can intuitively see that bidirectional BFS will outperform regular BFS here. /// /// Regular BFS: /// ============ /// /// $---------$ $---------$ $---------$ $---------$ $---------$ /// | G| | G| | G| | FFFFFFFG| |FFFFFFFFG| /// | | | | | | |FFFFFFFFF| |FFFFFFFFF| /// | | | F | | F | |FFFFFFFFF| |FFFFFFFFF| /// | | | FFF | | FFF | |FFFFFFFFF| |FFFFFFFFF| /// | S | => | FFSFF | => | FFSFF | => ... => |FFFFSFFFF| => |FFFFSFFFF| /// | | | FFF | | FFF | |FFFFFFFFF| |FFFFFFFFF| /// | | | F | | F | |FFFFFFFFF| |FFFFFFFFF| /// | | | | | | |FFFFFFFFF| |FFFFFFFFF| /// | | | | | | | FFFFFFF | |FFFFFFFFF| /// $---------$ $---------$ $---------$ $---------$ $---------$ /// /// Bidirectional BFS: /// ================== /// /// $---------$ $---------$ $---------$ $---------$ $---------$ /// | G| | BG| | BBG| | BBBG| | FBBBG| /// | | | B| | BB| | F BBB| | FFFBBB| /// | | | | | F | | FFF B| | FFFFFBB| /// | | | F | | FFF | | FFFFF | | FFFFFFFB| /// | S | => | FSF | => | FFSFF | => | FFFSFFF | => |FFFFSFFFF| /// | | | F | | FFF | | FFFFF | | FFFFFFF | /// | | | | | F | | FFF | | FFFFF | /// | | | | | | | F | | FFF | /// | | | | | | | | | F | /// $---------$ $---------$ $---------$ $---------$ $---------$ fn run_center_to_corner() { let instant = Instant::now(); bfs(&CENTER, &successors, |p| *p == TOP_RIGHT); let duration_bfs = instant.elapsed(); let instant = Instant::now(); bfs_bidirectional(&CENTER, &TOP_RIGHT, successors, successors); let duration_bfs_bidirectional = instant.elapsed(); print!( " Center to Corner ================ BFS took {duration_bfs:?} Bidirectional BFS took {duration_bfs_bidirectional:?} " ); } pathfinding-4.14.0/examples/sliding-puzzle.rs000064400000000000000000000130621046102023000173530ustar 00000000000000use itertools::Itertools; use lazy_static::lazy_static; use pathfinding::prelude::{astar, idastar}; use rand::prelude::*; use rand::rngs::OsRng; use std::thread; use std::time::Instant; #[cfg(test)] const SIDE: u8 = 3; #[cfg(not(test))] const SIDE: u8 = 4; const LIMIT: usize = (SIDE * SIDE) as usize; #[allow(clippy::derived_hash_with_manual_eq)] #[derive(Clone, Debug, Hash)] struct Game { positions: [u8; LIMIT], // Correct position of piece at every index hole_idx: u8, // Current index of the hole weight: u8, // Current sum of pieces Manhattan distances } impl PartialEq for Game { fn eq(&self, other: &Self) -> bool { self.hole_idx == other.hole_idx && self.weight == other.weight && self.positions == other.positions } } impl Eq for Game {} lazy_static! { static ref GOAL: Game = Game { positions: { let mut p = [0u8; LIMIT]; for (i, e) in p.iter_mut().enumerate() { *e = u8::try_from(i).unwrap(); } p }, hole_idx: 0, weight: 0, }; static ref SUCCESSORS: Vec> = (0..SIDE * SIDE) .map(|idx| (0..4) .filter_map(|dir| match dir { 0 if idx % SIDE > 0 => Some(idx - 1), 1 if idx >= SIDE => Some(idx - SIDE), 2 if idx % SIDE < SIDE - 1 => Some(idx + 1), 3 if idx < SIDE * SIDE - SIDE => Some(idx + SIDE), _ => None, }) .collect::>()) .collect(); } impl Game { /// Move the hole to the given index. fn switch(&self, idx: u8) -> Self { let mut g = self.clone(); g.positions.swap(self.hole_idx as usize, idx as usize); g.hole_idx = idx; g.weight = g.weight + g.distance(self.hole_idx) // Distance of the moved piece at its new index - self.distance(idx); // Distance of the moved piece at its previous index g } #[inline] const fn x(pos: u8) -> u8 { pos % SIDE } #[inline] const fn y(pos: u8) -> u8 { pos / SIDE } // Compute the Manhattan distance between the piece at idx and its correct position. fn distance(&self, idx: u8) -> u8 { let (actual_x, actual_y) = (Self::x(idx), Self::y(idx)); let (correct_x, correct_y) = ( Self::x(self.positions[idx as usize]), Self::y(self.positions[idx as usize]), ); actual_x.abs_diff(correct_x) + actual_y.abs_diff(correct_y) } fn solved(&self) -> bool { self.positions == GOAL.positions } // Here we try to illustrate that we can return an iterator without building a Vec. // However, since the successors are the current board with the hole moved one // position, we need to build a clone of the current board that will be reused in // this iterator. fn successors(&self) -> impl Iterator { let game = self.clone(); SUCCESSORS[self.hole_idx as usize] .iter() .map(move |&n| (game.switch(n), 1)) } fn is_solvable(&self) -> bool { let mut inversions = 0; for i in 0..LIMIT { let c = self.positions[i]; if c != 0 { for j in i + 1..LIMIT { let d = self.positions[j]; if d != 0 && d < c { inversions ^= 1; } } } } if SIDE % 2 == 1 { inversions == 0 } else { Self::y(self.hole_idx) % 2 == inversions } } fn from_array(positions: [u8; LIMIT]) -> Self { let hole_idx = u8::try_from(positions.iter().find_position(|&&n| n == 0).unwrap().0).unwrap(); let mut game = Self { positions, hole_idx, weight: 0, }; game.weight = (0..u8::try_from(LIMIT).unwrap()) .filter(|&n| n != game.hole_idx) .map(|n| game.distance(n)) .sum(); game } fn shuffled() -> Self { let mut rng = OsRng; let mut positions = Self::default().positions; loop { positions.shuffle(&mut rng); let game = Self::from_array(positions); if game.is_solvable() { return game; } } } } impl Default for Game { fn default() -> Self { GOAL.clone() } } #[test] fn test() { // main() already contains checks. main(); } fn main() { let b = Game::shuffled(); println!("{b:?}"); assert!(b.is_solvable()); let start = Instant::now(); let (astar_result, idastar_result) = thread::scope(|s| { let idastar_handle = s.spawn({ || { let result = idastar(&b, Game::successors, |b| b.weight, Game::solved).unwrap(); println!("idastar: {} moves in {:.3?}", result.1, start.elapsed(),); assert!(result.0.last().unwrap().weight == 0); result.1 } }); ( { let result = astar(&b, Game::successors, |b| b.weight, Game::solved).unwrap(); println!("astar: {} moves in {:.3?}", result.1, start.elapsed(),); assert!(result.0.last().unwrap().weight == 0); result.1 }, idastar_handle.join().unwrap(), ) }); println!("Total execution time: {:.3?}", start.elapsed()); assert_eq!(idastar_result, astar_result); assert!(idastar_result >= b.weight); } pathfinding-4.14.0/release.sh000075500000000000000000000010031046102023000141560ustar 00000000000000#! /bin/sh # # Usage: ./release.sh [arguments to cargo release] set -e nix shell nixpkgs#git-extras -c git-changelog -n CHANGELOG.md changelog=$(mktemp) awk '/^n/,/^v/{if(/^ /)print}' < CHANGELOG.md > "$changelog" git commit -am "chore(changelog): prepare for next release" echo "Changelog that will be used for this release:" echo "---" cat "$changelog" echo "---" cargo release --sign-tag --execute "$@" tag=$(git tag --list --sort=-v:refname | head -n 1) gh release create $tag -F "$changelog" rm "$changelog" pathfinding-4.14.0/src/directed/astar.rs000064400000000000000000000326401046102023000162440ustar 00000000000000//! Compute a shortest path (or all shorted paths) using the [A* search //! algorithm](https://en.wikipedia.org/wiki/A*_search_algorithm). use indexmap::map::Entry::{Occupied, Vacant}; use num_traits::Zero; use std::cmp::Ordering; use std::collections::{BinaryHeap, HashSet}; use std::hash::Hash; use std::iter::FusedIterator; use super::reverse_path; use crate::FxIndexMap; /// Compute a shortest path using the [A* search /// algorithm](https://en.wikipedia.org/wiki/A*_search_algorithm). /// /// The shortest path starting from `start` up to a node for which `success` returns `true` is /// computed and returned along with its total cost, in a `Some`. If no path can be found, `None` /// is returned instead. /// /// - `start` is the starting node. /// - `successors` returns a list of successors for a given node, along with the cost for moving /// from the node to the successor. This cost must be non-negative. /// - `heuristic` returns an approximation of the cost from a given node to the goal. The /// approximation must not be greater than the real cost, or a wrong shortest path may be returned. /// - `success` checks whether the goal has been reached. It is not a node as some problems require /// a dynamic solution instead of a fixed node. /// /// A node will never be included twice in the path as determined by the `Eq` relationship. /// /// The returned path comprises both the start and end node. /// /// # Example /// /// We will search the shortest path on a chess board to go from (1, 1) to (4, 6) doing only knight /// moves. /// /// The first version uses an explicit type `Pos` on which the required traits are derived. /// /// ``` /// use pathfinding::prelude::astar; /// /// #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] /// struct Pos(i32, i32); /// /// impl Pos { /// fn distance(&self, other: &Pos) -> u32 { /// (self.0.abs_diff(other.0) + self.1.abs_diff(other.1)) as u32 /// } /// /// fn successors(&self) -> Vec<(Pos, u32)> { /// let &Pos(x, y) = self; /// vec![Pos(x+1,y+2), Pos(x+1,y-2), Pos(x-1,y+2), Pos(x-1,y-2), /// Pos(x+2,y+1), Pos(x+2,y-1), Pos(x-2,y+1), Pos(x-2,y-1)] /// .into_iter().map(|p| (p, 1)).collect() /// } /// } /// /// static GOAL: Pos = Pos(4, 6); /// let result = astar(&Pos(1, 1), |p| p.successors(), |p| p.distance(&GOAL) / 3, /// |p| *p == GOAL); /// assert_eq!(result.expect("no path found").1, 4); /// ``` /// /// The second version does not declare a `Pos` type, makes use of more closures, /// and is thus shorter. /// /// ``` /// use pathfinding::prelude::astar; /// /// static GOAL: (i32, i32) = (4, 6); /// let result = astar(&(1, 1), /// |&(x, y)| vec![(x+1,y+2), (x+1,y-2), (x-1,y+2), (x-1,y-2), /// (x+2,y+1), (x+2,y-1), (x-2,y+1), (x-2,y-1)] /// .into_iter().map(|p| (p, 1)), /// |&(x, y)| (GOAL.0.abs_diff(x) + GOAL.1.abs_diff(y)) / 3, /// |&p| p == GOAL); /// assert_eq!(result.expect("no path found").1, 4); /// ``` #[allow(clippy::missing_panics_doc)] pub fn astar( start: &N, mut successors: FN, mut heuristic: FH, mut success: FS, ) -> Option<(Vec, C)> where N: Eq + Hash + Clone, C: Zero + Ord + Copy, FN: FnMut(&N) -> IN, IN: IntoIterator, FH: FnMut(&N) -> C, FS: FnMut(&N) -> bool, { let mut to_see = BinaryHeap::new(); to_see.push(SmallestCostHolder { estimated_cost: Zero::zero(), cost: Zero::zero(), index: 0, }); let mut parents: FxIndexMap = FxIndexMap::default(); parents.insert(start.clone(), (usize::MAX, Zero::zero())); while let Some(SmallestCostHolder { cost, index, .. }) = to_see.pop() { let successors = { let (node, &(_, c)) = parents.get_index(index).unwrap(); // Cannot fail if success(node) { let path = reverse_path(&parents, |&(p, _)| p, index); return Some((path, cost)); } // We may have inserted a node several time into the binary heap if we found // a better way to access it. Ensure that we are currently dealing with the // best path and discard the others. if cost > c { continue; } successors(node) }; for (successor, move_cost) in successors { let new_cost = cost + move_cost; let h; // heuristic(&successor) let n; // index for successor match parents.entry(successor) { Vacant(e) => { h = heuristic(e.key()); n = e.index(); e.insert((index, new_cost)); } Occupied(mut e) => { if e.get().1 > new_cost { h = heuristic(e.key()); n = e.index(); e.insert((index, new_cost)); } else { continue; } } } to_see.push(SmallestCostHolder { estimated_cost: new_cost + h, cost: new_cost, index: n, }); } } None } /// Compute all shortest paths using the [A* search /// algorithm](https://en.wikipedia.org/wiki/A*_search_algorithm). /// /// Whereas `astar` (non-deterministic-ally) returns a single shortest /// path, `astar_bag` returns all shortest paths (in a /// non-deterministic order). /// /// The shortest paths starting from `start` up to a node for which `success` returns `true` are /// computed and returned in an iterator along with the cost (which, by definition, is the same for /// each shortest path), wrapped in a `Some`. If no paths are found, `None` is returned. /// /// - `start` is the starting node. /// - `successors` returns a list of successors for a given node, along with the cost for moving /// from the node to the successor. /// - `heuristic` returns an approximation of the cost from a given node to the goal. The /// approximation must not be greater than the real cost, or a wrong shortest path may be returned. /// - `success` checks whether the goal has been reached. It is not a node as some problems require /// a dynamic solution instead of a fixed node. /// /// A node will never be included twice in the path as determined by the `Eq` relationship. /// /// Each path comprises both the start and an end node. Note that while every path shares the same /// start node, different paths may have different end nodes. #[allow(clippy::missing_panics_doc)] pub fn astar_bag( start: &N, mut successors: FN, mut heuristic: FH, mut success: FS, ) -> Option<(AstarSolution, C)> where N: Eq + Hash + Clone, C: Zero + Ord + Copy, FN: FnMut(&N) -> IN, IN: IntoIterator, FH: FnMut(&N) -> C, FS: FnMut(&N) -> bool, { let mut to_see = BinaryHeap::new(); let mut min_cost = None; let mut sinks = HashSet::new(); to_see.push(SmallestCostHolder { estimated_cost: Zero::zero(), cost: Zero::zero(), index: 0, }); let mut parents: FxIndexMap, C)> = FxIndexMap::default(); parents.insert(start.clone(), (HashSet::new(), Zero::zero())); while let Some(SmallestCostHolder { cost, index, estimated_cost, .. }) = to_see.pop() { if matches!(min_cost, Some(min_cost) if estimated_cost > min_cost) { break; } let successors = { let (node, &(_, c)) = parents.get_index(index).unwrap(); // Cannot fail if success(node) { min_cost = Some(cost); sinks.insert(index); } // We may have inserted a node several time into the binary heap if we found // a better way to access it. Ensure that we are currently dealing with the // best path and discard the others. if cost > c { continue; } successors(node) }; for (successor, move_cost) in successors { let new_cost = cost + move_cost; let h; // heuristic(&successor) let n; // index for successor match parents.entry(successor) { Vacant(e) => { h = heuristic(e.key()); n = e.index(); let mut p = HashSet::new(); p.insert(index); e.insert((p, new_cost)); } Occupied(mut e) => { if e.get().1 > new_cost { h = heuristic(e.key()); n = e.index(); let s = e.get_mut(); s.0.clear(); s.0.insert(index); s.1 = new_cost; } else { if e.get().1 == new_cost { // New parent with an identical cost, this is not // considered as an insertion. e.get_mut().0.insert(index); } continue; } } } to_see.push(SmallestCostHolder { estimated_cost: new_cost + h, cost: new_cost, index: n, }); } } min_cost.map(|cost| { let parents = parents .into_iter() .map(|(k, (ps, _))| (k, ps.into_iter().collect())) .collect(); ( AstarSolution { sinks: sinks.into_iter().collect(), parents, current: vec![], terminated: false, }, cost, ) }) } /// Compute all shortest paths using the [A* search /// algorithm](https://en.wikipedia.org/wiki/A*_search_algorithm). /// /// Whereas `astar` (non-deterministic-ally) returns a single shortest /// path, `astar_bag` returns all shortest paths (in a /// non-deterministic order). /// /// This is a utility function which collects the results of the `astar_bag` function into a /// vector. Most of the time, it is more appropriate to use `astar_bag` directly. /// /// ### Warning /// /// The number of results with the same value might be very large in some graphs. Use with caution. pub fn astar_bag_collect( start: &N, successors: FN, heuristic: FH, success: FS, ) -> Option<(Vec>, C)> where N: Eq + Hash + Clone, C: Zero + Ord + Copy, FN: FnMut(&N) -> IN, IN: IntoIterator, FH: FnMut(&N) -> C, FS: FnMut(&N) -> bool, { astar_bag(start, successors, heuristic, success) .map(|(solutions, cost)| (solutions.collect(), cost)) } /// This structure is used to implement Rust's max-heap as a min-heap /// version for A*. The smallest `estimated_cost` (which is the sum of /// the `cost` and the heuristic) is preferred. For the same /// `estimated_cost`, the highest `cost` will be favored, as it may /// indicate that the goal is nearer, thereby requiring fewer /// exploration steps. struct SmallestCostHolder { estimated_cost: K, cost: K, index: usize, } impl PartialEq for SmallestCostHolder { fn eq(&self, other: &Self) -> bool { self.estimated_cost.eq(&other.estimated_cost) && self.cost.eq(&other.cost) } } impl Eq for SmallestCostHolder {} impl PartialOrd for SmallestCostHolder { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for SmallestCostHolder { fn cmp(&self, other: &Self) -> Ordering { match other.estimated_cost.cmp(&self.estimated_cost) { Ordering::Equal => self.cost.cmp(&other.cost), s => s, } } } /// Iterator structure created by the `astar_bag` function. #[derive(Clone)] pub struct AstarSolution { sinks: Vec, parents: Vec<(N, Vec)>, current: Vec>, terminated: bool, } impl AstarSolution { fn complete(&mut self) { loop { let ps = match self.current.last() { None => self.sinks.clone(), Some(last) => self.parents(*last.last().unwrap()).clone(), }; if ps.is_empty() { break; } self.current.push(ps); } } fn next_vec(&mut self) { while self.current.last().map(Vec::len) == Some(1) { self.current.pop(); } self.current.last_mut().map(Vec::pop); } fn node(&self, i: usize) -> &N { &self.parents[i].0 } fn parents(&self, i: usize) -> &Vec { &self.parents[i].1 } } impl Iterator for AstarSolution { type Item = Vec; fn next(&mut self) -> Option { if self.terminated { return None; } self.complete(); let path = self .current .iter() .rev() .map(|v| v.last().copied().unwrap()) .map(|i| self.node(i).clone()) .collect::>(); self.next_vec(); self.terminated = self.current.is_empty(); Some(path) } } impl FusedIterator for AstarSolution {} pathfinding-4.14.0/src/directed/bfs.rs000064400000000000000000000253071046102023000157060ustar 00000000000000//! Compute a shortest path using the [breadth-first search //! algorithm](https://en.wikipedia.org/wiki/Breadth-first_search). use super::reverse_path; use crate::{FxIndexMap, FxIndexSet}; use indexmap::map::Entry::Vacant; use std::hash::Hash; use std::iter::FusedIterator; /// Compute a shortest path using the [breadth-first search /// algorithm](https://en.wikipedia.org/wiki/Breadth-first_search). /// /// The shortest path starting from `start` up to a node for which `success` returns `true` is /// computed and returned in a `Some`. If no path can be found, `None` /// is returned instead. /// /// - `start` is the starting node. /// - `successors` returns a list of successors for a given node. /// - `success` checks whether the goal has been reached. It is not a node as some problems require /// a dynamic solution instead of a fixed node. /// /// A node will never be included twice in the path as determined by the `Eq` relationship. /// /// The returned path comprises both the start and end node. /// /// # Example /// /// We will search the shortest path on a chess board to go from (1, 1) to (4, 6) doing only knight /// moves. /// /// The first version uses an explicit type `Pos` on which the required traits are derived. /// /// ``` /// use pathfinding::prelude::bfs; /// /// #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] /// struct Pos(i32, i32); /// /// impl Pos { /// fn successors(&self) -> Vec { /// let &Pos(x, y) = self; /// vec![Pos(x+1,y+2), Pos(x+1,y-2), Pos(x-1,y+2), Pos(x-1,y-2), /// Pos(x+2,y+1), Pos(x+2,y-1), Pos(x-2,y+1), Pos(x-2,y-1)] /// } /// } /// /// static GOAL: Pos = Pos(4, 6); /// let result = bfs(&Pos(1, 1), |p| p.successors(), |p| *p == GOAL); /// assert_eq!(result.expect("no path found").len(), 5); /// ``` /// /// The second version does not declare a `Pos` type, makes use of more closures, /// and is thus shorter. /// /// ``` /// use pathfinding::prelude::bfs; /// /// static GOAL: (i32, i32) = (4, 6); /// let result = bfs(&(1, 1), /// |&(x, y)| vec![(x+1,y+2), (x+1,y-2), (x-1,y+2), (x-1,y-2), /// (x+2,y+1), (x+2,y-1), (x-2,y+1), (x-2,y-1)], /// |&p| p == GOAL); /// assert_eq!(result.expect("no path found").len(), 5); /// ``` pub fn bfs(start: &N, successors: FN, success: FS) -> Option> where N: Eq + Hash + Clone, FN: FnMut(&N) -> IN, IN: IntoIterator, FS: FnMut(&N) -> bool, { bfs_core(start, successors, success, true) } fn bfs_core( start: &N, mut successors: FN, mut success: FS, check_first: bool, ) -> Option> where N: Eq + Hash + Clone, FN: FnMut(&N) -> IN, IN: IntoIterator, FS: FnMut(&N) -> bool, { if check_first && success(start) { return Some(vec![start.clone()]); } let mut i = 0; let mut parents: FxIndexMap = FxIndexMap::default(); parents.insert(start.clone(), usize::MAX); while let Some((node, _)) = parents.get_index(i) { for successor in successors(node) { if success(&successor) { let mut path = reverse_path(&parents, |&p| p, i); path.push(successor); return Some(path); } if let Vacant(e) = parents.entry(successor) { e.insert(i); } } i += 1; } None } /// Return one of the shortest loop from start to start if it exists, `None` otherwise. /// /// - `start` is the starting node. /// - `successors` returns a list of successors for a given node. /// /// Except the start node which will be included both at the beginning and the end of /// the path, a node will never be included twice in the path as determined /// by the `Eq` relationship. pub fn bfs_loop(start: &N, successors: FN) -> Option> where N: Eq + Hash + Clone, FN: FnMut(&N) -> IN, IN: IntoIterator, { bfs_core(start, successors, |n| n == start, false) } /// Compute a shortest path using the [breadth-first search /// algorithm](https://en.wikipedia.org/wiki/Breadth-first_search) with /// [bidirectional search](https://en.wikipedia.org/wiki/Bidirectional_search). /// /// Bidirectional search runs two simultaneous searches: one forward from the start, /// and one backward from the end, stopping when the two meet. In many cases this gives /// a faster result than searching only in a single direction. /// /// The shortest path starting from `start` up to a node `end` is /// computed and returned in a `Some`. If no path can be found, `None` /// is returned instead. /// /// - `start` is the starting node. /// - `end` is the end node. /// - `successors_fn` returns a list of successors for a given node. /// - `predecessors_fn` returns a list of predecessors for a given node. For an undirected graph /// this will be the same as `successors_fn`, however for a directed graph this will be different. /// /// A node will never be included twice in the path as determined by the `Eq` relationship. /// /// The returned path comprises both the start and end node. /// /// # Example /// /// We will search the shortest path on a chess board to go from (1, 1) to (4, 6) doing only knight /// moves. /// /// ``` /// use pathfinding::prelude::bfs_bidirectional; /// /// static SUCCESSORS: fn(&(i32, i32)) -> Vec<(i32, i32)> = |&(x, y)| vec![ /// (x+1,y+2), (x+1,y-2), (x-1,y+2), (x-1,y-2), /// (x+2,y+1), (x+2,y-1), (x-2,y+1), (x-2,y-1) /// ]; /// let result = bfs_bidirectional(&(1, 1), &(4, 6), SUCCESSORS, SUCCESSORS); /// assert_eq!(result.expect("no path found").len(), 5); /// ``` /// /// Find also a more interesting example, comparing regular /// and bidirectional BFS [here](https://github.com/evenfurther/pathfinding/blob/main/examples/bfs_bidirectional.rs). #[allow(clippy::missing_panics_doc)] pub fn bfs_bidirectional( start: &N, end: &N, successors_fn: FNS, predecessors_fn: FNP, ) -> Option> where N: Eq + Hash + Clone, FNS: Fn(&N) -> IN, FNP: Fn(&N) -> IN, IN: IntoIterator, { let mut predecessors: FxIndexMap> = FxIndexMap::default(); predecessors.insert(start.clone(), None); let mut successors: FxIndexMap> = FxIndexMap::default(); successors.insert(end.clone(), None); let mut i_forwards = 0; let mut i_backwards = 0; let middle = 'l: loop { for _ in 0..(predecessors.len() - i_forwards) { let node = predecessors.get_index(i_forwards).unwrap().0; for successor_node in successors_fn(node) { if !predecessors.contains_key(&successor_node) { predecessors.insert(successor_node.clone(), Some(i_forwards)); } if successors.contains_key(&successor_node) { break 'l Some(successor_node); } } i_forwards += 1; } for _ in 0..(successors.len() - i_backwards) { let node = successors.get_index(i_backwards).unwrap().0; for predecessor_node in predecessors_fn(node) { if !successors.contains_key(&predecessor_node) { successors.insert(predecessor_node.clone(), Some(i_backwards)); } if predecessors.contains_key(&predecessor_node) { break 'l Some(predecessor_node); } } i_backwards += 1; } if i_forwards == predecessors.len() && i_backwards == successors.len() { break 'l None; } }; middle.map(|middle| { // Path found! // Build the path. let mut path = vec![]; // From middle to the start. let mut node = Some(middle.clone()); while let Some(n) = node { path.push(n.clone()); node = predecessors[&n].map(|i| predecessors.get_index(i).unwrap().0.clone()); } // Reverse, to put start at the front. path.reverse(); // And from middle to the end. let mut node = successors[&middle].map(|i| successors.get_index(i).unwrap().0.clone()); while let Some(n) = node { path.push(n.clone()); node = successors[&n].map(|i| successors.get_index(i).unwrap().0.clone()); } path }) } /// Visit all nodes that are reachable from a start node. The node will be visited /// in BFS order, starting from the `start` node and following the order returned /// by the `successors` function. /// /// # Examples /// /// The iterator stops when there are no new nodes to visit: /// /// ``` /// use pathfinding::prelude::bfs_reach; /// /// let all_nodes = bfs_reach(3, |_| (1..=5)).collect::>(); /// assert_eq!(all_nodes, vec![3, 1, 2, 4, 5]); /// ``` /// /// The iterator can be used as a generator. Here are for examples /// the multiples of 2 and 3 (although not in natural order but in /// the order they are discovered by the BFS algorithm): /// /// ``` /// use pathfinding::prelude::bfs_reach; /// /// let mut it = bfs_reach(1, |&n| vec![n*2, n*3]).skip(1); /// assert_eq!(it.next(), Some(2)); // 1*2 /// assert_eq!(it.next(), Some(3)); // 1*3 /// assert_eq!(it.next(), Some(4)); // (1*2)*2 /// assert_eq!(it.next(), Some(6)); // (1*2)*3 /// // (1*3)*2 == 6 which has been seen already /// assert_eq!(it.next(), Some(9)); // (1*3)*3 /// assert_eq!(it.next(), Some(8)); // ((1*2)*2)*2 /// assert_eq!(it.next(), Some(12)); // ((1*2)*2)*3 /// ``` pub fn bfs_reach(start: N, successors: FN) -> BfsReachable where N: Eq + Hash + Clone, FN: FnMut(&N) -> IN, IN: IntoIterator, { let mut seen = FxIndexSet::default(); seen.insert(start); BfsReachable { i: 0, seen, successors, } } /// Struct returned by [`bfs_reach`]. pub struct BfsReachable { i: usize, seen: FxIndexSet, successors: FN, } impl BfsReachable { /// Return a lower bound on the number of remaining reachable /// nodes. Not all nodes are necessarily known in advance, and /// new reachable nodes may be discovered while using the iterator. pub fn remaining_nodes_low_bound(&self) -> usize { self.seen.len() - self.i } } impl Iterator for BfsReachable where N: Eq + Hash + Clone, FN: FnMut(&N) -> IN, IN: IntoIterator, { type Item = N; fn next(&mut self) -> Option { let n = self.seen.get_index(self.i)?.clone(); for s in (self.successors)(&n) { self.seen.insert(s); } self.i += 1; Some(n) } } impl FusedIterator for BfsReachable where N: Eq + Hash + Clone, FN: FnMut(&N) -> IN, IN: IntoIterator, { } pathfinding-4.14.0/src/directed/count_paths.rs000064400000000000000000000031321046102023000174530ustar 00000000000000//! Count the total number of possible paths to reach a destination. use std::hash::Hash; use rustc_hash::FxHashMap; fn cached_count_paths( start: T, successors: &mut FN, success: &mut FS, cache: &mut FxHashMap, ) -> usize where T: Eq + Hash, FN: FnMut(&T) -> IN, IN: IntoIterator, FS: FnMut(&T) -> bool, { if let Some(&n) = cache.get(&start) { return n; } let count = if success(&start) { 1 } else { successors(&start) .into_iter() .map(|successor| cached_count_paths(successor, successors, success, cache)) .sum() }; cache.insert(start, count); count } /// Count the total number of possible paths to reach a destination. There must be no loops /// in the graph, or the function will overflow its stack. /// /// # Example /// /// On a 8x8 board, find the total paths from the bottom-left square to the top-right square. /// /// ``` /// use pathfinding::prelude::count_paths; /// /// let n = count_paths( /// (0, 0), /// |&(x, y)| { /// [(x + 1, y), (x, y + 1)] /// .into_iter() /// .filter(|&(x, y)| x < 8 && y < 8) /// }, /// |&c| c == (7, 7), /// ); /// assert_eq!(n, 3432); /// ``` pub fn count_paths(start: T, mut successors: FN, mut success: FS) -> usize where T: Eq + Hash, FN: FnMut(&T) -> IN, IN: IntoIterator, FS: FnMut(&T) -> bool, { cached_count_paths( start, &mut successors, &mut success, &mut FxHashMap::default(), ) } pathfinding-4.14.0/src/directed/cycle_detection.rs000064400000000000000000000034501046102023000202640ustar 00000000000000//! Identify a cycle in an infinite sequence. /// Identify a cycle in an infinite sequence using Floyd's algorithm. /// Return the cycle size, the first element, and the index of first element. /// /// # Warning /// /// If no cycle exist, this function loops forever. pub fn floyd(start: T, successor: FS) -> (usize, T, usize) where T: Clone + PartialEq, FS: Fn(T) -> T, { let mut tortoise = successor(start.clone()); let mut hare = successor(successor(start.clone())); while tortoise != hare { (tortoise, hare) = (successor(tortoise), successor(successor(hare))); } let mut mu = 0; tortoise = start; while tortoise != hare { (tortoise, hare, mu) = (successor(tortoise), successor(hare), mu + 1); } let mut lam = 1; hare = successor(tortoise.clone()); while tortoise != hare { (hare, lam) = (successor(hare), lam + 1); } (lam, tortoise, mu) } /// Identify a cycle in an infinite sequence using Brent's algorithm. /// Return the cycle size, the first element, and the index of first element. /// /// # Warning /// /// If no cycle exist, this function loops forever. pub fn brent(start: T, successor: FS) -> (usize, T, usize) where T: Clone + PartialEq, FS: Fn(T) -> T, { let mut power = 1; let mut lam = 1; let mut tortoise = start.clone(); let mut hare = successor(start.clone()); while tortoise != hare { if power == lam { (tortoise, power, lam) = (hare.clone(), power * 2, 0); } (hare, lam) = (successor(hare), lam + 1); } let mut mu = 0; (tortoise, hare) = (start.clone(), (0..lam).fold(start, |x, _| successor(x))); while tortoise != hare { (tortoise, hare, mu) = (successor(tortoise), successor(hare), mu + 1); } (lam, hare, mu) } pathfinding-4.14.0/src/directed/dfs.rs000064400000000000000000000132331046102023000157030ustar 00000000000000//! Compute a path using the [depth-first search //! algorithm](https://en.wikipedia.org/wiki/Depth-first_search). use std::collections::HashSet; use std::hash::Hash; use std::iter::FusedIterator; use rustc_hash::{FxHashMap, FxHashSet}; /// Compute a path using the [depth-first search /// algorithm](https://en.wikipedia.org/wiki/Depth-first_search). /// /// The path starts from `start` up to a node for which `success` /// returns `true` is computed and returned along with its total cost, /// in a `Some`. If no path can be found, `None` is returned instead. /// /// - `start` is the starting node. /// - `successors` returns a list of successors for a given node, which will be tried in order. /// - `success` checks whether the goal has been reached. It is not a node as some problems require /// a dynamic solution instead of a fixed node. /// /// A node will never be included twice in the path as determined by the `Eq` relationship. /// /// The returned path comprises both the start and end node. Note that the start node ownership /// is taken by `dfs` as no clones are made. /// /// # Example /// /// We will search a way to get from 1 to 17 while only adding 1 or multiplying the number by /// itself. /// /// If we put the adder first, an adder-only solution will be found: /// /// ``` /// use pathfinding::prelude::dfs; /// /// assert_eq!(dfs(1, |&n| vec![n+1, n*n].into_iter().filter(|&x| x <= 17), |&n| n == 17), /// Some((1..18).collect())); /// ``` /// /// However, if we put the multiplier first, a shorter solution will be explored first: /// /// ``` /// use pathfinding::prelude::dfs; /// /// assert_eq!(dfs(1, |&n| vec![n*n, n+1].into_iter().filter(|&x| x <= 17), |&n| n == 17), /// Some(vec![1, 2, 4, 16, 17])); /// ``` pub fn dfs(start: N, mut successors: FN, mut success: FS) -> Option> where N: Clone + Eq + Hash, FN: FnMut(&N) -> IN, IN: IntoIterator, FS: FnMut(&N) -> bool, { let mut to_visit = vec![start]; let mut visited = FxHashSet::default(); let mut parents = FxHashMap::default(); while let Some(node) = to_visit.pop() { if visited.insert(node.clone()) { if success(&node) { return Some(build_path(node, &parents)); } for next in successors(&node) .into_iter() .collect::>() .into_iter() .rev() { if !visited.contains(&next) { parents.insert(next.clone(), node.clone()); to_visit.push(next); } } } } None } fn build_path(mut node: N, parents: &FxHashMap) -> Vec where N: Clone + Eq + Hash, { let mut path = vec![node.clone()]; while let Some(parent) = parents.get(&node).cloned() { path.push(parent.clone()); node = parent; } path.into_iter().rev().collect() } /// Visit all nodes that are reachable from a start node. The node will be visited /// in DFS order, starting from the `start` node and following the order returned /// by the `successors` function. /// /// # Examples /// /// The iterator stops when there are no new nodes to visit: /// /// ``` /// use pathfinding::prelude::dfs_reach; /// /// let all_nodes = dfs_reach(3, |_| (1..=5)).collect::>(); /// assert_eq!(all_nodes, vec![3, 1, 2, 4, 5]); /// ``` /// /// The iterator can be used as a generator. Here are for examples /// the multiples of 2 and 3 smaller than 15 (although not in /// natural order but in the order they are discovered by the DFS /// algorithm): /// /// ``` /// use pathfinding::prelude::dfs_reach; /// /// let mut it = dfs_reach(1, |&n| vec![n*2, n*3].into_iter().filter(|&x| x < 15)).skip(1); /// assert_eq!(it.next(), Some(2)); // 1*2 /// assert_eq!(it.next(), Some(4)); // (1*2)*2 /// assert_eq!(it.next(), Some(8)); // ((1*2)*2)*2 /// assert_eq!(it.next(), Some(12)); // ((1*2)*2)*3 /// assert_eq!(it.next(), Some(6)); // (1*2)*3 /// assert_eq!(it.next(), Some(3)); // 1*3 /// // (1*3)*2 == 6 which has been seen already /// assert_eq!(it.next(), Some(9)); // (1*3)*3 /// ``` pub fn dfs_reach(start: N, successors: FN) -> DfsReachable where N: Eq + Hash + Clone, FN: FnMut(&N) -> IN, IN: IntoIterator, { DfsReachable { to_see: vec![start], visited: HashSet::new(), successors, } } /// Struct returned by [`dfs_reach`]. pub struct DfsReachable { to_see: Vec, visited: HashSet, successors: FN, } impl DfsReachable where N: Eq + Hash, { /// Return a lower bound on the number of remaining reachable /// nodes. Not all nodes are necessarily known in advance, and /// new reachable nodes may be discovered while using the iterator. pub fn remaining_nodes_low_bound(&self) -> usize { self.to_see.iter().collect::>().len() } } impl Iterator for DfsReachable where N: Eq + Hash + Clone, FN: FnMut(&N) -> IN, IN: IntoIterator, { type Item = N; fn next(&mut self) -> Option { let n = self.to_see.pop()?; if self.visited.contains(&n) { return self.next(); } self.visited.insert(n.clone()); let mut to_insert = Vec::new(); for s in (self.successors)(&n) { if !self.visited.contains(&s) { to_insert.push(s.clone()); } } self.to_see.extend(to_insert.into_iter().rev()); Some(n) } } impl FusedIterator for DfsReachable where N: Eq + Hash + Clone, FN: FnMut(&N) -> IN, IN: IntoIterator, { } pathfinding-4.14.0/src/directed/dijkstra.rs000064400000000000000000000345161046102023000167510ustar 00000000000000//! Compute a shortest path using the [Dijkstra search //! algorithm](https://en.wikipedia.org/wiki/Dijkstra's_algorithm). use super::reverse_path; use crate::FxIndexMap; use indexmap::map::Entry::{Occupied, Vacant}; use num_traits::Zero; use rustc_hash::{FxHashMap, FxHashSet}; use std::cmp::Ordering; use std::collections::{BinaryHeap, HashMap}; use std::hash::Hash; /// Compute a shortest path using the [Dijkstra search /// algorithm](https://en.wikipedia.org/wiki/Dijkstra's_algorithm). /// /// The shortest path starting from `start` up to a node for which `success` returns `true` is /// computed and returned along with its total cost, in a `Some`. If no path can be found, `None` /// is returned instead. /// /// - `start` is the starting node. /// - `successors` returns a list of successors for a given node, along with the cost for moving /// from the node to the successor. This cost must be non-negative. /// - `success` checks whether the goal has been reached. It is not a node as some problems require /// a dynamic solution instead of a fixed node. /// /// A node will never be included twice in the path as determined by the `Eq` relationship. /// /// The returned path comprises both the start and end node. /// /// # Example /// /// We will search the shortest path on a chess board to go from (1, 1) to (4, 6) doing only knight /// moves. /// /// The first version uses an explicit type `Pos` on which the required traits are derived. /// /// ``` /// use pathfinding::prelude::dijkstra; /// /// #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] /// struct Pos(i32, i32); /// /// impl Pos { /// fn successors(&self) -> Vec<(Pos, usize)> { /// let &Pos(x, y) = self; /// vec![Pos(x+1,y+2), Pos(x+1,y-2), Pos(x-1,y+2), Pos(x-1,y-2), /// Pos(x+2,y+1), Pos(x+2,y-1), Pos(x-2,y+1), Pos(x-2,y-1)] /// .into_iter().map(|p| (p, 1)).collect() /// } /// } /// /// static GOAL: Pos = Pos(4, 6); /// let result = dijkstra(&Pos(1, 1), |p| p.successors(), |p| *p == GOAL); /// assert_eq!(result.expect("no path found").1, 4); /// ``` /// /// The second version does not declare a `Pos` type, makes use of more closures, /// and is thus shorter. /// /// ``` /// use pathfinding::prelude::dijkstra; /// /// static GOAL: (i32, i32) = (4, 6); /// let result = dijkstra(&(1, 1), /// |&(x, y)| vec![(x+1,y+2), (x+1,y-2), (x-1,y+2), (x-1,y-2), /// (x+2,y+1), (x+2,y-1), (x-2,y+1), (x-2,y-1)] /// .into_iter().map(|p| (p, 1)), /// |&p| p == GOAL); /// assert_eq!(result.expect("no path found").1, 4); /// ``` pub fn dijkstra( start: &N, mut successors: FN, mut success: FS, ) -> Option<(Vec, C)> where N: Eq + Hash + Clone, C: Zero + Ord + Copy, FN: FnMut(&N) -> IN, IN: IntoIterator, FS: FnMut(&N) -> bool, { dijkstra_internal(start, &mut successors, &mut success) } pub(crate) fn dijkstra_internal( start: &N, successors: &mut FN, success: &mut FS, ) -> Option<(Vec, C)> where N: Eq + Hash + Clone, C: Zero + Ord + Copy, FN: FnMut(&N) -> IN, IN: IntoIterator, FS: FnMut(&N) -> bool, { let (parents, reached) = run_dijkstra(start, successors, success); reached.map(|target| { ( reverse_path(&parents, |&(p, _)| p, target), parents.get_index(target).unwrap().1 .1, ) }) } /// Determine all reachable nodes from a starting point as well as the /// minimum cost to reach them and a possible optimal parent node /// using the [Dijkstra search /// algorithm](https://en.wikipedia.org/wiki/Dijkstra's_algorithm). /// /// - `start` is the starting node. /// - `successors` returns a list of successors for a given node, along with the cost for moving /// from the node to the successor. /// /// The result is a map where every reachable node (not including `start`) is associated with /// an optimal parent node and a cost from the start node. /// /// The [`build_path`] function can be used to build a full path from the starting point to one /// of the reachable targets. /// /// # Example /// /// We use a graph of integer nodes from 1 to 9, each node leading to its double and the value /// after it with a cost of 10 at every step. /// /// ``` /// use pathfinding::prelude::dijkstra_all; /// /// fn successors(&n: &u32) -> Vec<(u32, usize)> { /// if n <= 4 { vec![(n*2, 10), (n*2+1, 10)] } else { vec![] } /// } /// /// let reachables = dijkstra_all(&1, successors); /// assert_eq!(reachables.len(), 8); /// assert_eq!(reachables[&2], (1, 10)); // 1 -> 2 /// assert_eq!(reachables[&3], (1, 10)); // 1 -> 3 /// assert_eq!(reachables[&4], (2, 20)); // 1 -> 2 -> 4 /// assert_eq!(reachables[&5], (2, 20)); // 1 -> 2 -> 5 /// assert_eq!(reachables[&6], (3, 20)); // 1 -> 3 -> 6 /// assert_eq!(reachables[&7], (3, 20)); // 1 -> 3 -> 7 /// assert_eq!(reachables[&8], (4, 30)); // 1 -> 2 -> 4 -> 8 /// assert_eq!(reachables[&9], (4, 30)); // 1 -> 2 -> 4 -> 9 /// ``` pub fn dijkstra_all(start: &N, successors: FN) -> HashMap where N: Eq + Hash + Clone, C: Zero + Ord + Copy, FN: FnMut(&N) -> IN, IN: IntoIterator, { dijkstra_partial(start, successors, |_| false).0 } /// Determine some reachable nodes from a starting point as well as the minimum cost to /// reach them and a possible optimal parent node /// using the [Dijkstra search algorithm](https://en.wikipedia.org/wiki/Dijkstra's_algorithm). /// /// - `start` is the starting node. /// - `successors` returns a list of successors for a given node, along with the cost for moving /// from the node to the successor. /// - `stop` is a function which is called every time a node is examined (including `start`). /// A `true` return value will stop the algorithm. /// /// The result is a map where every node examined before the algorithm stopped (not including /// `start`) is associated with an optimal parent node and a cost from the start node, as well /// as the node which caused the algorithm to stop if any. /// /// The [`build_path`] function can be used to build a full path from the starting point to one /// of the reachable targets. #[allow(clippy::missing_panics_doc)] pub fn dijkstra_partial( start: &N, mut successors: FN, mut stop: FS, ) -> (HashMap, Option) where N: Eq + Hash + Clone, C: Zero + Ord + Copy, FN: FnMut(&N) -> IN, IN: IntoIterator, FS: FnMut(&N) -> bool, { let (parents, reached) = run_dijkstra(start, &mut successors, &mut stop); ( parents .iter() .skip(1) .map(|(n, (p, c))| (n.clone(), (parents.get_index(*p).unwrap().0.clone(), *c))) // unwrap() cannot fail .collect(), reached.map(|i| parents.get_index(i).unwrap().0.clone()), ) } fn run_dijkstra( start: &N, successors: &mut FN, stop: &mut FS, ) -> (FxIndexMap, Option) where N: Eq + Hash + Clone, C: Zero + Ord + Copy, FN: FnMut(&N) -> IN, IN: IntoIterator, FS: FnMut(&N) -> bool, { let mut to_see = BinaryHeap::new(); to_see.push(SmallestHolder { cost: Zero::zero(), index: 0, }); let mut parents: FxIndexMap = FxIndexMap::default(); parents.insert(start.clone(), (usize::MAX, Zero::zero())); let mut target_reached = None; while let Some(SmallestHolder { cost, index }) = to_see.pop() { let successors = { let (node, &(_, c)) = parents.get_index(index).unwrap(); if stop(node) { target_reached = Some(index); break; } // We may have inserted a node several time into the binary heap if we found // a better way to access it. Ensure that we are currently dealing with the // best path and discard the others. if cost > c { continue; } successors(node) }; for (successor, move_cost) in successors { let new_cost = cost + move_cost; let n; match parents.entry(successor) { Vacant(e) => { n = e.index(); e.insert((index, new_cost)); } Occupied(mut e) => { if e.get().1 > new_cost { n = e.index(); e.insert((index, new_cost)); } else { continue; } } } to_see.push(SmallestHolder { cost: new_cost, index: n, }); } } (parents, target_reached) } /// Build a path leading to a target according to a parents map, which must /// contain no loop. This function can be used after [`dijkstra_all`] or /// [`dijkstra_partial`] to build a path from a starting point to a reachable target. /// /// - `target` is reachable target. /// - `parents` is a map containing an optimal parent (and an associated /// cost which is ignored here) for every reachable node. /// /// This function returns a vector with a path from the farthest parent up to /// `target`, including `target` itself. /// /// # Panics /// /// If the `parents` map contains a loop, this function will attempt to build /// a path of infinite length and panic when memory is exhausted. /// /// # Example /// /// We will use a `parents` map to indicate that each integer from 2 to 100 /// parent is its integer half (2 -> 1, 3 -> 1, 4 -> 2, etc.) /// /// ``` /// use pathfinding::prelude::build_path; /// /// let parents = (2..=100).map(|n| (n, (n/2, 1))).collect(); /// assert_eq!(vec![1, 2, 4, 9, 18], build_path(&18, &parents)); /// assert_eq!(vec![1], build_path(&1, &parents)); /// assert_eq!(vec![101], build_path(&101, &parents)); /// ``` #[allow(clippy::implicit_hasher)] pub fn build_path(target: &N, parents: &HashMap) -> Vec where N: Eq + Hash + Clone, { let mut rev = vec![target.clone()]; let mut next = target.clone(); while let Some((parent, _)) = parents.get(&next) { rev.push(parent.clone()); next = parent.clone(); } rev.reverse(); rev } struct SmallestHolder { cost: K, index: usize, } impl PartialEq for SmallestHolder { fn eq(&self, other: &Self) -> bool { self.cost == other.cost } } impl Eq for SmallestHolder {} impl PartialOrd for SmallestHolder { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for SmallestHolder { fn cmp(&self, other: &Self) -> Ordering { other.cost.cmp(&self.cost) } } /// Struct returned by [`dijkstra_reach`]. pub struct DijkstraReachable { to_see: BinaryHeap>, seen: FxHashSet, parents: FxIndexMap, total_costs: FxHashMap, successors: FN, } /// Information about a node reached by [`dijkstra_reach`]. #[derive(Debug, Hash, PartialEq, Eq, Clone)] pub struct DijkstraReachableItem { /// The node that was reached by [`dijkstra_reach`]. pub node: N, /// The previous node that the current node came from. /// If the node is the first node, there will be no parent. pub parent: Option, /// The total cost from the starting node. pub total_cost: C, } impl Iterator for DijkstraReachable where N: Eq + Hash + Clone, C: Zero + Ord + Copy + Hash, FN: FnMut(&N) -> IN, IN: IntoIterator, { type Item = DijkstraReachableItem; fn next(&mut self) -> Option { while let Some(SmallestHolder { cost, index }) = self.to_see.pop() { if !self.seen.insert(index) { continue; } let item; let successors = { let (node, (parent_index, _)) = self.parents.get_index(index).unwrap(); let total_cost = self.total_costs[node]; item = Some(DijkstraReachableItem { node: node.clone(), parent: self.parents.get_index(*parent_index).map(|x| x.0.clone()), total_cost, }); (self.successors)(node) }; for (successor, move_cost) in successors { let new_cost = cost + move_cost; let n; match self.parents.entry(successor.clone()) { Vacant(e) => { n = e.index(); e.insert((index, new_cost)); self.total_costs.insert(successor.clone(), new_cost); } Occupied(mut e) => { if e.get().1 > new_cost { n = e.index(); e.insert((index, new_cost)); self.total_costs.insert(successor.clone(), new_cost); } else { continue; } } } self.to_see.push(SmallestHolder { cost: new_cost, index: n, }); } return item; } None } } /// Visit all nodes that are reachable from a start node. The node /// will be visited in order of cost, with the closest nodes first. /// /// The `successors` function receives the current node, and returns /// an iterator of successors associated with their move cost. pub fn dijkstra_reach(start: &N, successors: FN) -> DijkstraReachable where N: Eq + Hash + Clone, C: Zero + Ord + Copy, FN: FnMut(&N) -> IN, IN: IntoIterator, { let mut to_see = BinaryHeap::new(); to_see.push(SmallestHolder { cost: Zero::zero(), index: 0, }); let mut parents: FxIndexMap = FxIndexMap::default(); parents.insert(start.clone(), (usize::MAX, Zero::zero())); let mut total_costs = FxHashMap::default(); total_costs.insert(start.clone(), Zero::zero()); let seen = FxHashSet::default(); DijkstraReachable { to_see, seen, parents, total_costs, successors, } } pathfinding-4.14.0/src/directed/edmonds_karp.rs000064400000000000000000000455231046102023000176040ustar 00000000000000//! Compute the maximum flow that can go through a directed graph using the //! [Edmonds Karp algorithm](https://en.wikipedia.org/wiki/Edmonds–Karp_algorithm). //! //! This module contains several functions helping compute the flow on a given //! graph, as well as a structure which allows iterative modifications of the //! network. When the network is modified, the flow is recomputed and tries to //! take advantage of computations already performed on unchanged or augmented //! edges. use super::bfs::bfs; use crate::{matrix::Matrix, FxIndexSet}; use num_traits::{Bounded, Signed, Zero}; use std::collections::{BTreeMap, BTreeSet, VecDeque}; use std::hash::Hash; /// Type alias for Edmonds-Karp maximum flow result. pub type EKFlows = (Vec>, C, Vec>); /// Type alias for representing an edge in a graph pub type Edge = ((N, N), C); /// Compute the maximum flow and the minimal cut of a directed graph using the /// [Edmonds Karp algorithm](https://en.wikipedia.org/wiki/Edmonds–Karp_algorithm). /// /// A maximum flow going from `source` to `sink` will be computed, and the various /// flow values along with the total will be returned. /// /// - `vertices` is the collection of vertices in the graph. /// - `source` is the source node (the origin of the flow). /// - `sink` is the sink node (the target of the flow). /// - `caps` is an iterator-like object describing the positive capacities between the /// nodes. /// /// The output of this function is a tuple containing: /// /// - the various flows corresponding to the solution that has been found as a collection /// of [`Edge`](Edge) /// - the maximum capacity /// - the minimum cut corresponding to the solution that has been found as a collection /// of [`Edge`](Edge) /// /// Note that the capacity type `C` must be signed as the algorithm has to deal with /// negative residual capacities. /// /// By creating an [`EdmondsKarp`]() structure, it is possible to adjust the capacities /// after computing the maximum flow and rerun the algorithm without starting from /// scratch. This function is a helper function that remaps the `N` node type to /// appropriate indices. /// /// # Panics /// /// This function panics if `source` or `sink` is not found in `vertices`. pub fn edmonds_karp(vertices: &[N], source: &N, sink: &N, caps: IC) -> EKFlows where N: Eq + Hash + Copy, C: Zero + Bounded + Signed + Ord + Copy, IC: IntoIterator>, EK: EdmondsKarp, { // Build a correspondence between N and 0..vertices.len() so that we can // work with matrices more easily. let reverse = vertices.iter().collect::>(); let mut capacities = EK::new( vertices.len(), reverse .get_index_of(source) .unwrap_or_else(|| panic!("source not found in vertices")), reverse .get_index_of(sink) .unwrap_or_else(|| panic!("sink not found in vertices")), ); for ((from, to), capacity) in caps { capacities.set_capacity( reverse.get_index_of(&from).unwrap(), reverse.get_index_of(&to).unwrap(), capacity, ); } let (paths, max, cut) = capacities.augment(); ( paths .into_iter() .map(|((a, b), c)| ((vertices[a], vertices[b]), c)) .collect(), max, cut.into_iter() .map(|((a, b), c)| ((vertices[a], vertices[b]), c)) .collect(), ) } /// Helper for the `edmonds_karp` function using an adjacency matrix for dense graphs. pub fn edmonds_karp_dense(vertices: &[N], source: &N, sink: &N, caps: IC) -> EKFlows where N: Eq + Hash + Copy, C: Zero + Bounded + Signed + Ord + Copy, IC: IntoIterator>, { edmonds_karp::>(vertices, source, sink, caps) } /// Helper for the `edmonds_karp` function using adjacency maps for sparse graphs. pub fn edmonds_karp_sparse( vertices: &[N], source: &N, sink: &N, caps: IC, ) -> EKFlows where N: Eq + Hash + Copy, C: Zero + Bounded + Signed + Ord + Copy, IC: IntoIterator>, { edmonds_karp::>(vertices, source, sink, caps) } /// Representation of capacity and flow data. pub trait EdmondsKarp { /// Create a new empty structure. /// /// # Panics /// /// This function panics when `source` or `sink` is greater or equal than `size`. fn new(size: usize, source: usize, sink: usize) -> Self where Self: Sized; /// Create a new populated structure. /// /// # Panics /// /// This function panics when `source` or `sink` is greater or equal than the /// number of rows in the `capacities` matrix, or it the matrix is not /// a square one. fn from_matrix(source: usize, sink: usize, capacities: Matrix) -> Self where Self: Sized; /// Create a new populated structure. /// /// # Panics /// /// This function panics when `source` or `sink` is greater or equal than the /// number of rows in the square matrix created from the `capacities` vector. #[must_use] fn from_vec(source: usize, sink: usize, capacities: Vec) -> Self where Self: Sized, { Self::from_matrix(source, sink, Matrix::square_from_vec(capacities).unwrap()) } /// Common data. fn common(&self) -> &Common; /// Mutable common data. fn common_mut(&mut self) -> &mut Common; /// Number of nodes. fn size(&self) -> usize { self.common().size } /// Source. fn source(&self) -> usize { self.common().source } /// Sink. fn sink(&self) -> usize { self.common().sink } /// List of successors with positive residual capacity and this capacity. fn residual_successors(&self, from: usize) -> Vec<(usize, C)>; /// Residual capacity between two nodes. fn residual_capacity(&self, from: usize, to: usize) -> C; /// Flow between two nodes. fn flow(&self, from: usize, to: usize) -> C; /// All positive flows starting from a node. fn flows_from(&self, from: usize) -> Vec; /// All flows between nodes. fn flows(&self) -> Vec<((usize, usize), C)>; /// Set capacity between two nodes. fn set_capacity(&mut self, from: usize, to: usize, capacity: C) { let flow = self.flow(from, to); let delta = capacity - (self.residual_capacity(from, to) + flow); if capacity < flow { let to_cancel = flow - capacity; self.add_flow(to, from, to_cancel); let source = self.source(); self.cancel_flow(source, from, to_cancel); let sink = self.sink(); self.cancel_flow(to, sink, to_cancel); self.common_mut().total_capacity = self.common().total_capacity - to_cancel; } self.add_residual_capacity(from, to, delta); } /// Add a given flow between two nodes. This should not be used /// directly. fn add_flow(&mut self, from: usize, to: usize, capacity: C); /// Get total capacity. fn total_capacity(&self) -> C { self.common().total_capacity } /// Add some residual capacity. fn add_residual_capacity(&mut self, from: usize, to: usize, capacity: C); /// Set total capacity. fn set_total_capacity(&mut self, capacity: C) { self.common_mut().total_capacity = capacity; } /// Do not request the detailed flows and cuts as a result. The returned /// flows and cuts will be empty vectors. fn omit_details(&mut self) { self.common_mut().details = false; } /// Are detailed flows and cuts requested? fn has_details(&self) -> bool { self.common().details } /// Compute the maximum flow and minimum cut. fn augment(&mut self) -> EKFlows { let source_nodes = self.update_flows(); if self.has_details() { let cuts = self .flows() .iter() .filter(|((from, to), _)| source_nodes.contains(from) && !source_nodes.contains(to)) .copied() .collect::>(); (self.flows(), self.total_capacity(), cuts) } else { (Vec::new(), self.total_capacity(), Vec::new()) } } } trait EdmondsKarpInternal { fn update_flows(&mut self) -> BTreeSet; fn cancel_flow(&mut self, from: usize, to: usize, capacity: C); } impl EdmondsKarpInternal for T where C: Copy + Zero + Signed + Ord + Bounded, T: EdmondsKarp + ?Sized, { /// Internal: update flows until maximum-flow / minimum-cut is reached. fn update_flows(&mut self) -> BTreeSet { let size = self.size(); let source = self.source(); let sink = self.sink(); let mut parents = vec![None; size]; let mut path_capacity = vec![C::max_value(); size]; let mut to_see = VecDeque::new(); let mut seen = BTreeSet::new(); 'augment: loop { to_see.clear(); to_see.push_back(source); seen.clear(); while let Some(node) = to_see.pop_front() { seen.insert(node); let capacity_so_far = path_capacity[node]; for (successor, residual) in self.residual_successors(node).iter().copied() { if successor == source || parents[successor].is_some() { continue; } parents[successor] = Some(node); path_capacity[successor] = if capacity_so_far < residual { capacity_so_far } else { residual }; if successor == sink { let mut n = sink; while n != source { let p = parents[n].unwrap(); self.add_flow(p, n, path_capacity[sink]); n = p; } let total = self.total_capacity(); self.set_total_capacity(total + path_capacity[sink]); parents.fill(None); path_capacity.fill(C::max_value()); continue 'augment; } to_see.push_back(successor); } } break; } seen } /// Internal: cancel a flow capacity between two nodes. fn cancel_flow(&mut self, from: usize, to: usize, mut capacity: C) { if from == to { return; } while capacity > Zero::zero() { let Some(path) = bfs(&from, |&n| self.flows_from(n).into_iter(), |&n| n == to) else { unreachable!("no flow to cancel"); }; let path = path .clone() .into_iter() .zip(path.into_iter().skip(1)) .collect::>(); let mut max_cancelable = path .iter() .map(|&(src, dst)| self.flow(src, dst)) .min() .unwrap(); if max_cancelable > capacity { max_cancelable = capacity; } for (src, dst) in path { self.add_flow(dst, src, max_cancelable); } capacity = capacity - max_cancelable; } } } /// Common fields. #[derive(Clone, Debug)] pub struct Common { size: usize, source: usize, sink: usize, total_capacity: C, details: bool, } /// Sparse capacity and flow data. #[derive(Clone, Debug)] pub struct SparseCapacity { common: Common, flows: BTreeMap>, residuals: BTreeMap>, } unsafe impl Send for SparseCapacity {} impl SparseCapacity { fn set_value(data: &mut BTreeMap>, from: usize, to: usize, value: C) { let to_remove = { let sub = data.entry(from).or_default(); if value == Zero::zero() { sub.remove(&to); } else { sub.insert(to, value); } sub.is_empty() }; if to_remove { data.remove(&from); } } fn get_value(data: &BTreeMap>, from: usize, to: usize) -> C { data.get(&from) .and_then(|ns| ns.get(&to).copied()) .unwrap_or_else(Zero::zero) } } impl EdmondsKarp for SparseCapacity { fn new(size: usize, source: usize, sink: usize) -> Self { assert!(source < size, "source is greater or equal than size"); assert!(sink < size, "sink is greater or equal than size"); Self { common: Common { size, source, sink, total_capacity: Zero::zero(), details: true, }, flows: BTreeMap::new(), residuals: BTreeMap::new(), } } #[must_use] fn from_matrix(source: usize, sink: usize, capacities: Matrix) -> Self { assert!( capacities.is_square(), "capacities matrix is not a square one" ); let size = capacities.rows; assert!(source < size, "source is greater or equal than matrix side"); assert!(sink < size, "sink is greater or equal than matrix side"); let mut result = Self::new(size, source, sink); for from in 0..size { for to in 0..size { let capacity = capacities[(from, to)]; if capacity > Zero::zero() { result.set_capacity(from, to, capacity); } } } result } fn common(&self) -> &Common { &self.common } fn common_mut(&mut self) -> &mut Common { &mut self.common } fn residual_successors(&self, from: usize) -> Vec<(usize, C)> { self.residuals.get(&from).map_or_else(Vec::new, |ns| { ns.iter() .filter_map(|(&n, &c)| (c > Zero::zero()).then_some((n, c))) .collect() }) } fn residual_capacity(&self, from: usize, to: usize) -> C { Self::get_value(&self.residuals, from, to) } fn flow(&self, from: usize, to: usize) -> C { Self::get_value(&self.flows, from, to) } fn flows(&self) -> Vec<((usize, usize), C)> { self.flows .clone() .into_iter() .flat_map(|(k, vs)| { vs.into_iter() .filter_map(move |(v, c)| (c > Zero::zero()).then_some(((k, v), c))) }) .collect() } fn add_flow(&mut self, from: usize, to: usize, capacity: C) { let direct = self.flow(from, to) + capacity; Self::set_value(&mut self.flows, from, to, direct); Self::set_value(&mut self.flows, to, from, -direct); self.add_residual_capacity(from, to, -capacity); self.add_residual_capacity(to, from, capacity); } fn add_residual_capacity(&mut self, from: usize, to: usize, capacity: C) { let new_capacity = self.residual_capacity(from, to) + capacity; Self::set_value(&mut self.residuals, from, to, new_capacity); } fn flows_from(&self, n: usize) -> Vec { self.flows.get(&n).map_or_else(Vec::new, |ns| { ns.iter() .filter_map(|(&o, &c)| (c > Zero::zero()).then_some(o)) .collect() }) } } /// Dense capacity and flow data. #[derive(Clone, Debug)] pub struct DenseCapacity { common: Common, residuals: Matrix, flows: Matrix, } unsafe impl Send for DenseCapacity {} impl EdmondsKarp for DenseCapacity { #[must_use] fn new(size: usize, source: usize, sink: usize) -> Self { assert!(source < size, "source is greater or equal than size"); assert!(sink < size, "sink is greater or equal than size"); Self { common: Common { size, source, sink, total_capacity: Zero::zero(), details: true, }, residuals: Matrix::new(size, size, Zero::zero()), flows: Matrix::new(size, size, Zero::zero()), } } #[must_use] fn from_matrix(source: usize, sink: usize, capacities: Matrix) -> Self { assert!( capacities.is_square(), "capacities matrix is not a square one" ); let size = capacities.rows; assert!(source < size, "source is greater or equal than matrix side"); assert!(sink < size, "sink is greater or equal than matrix side"); Self { common: Common { size, source, sink, total_capacity: Zero::zero(), details: true, }, residuals: capacities, flows: Matrix::new(size, size, Zero::zero()), } } fn common(&self) -> &Common { &self.common } fn common_mut(&mut self) -> &mut Common { &mut self.common } fn residual_successors(&self, from: usize) -> Vec<(usize, C)> { (0..self.common.size) .filter_map(|n| { let residual = self.residual_capacity(from, n); (residual > Zero::zero()).then_some((n, residual)) }) .collect() } fn residual_capacity(&self, from: usize, to: usize) -> C { self.residuals[(from, to)] } fn flow(&self, from: usize, to: usize) -> C { self.flows[(from, to)] } fn flows(&self) -> Vec<((usize, usize), C)> { (0..self.size()) .flat_map(|from| (0..self.size()).map(move |to| (from, to))) .filter_map(|(from, to)| { let flow = self.flow(from, to); (flow > Zero::zero()).then_some(((from, to), flow)) }) .collect() } fn add_flow(&mut self, from: usize, to: usize, capacity: C) { self.flows[(from, to)] = self.flows[(from, to)] + capacity; self.flows[(to, from)] = self.flows[(to, from)] - capacity; self.residuals[(from, to)] = self.residuals[(from, to)] - capacity; self.residuals[(to, from)] = self.residuals[(to, from)] + capacity; } fn add_residual_capacity(&mut self, from: usize, to: usize, capacity: C) { self.residuals[(from, to)] = self.residual_capacity(from, to) + capacity; } fn flows_from(&self, from: usize) -> Vec { (0..self.common.size) .filter(|to| self.flow(from, *to) > Zero::zero()) .collect() } } pathfinding-4.14.0/src/directed/fringe.rs000064400000000000000000000126351046102023000164060ustar 00000000000000//! Compute a shortest path using the [Fringe search //! algorithm](https://en.wikipedia.org/wiki/Fringe_search). use super::reverse_path; use crate::FxIndexMap; use indexmap::map::Entry::{Occupied, Vacant}; use num_traits::{Bounded, Zero}; use std::collections::VecDeque; use std::hash::Hash; use std::mem; /// Compute a shortest path using the [Fringe search /// algorithm](https://en.wikipedia.org/wiki/Fringe_search). /// /// The shortest path starting from `start` up to a node for which `success` returns `true` is /// computed and returned along with its total cost, in a `Some`. If no path can be found, `None` /// is returned instead. /// /// - `start` is the starting node. /// - `successors` returns a list of successors for a given node, along with the cost for moving /// from the node to the successor. This cost must be non-negative. /// - `heuristic` returns an approximation of the cost from a given node to the goal. The /// approximation must not be greater than the real cost, or a wrong shortest path may be returned. /// - `success` checks whether the goal has been reached. It is not a node as some problems require /// a dynamic solution instead of a fixed node. /// /// A node will never be included twice in the path as determined by the `Eq` relationship. /// /// The returned path comprises both the start and end node. /// /// # Example /// /// We will search the shortest path on a chess board to go from (1, 1) to (4, 6) doing only knight /// moves. /// /// The first version uses an explicit type `Pos` on which the required traits are derived. /// /// ``` /// use pathfinding::prelude::fringe; /// /// #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] /// struct Pos(i32, i32); /// /// impl Pos { /// fn distance(&self, other: &Pos) -> u32 { /// (self.0.abs_diff(other.0) + self.1.abs_diff(other.1)) as u32 /// } /// /// fn successors(&self) -> Vec<(Pos, u32)> { /// let &Pos(x, y) = self; /// vec![Pos(x+1,y+2), Pos(x+1,y-2), Pos(x-1,y+2), Pos(x-1,y-2), /// Pos(x+2,y+1), Pos(x+2,y-1), Pos(x-2,y+1), Pos(x-2,y-1)] /// .into_iter().map(|p| (p, 1)).collect() /// } /// } /// /// static GOAL: Pos = Pos(4, 6); /// let result = fringe(&Pos(1, 1), /// |p| p.successors(), /// |p| p.distance(&GOAL) / 3, /// |p| *p == GOAL); /// assert_eq!(result.expect("no path found").1, 4); /// ``` /// /// The second version does not declare a `Pos` type, makes use of more closures, /// and is thus shorter. /// /// ``` /// use pathfinding::prelude::fringe; /// /// static GOAL: (i32, i32) = (4, 6); /// let result = fringe(&(1, 1), /// |&(x, y)| vec![(x+1,y+2), (x+1,y-2), (x-1,y+2), (x-1,y-2), /// (x+2,y+1), (x+2,y-1), (x-2,y+1), (x-2,y-1)] /// .into_iter().map(|p| (p, 1)), /// |&(x, y)| (GOAL.0.abs_diff(x) + GOAL.1.abs_diff(y)) / 3, /// |&p| p == GOAL); /// assert_eq!(result.expect("no path found").1, 4); /// ``` #[allow(clippy::missing_panics_doc)] pub fn fringe( start: &N, mut successors: FN, mut heuristic: FH, mut success: FS, ) -> Option<(Vec, C)> where N: Eq + Hash + Clone, C: Bounded + Zero + Ord + Copy, FN: FnMut(&N) -> IN, IN: IntoIterator, FH: FnMut(&N) -> C, FS: FnMut(&N) -> bool, { let mut now = VecDeque::new(); let mut later = VecDeque::new(); let mut parents: FxIndexMap = FxIndexMap::default(); let mut flimit = heuristic(start); now.push_back(0); parents.insert(start.clone(), (usize::MAX, Zero::zero())); loop { if now.is_empty() { return None; } let mut fmin = C::max_value(); while let Some(i) = now.pop_front() { let (g, successors) = { let (node, &(_, g)) = parents.get_index(i).unwrap(); // Cannot fail let f = g + heuristic(node); if f > flimit { if f < fmin { fmin = f; } later.push_back(i); continue; } if success(node) { let path = reverse_path(&parents, |&(p, _)| p, i); return Some((path, g)); } (g, successors(node)) }; for (successor, cost) in successors { let g_successor = g + cost; let n; // index for successor match parents.entry(successor) { Vacant(e) => { n = e.index(); e.insert((i, g_successor)); } Occupied(mut e) => { if e.get().1 > g_successor { n = e.index(); e.insert((i, g_successor)); } else { continue; } } } if !remove(&mut later, &n) { remove(&mut now, &n); } now.push_front(n); } } mem::swap(&mut now, &mut later); flimit = fmin; } } fn remove(v: &mut VecDeque, e: &T) -> bool { v.iter().position(|x| x == e).is_some_and(|index| { v.remove(index); true }) } pathfinding-4.14.0/src/directed/idastar.rs000064400000000000000000000121631046102023000165570ustar 00000000000000//! Compute a shortest path using the [IDA* search //! algorithm](https://en.wikipedia.org/wiki/Iterative_deepening_A*). use num_traits::Zero; /// Compute a shortest path using the [IDA* search /// algorithm](https://en.wikipedia.org/wiki/Iterative_deepening_A*). /// /// The shortest path starting from `start` up to a node for which `success` returns `true` is /// computed and returned along with its total cost, in a `Some`. If no path can be found, `None` /// is returned instead. /// /// - `start` is the starting node. /// - `successors` returns a list of successors for a given node, along with the cost for moving /// from the node to the successor. This cost must be non-negative. /// - `heuristic` returns an approximation of the cost from a given node to the goal. The /// approximation must not be greater than the real cost, or a wrong shortest path may be returned. /// - `success` checks whether the goal has been reached. It is not a node as some problems require /// a dynamic solution instead of a fixed node. /// /// A node will never be included twice in the path as determined by the `Eq` relationship. /// /// The returned path comprises both the start and end node. /// /// # Example /// /// We will search the shortest path on a chess board to go from (1, 1) to (4, 6) doing only knight /// moves. /// /// The first version uses an explicit type `Pos` on which the required traits are derived. /// /// ``` /// use pathfinding::prelude::idastar; /// /// #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] /// struct Pos(i32, i32); /// /// impl Pos { /// fn distance(&self, other: &Pos) -> u32 { /// (self.0.abs_diff(other.0) + self.1.abs_diff(other.1)) as u32 /// } /// /// fn successors(&self) -> Vec<(Pos, u32)> { /// let &Pos(x, y) = self; /// vec![Pos(x+1,y+2), Pos(x+1,y-2), Pos(x-1,y+2), Pos(x-1,y-2), /// Pos(x+2,y+1), Pos(x+2,y-1), Pos(x-2,y+1), Pos(x-2,y-1)] /// .into_iter().map(|p| (p, 1)).collect() /// } /// } /// /// static GOAL: Pos = Pos(4, 6); /// let result = idastar(&Pos(1, 1), |p| p.successors(), |p| p.distance(&GOAL) / 3, /// |p| *p == GOAL); /// assert_eq!(result.expect("no path found").1, 4); /// ``` /// /// The second version does not declare a `Pos` type, makes use of more closures, /// and is thus shorter. /// /// ``` /// use pathfinding::prelude::idastar; /// /// static GOAL: (i32, i32) = (4, 6); /// let result = idastar(&(1, 1), /// |&(x, y)| vec![(x+1,y+2), (x+1,y-2), (x-1,y+2), (x-1,y-2), /// (x+2,y+1), (x+2,y-1), (x-2,y+1), (x-2,y-1)] /// .into_iter().map(|p| (p, 1)), /// |&(x, y)| (GOAL.0.abs_diff(x) + GOAL.1.abs_diff(y)) / 3, /// |&p| p == GOAL); /// assert_eq!(result.expect("no path found").1, 4); /// ``` pub fn idastar( start: &N, mut successors: FN, mut heuristic: FH, mut success: FS, ) -> Option<(Vec, C)> where N: Eq + Clone, C: Zero + Ord + Copy, FN: FnMut(&N) -> IN, IN: IntoIterator, FH: FnMut(&N) -> C, FS: FnMut(&N) -> bool, { let mut bound = heuristic(start); let mut path = vec![start.clone()]; loop { match search( &mut path, Zero::zero(), bound, &mut successors, &mut heuristic, &mut success, ) { Path::Found(path, cost) => return Some((path, cost)), Path::Minimum(min) => { if bound == min { return None; } bound = min; } Path::Impossible => return None, } } } enum Path { Found(Vec, C), Minimum(C), Impossible, } fn search( path: &mut Vec, cost: C, bound: C, successors: &mut FN, heuristic: &mut FH, success: &mut FS, ) -> Path where N: Eq + Clone, C: Zero + Ord + Copy, FN: FnMut(&N) -> IN, IN: IntoIterator, FH: FnMut(&N) -> C, FS: FnMut(&N) -> bool, { let neighbs = { let start = &path[path.len() - 1]; let f = cost + heuristic(start); if f > bound { return Path::Minimum(f); } if success(start) { return Path::Found(path.clone(), f); } let mut neighbs = successors(start) .into_iter() .filter_map(|(n, c)| { (!path.contains(&n)).then(|| { let h = heuristic(&n); (n, c, c + h) }) }) .collect::>(); neighbs.sort_unstable_by(|(_, _, c1), (_, _, c2)| c1.cmp(c2)); neighbs }; let mut min = None; for (node, extra, _) in neighbs { path.push(node); match search(path, cost + extra, bound, successors, heuristic, success) { found_path @ Path::Found(_, _) => return found_path, Path::Minimum(m) if !min.is_some_and(|n| n < m) => min = Some(m), _ => (), } path.pop(); } min.map_or(Path::Impossible, Path::Minimum) } pathfinding-4.14.0/src/directed/iddfs.rs000064400000000000000000000073751046102023000162320ustar 00000000000000//! Compute a shortest path using the [iterative deepening depth-first search //! algorithm](https://en.wikipedia.org/wiki/Iterative_deepening_depth-first_search). /// Compute a shortest path using the [iterative deepening depth-first search /// algorithm](https://en.wikipedia.org/wiki/Iterative_deepening_depth-first_search). /// /// The shortest path starting from `start` up to a node for which `success` returns `true` is /// computed and returned in a `Some`. If no path can be found, `None` /// is returned instead. /// /// - `start` is the starting node. /// - `successors` returns a list of successors for a given node. /// - `success` checks whether the goal has been reached. It is not a node as some problems require /// a dynamic solution instead of a fixed node. /// /// A node will never be included twice in the path as determined by the `Eq` relationship. /// /// The returned path comprises both the start and end node. Note that the start node ownership /// is taken by `iddfs` as no clones are made. /// /// # Example /// /// We will search the shortest path on a chess board to go from (1, 1) to (4, 6) doing only knight /// moves. /// /// The first version uses an explicit type `Pos` on which the required traits are derived. /// /// ``` /// use pathfinding::prelude::iddfs; /// /// #[derive(Eq, PartialEq)] /// struct Pos(i32, i32); /// /// impl Pos { /// fn successors(&self) -> Vec { /// let &Pos(x, y) = self; /// vec![Pos(x+1,y+2), Pos(x+1,y-2), Pos(x-1,y+2), Pos(x-1,y-2), /// Pos(x+2,y+1), Pos(x+2,y-1), Pos(x-2,y+1), Pos(x-2,y-1)] /// } /// } /// /// static GOAL: Pos = Pos(4, 6); /// let result = iddfs(Pos(1, 1), |p| p.successors(), |p| *p == GOAL); /// assert_eq!(result.expect("no path found").len(), 5); /// ``` /// /// The second version does not declare a `Pos` type, makes use of more closures, /// and is thus shorter. /// /// ``` /// use pathfinding::prelude::iddfs; /// /// static GOAL: (i32, i32) = (4, 6); /// let result = iddfs((1, 1), /// |&(x, y)| vec![(x+1,y+2), (x+1,y-2), (x-1,y+2), (x-1,y-2), /// (x+2,y+1), (x+2,y-1), (x-2,y+1), (x-2,y-1)], /// |&p| p == GOAL); /// assert_eq!(result.expect("no path found").len(), 5); /// ``` pub fn iddfs(start: N, mut successors: FN, mut success: FS) -> Option> where N: Eq, FN: FnMut(&N) -> IN, IN: IntoIterator, FS: FnMut(&N) -> bool, { let mut path = vec![start]; let mut current_max_depth: usize = 1; loop { match step(&mut path, &mut successors, &mut success, current_max_depth) { Path::FoundOptimum => return Some(path), Path::NoneAtThisDepth => current_max_depth += 1, Path::Impossible => return None, } } } #[derive(Debug)] enum Path { FoundOptimum, Impossible, NoneAtThisDepth, } fn step( path: &mut Vec, successors: &mut FN, success: &mut FS, depth: usize, ) -> Path where N: Eq, FN: FnMut(&N) -> IN, IN: IntoIterator, FS: FnMut(&N) -> bool, { if depth == 0 { Path::NoneAtThisDepth } else if success(path.last().unwrap()) { Path::FoundOptimum } else { let successors_it = successors(path.last().unwrap()); let mut best_result = Path::Impossible; for n in successors_it { if !path.contains(&n) { path.push(n); match step(path, successors, success, depth - 1) { Path::FoundOptimum => return Path::FoundOptimum, Path::NoneAtThisDepth => best_result = Path::NoneAtThisDepth, Path::Impossible => (), } path.pop(); } } best_result } } pathfinding-4.14.0/src/directed/mod.rs000064400000000000000000000016521046102023000157100ustar 00000000000000//! Algorithms for directed graphs. use super::FxIndexMap; use std::hash::Hash; pub mod astar; pub mod bfs; pub mod count_paths; pub mod cycle_detection; pub mod dfs; pub mod dijkstra; pub mod edmonds_karp; pub mod fringe; pub mod idastar; pub mod iddfs; pub mod strongly_connected_components; pub mod topological_sort; pub mod yen; #[allow(clippy::needless_collect)] fn reverse_path(parents: &FxIndexMap, mut parent: F, start: usize) -> Vec where N: Eq + Hash + Clone, F: FnMut(&V) -> usize, { let mut i = start; let path = std::iter::from_fn(|| { parents.get_index(i).map(|(node, value)| { i = parent(value); node }) }) .collect::>(); // Collecting the going through the vector is needed to revert the path because the // unfold iterator is not double-ended due to its iterative nature. path.into_iter().rev().cloned().collect() } pathfinding-4.14.0/src/directed/strongly_connected_components.rs000064400000000000000000000100761046102023000233010ustar 00000000000000//! Separate nodes of a directed graph into [strongly connected //! components](https://en.wikipedia.org/wiki/Strongly_connected_component). //! //! A [path-based strong component //! algorithm](https://en.wikipedia.org/wiki/Path-based_strong_component_algorithm) //! is used. use std::collections::{HashMap, HashSet}; use std::hash::Hash; struct Params where N: Hash + Eq, { preorders: HashMap>, c: usize, successors: FN, p: Vec, s: Vec, scc: Vec>, scca: HashSet, } impl Params where N: Clone + Hash + Eq, FN: FnMut(&N) -> IN, IN: IntoIterator, { fn new(nodes: &[N], successors: FN) -> Self { Self { preorders: nodes .iter() .map(|n| (n.clone(), None)) .collect::>>(), c: 0, successors, p: Vec::new(), s: Vec::new(), scc: Vec::new(), scca: HashSet::new(), } } } fn recurse_onto(v: &N, params: &mut Params) where N: Clone + Hash + Eq, FN: FnMut(&N) -> IN, IN: IntoIterator, { params.preorders.insert(v.clone(), Some(params.c)); params.c += 1; params.s.push(v.clone()); params.p.push(v.clone()); for w in (params.successors)(v) { if !params.scca.contains(&w) { if let Some(pw) = params.preorders.get(&w).and_then(|w| *w) { while params.preorders[¶ms.p[params.p.len() - 1]].unwrap() > pw { params.p.pop(); } } else { recurse_onto(&w, params); } } } if params.p[params.p.len() - 1] == *v { params.p.pop(); let mut component = Vec::new(); while let Some(node) = params.s.pop() { component.push(node.clone()); params.scca.insert(node.clone()); params.preorders.remove(&node); if node == *v { break; } } params.scc.push(component); } } /// Partition nodes reachable from a starting point into strongly connected components. /// /// - `start` is the node we want to explore the graph from. /// - `successors` returns a list of successors for a given node. /// /// The function returns a list of strongly connected components sets. It will contain /// at least one component (the one containing the `start` node). pub fn strongly_connected_components_from(start: &N, successors: FN) -> Vec> where N: Clone + Hash + Eq, FN: FnMut(&N) -> IN, IN: IntoIterator, { let mut params = Params::new(&[], successors); recurse_onto(start, &mut params); params.scc } /// Compute the strongly connected component containing a given node. /// /// - `node` is the node we want the strongly connected component for. /// - `successors` returns a list of successors for a given node. /// /// The function returns the strongly connected component containing the node, /// which is guaranteed to contain at least `node`. #[allow(clippy::missing_panics_doc)] pub fn strongly_connected_component(node: &N, successors: FN) -> Vec where N: Clone + Hash + Eq, FN: FnMut(&N) -> IN, IN: IntoIterator, { // The unwrap() cannot fail as there will always be at least one group. strongly_connected_components_from(node, successors) .pop() .unwrap() } /// Partition all strongly connected components in a graph. /// /// - `nodes` is a collection of nodes. /// - `successors` returns a list of successors for a given node. /// /// The function returns a list of strongly connected components sets. pub fn strongly_connected_components(nodes: &[N], successors: FN) -> Vec> where N: Clone + Hash + Eq, FN: FnMut(&N) -> IN, IN: IntoIterator, { let mut params = Params::new(nodes, successors); while let Some(node) = params.preorders.keys().find(|_| true).cloned() { recurse_onto(&node, &mut params); } params.scc } pathfinding-4.14.0/src/directed/topological_sort.rs000064400000000000000000000163561046102023000205230ustar 00000000000000//! Find a topological order in a directed graph if one exists. use std::collections::{HashMap, HashSet, VecDeque}; use std::hash::Hash; use std::mem; /// Find a topological order in a directed graph if one exists. /// /// - `roots` is a collection of nodes that ought to be explored. /// - `successors` returns a list of successors for a given node, including possibly /// nodes that were not present in `roots`. /// /// The function returns an acceptable topological order of nodes given as roots or /// discovered, or an error if a cycle is detected. /// /// # Errors /// /// If a cycle is found, `Err(n)` is returned with `n` being an arbitrary node involved in a cycle. /// In this case case, the strongly connected set can then be found using the /// [`strongly_connected_component`](super::strongly_connected_components::strongly_connected_component) /// function, or if only one of the loops is needed the [`bfs_loop`](super::bfs::bfs_loop) function /// can be used instead to identify one of the shortest loops involving this node. /// /// # Examples /// /// We will sort integers from 1 to 9, each integer having its two immediate /// greater numbers as successors, starting with two roots 5 and 1: /// /// ``` /// use pathfinding::prelude::topological_sort; /// /// fn successors(node: &usize) -> Vec { /// match *node { /// n if n <= 7 => vec![n+1, n+2], /// 8 => vec![9], /// _ => vec![], /// } /// } /// /// let sorted = topological_sort(&[5, 1], successors); /// assert_eq!(sorted, Ok(vec![1, 2, 3, 4, 5, 6, 7, 8, 9])); /// ``` /// /// If, however, there is a loop in the graph (for example, all nodes but 7 /// have also 7 has a successor), one of the nodes in the loop will be returned as /// an error: /// /// ``` /// use pathfinding::prelude::*; /// /// fn successors(node: &usize) -> Vec { /// match *node { /// n if n <= 6 => vec![n+1, n+2, 7], /// 7 => vec![8, 9], /// 8 => vec![7, 9], /// _ => vec![7], /// } /// } /// /// let sorted = topological_sort(&[5, 1], successors); /// assert!(sorted.is_err()); /// /// // Let's assume that the returned node is 8 (it can be any node which is part /// // of a loop). We can lookup up one of the shortest loops containing 8 /// // (8 -> 7 -> 8 is the unique loop with two hops containing 8): /// /// assert_eq!(bfs_loop(&8, successors), Some(vec![8, 7, 8])); /// /// // We can also request the whole strongly connected set containing 8. Here /// // 7, 8, and 9 are all reachable from one another. /// /// let mut set = strongly_connected_component(&8, successors); /// set.sort(); /// assert_eq!(set, vec![7, 8, 9]); /// ``` pub fn topological_sort(roots: &[N], mut successors: FN) -> Result, N> where N: Eq + Hash + Clone, FN: FnMut(&N) -> IN, IN: IntoIterator, { let mut marked = HashSet::with_capacity(roots.len()); let mut temp = HashSet::new(); let mut sorted = VecDeque::with_capacity(roots.len()); let mut roots: HashSet = roots.iter().cloned().collect::>(); while let Some(node) = roots.iter().next().cloned() { temp.clear(); visit( &node, &mut successors, &mut roots, &mut marked, &mut temp, &mut sorted, )?; } Ok(sorted.into_iter().collect()) } fn visit( node: &N, successors: &mut FN, unmarked: &mut HashSet, marked: &mut HashSet, temp: &mut HashSet, sorted: &mut VecDeque, ) -> Result<(), N> where N: Eq + Hash + Clone, FN: FnMut(&N) -> IN, IN: IntoIterator, { unmarked.remove(node); if marked.contains(node) { return Ok(()); } if temp.contains(node) { return Err(node.clone()); } temp.insert(node.clone()); for n in successors(node) { visit(&n, successors, unmarked, marked, temp, sorted)?; } marked.insert(node.clone()); sorted.push_front(node.clone()); Ok(()) } /// Topologically sort a directed graph into groups of independent nodes. /// /// - `nodes` is a collection of nodes. /// - `successors` returns a list of successors for a given node. /// /// This function works like [`topological_sort`], but rather than /// producing a single ordering of nodes, this function partitions the /// nodes into groups: the first group contains all nodes with no /// dependencies, the second group contains all nodes whose only /// dependencies are in the first group, and so on. Concatenating the /// groups produces a valid topological sort regardless of how the /// nodes within each group are reordered. No guarantees are made /// about the order of nodes within each group. Also, the list of /// `nodes` must be exhaustive, new nodes must not be returned by the /// `successors` function. /// /// The function returns a collection of groups if there are no cycles in the /// graph and an error otherwise. /// /// # Errors /// /// A tuple `(groups, remaining)` containing a (possibly empty) partial list of /// groups, and a list of remaining nodes that could not be grouped due to cycles. /// In this case, the strongly connected set(s) can then be found using the /// [`strongly_connected_components`](super::strongly_connected_components::strongly_connected_components) /// function on the list of remaining nodes. #[allow(clippy::type_complexity)] #[allow(clippy::missing_panics_doc)] pub fn topological_sort_into_groups( nodes: &[N], mut successors: FN, ) -> Result>, (Vec>, Vec)> where N: Eq + Hash + Clone, FN: FnMut(&N) -> IN, IN: IntoIterator, { if nodes.is_empty() { return Ok(Vec::new()); } let mut succs_map = HashMap::>::with_capacity(nodes.len()); let mut preds_map = HashMap::::with_capacity(nodes.len()); for node in nodes { succs_map.insert(node.clone(), successors(node).into_iter().collect()); preds_map.insert(node.clone(), 0); } for succs in succs_map.values() { for succ in succs { *preds_map.get_mut(succ).unwrap() += 1; // Cannot fail } } let mut groups = Vec::>::new(); let mut prev_group: Vec = preds_map .iter() .filter(|&(_, num_preds)| *num_preds == 0) .map(|(node, _)| node.clone()) .collect(); if prev_group.is_empty() { let remaining: Vec = preds_map.into_keys().collect(); return Err((Vec::new(), remaining)); } for node in &prev_group { preds_map.remove(node); } while !preds_map.is_empty() { let mut next_group = Vec::::new(); for node in &prev_group { for succ in &succs_map[node] { { let num_preds = preds_map.get_mut(succ).unwrap(); // Cannot fail *num_preds -= 1; if *num_preds > 0 { continue; } } next_group.push(preds_map.remove_entry(succ).unwrap().0); // Cannot fail } } groups.push(mem::replace(&mut prev_group, next_group)); if prev_group.is_empty() { let remaining: Vec = preds_map.into_keys().collect(); return Err((groups, remaining)); } } groups.push(prev_group); Ok(groups) } pathfinding-4.14.0/src/directed/yen.rs000064400000000000000000000162321046102023000157240ustar 00000000000000//! Compute k-shortest paths using [Yen's search //! algorithm](https://en.wikipedia.org/wiki/Yen%27s_algorithm). use num_traits::Zero; use std::cmp::Ordering; use std::cmp::Reverse; use std::collections::BinaryHeap; use std::collections::HashSet; use std::hash::Hash; use super::dijkstra::dijkstra_internal; /// A representation of a path. #[derive(Eq, PartialEq, Debug)] struct Path { /// The nodes along the path nodes: Vec, /// The total cost of the path cost: C, } impl PartialOrd for Path where N: Eq + Hash + Clone, C: Zero + Ord + Copy, { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for Path where N: Eq + Hash + Clone, C: Zero + Ord + Copy, { fn cmp(&self, other: &Self) -> Ordering { // Compare costs first, then amount of nodes let cmp = self.cost.cmp(&other.cost); match cmp { Ordering::Equal => self.nodes.len().cmp(&other.nodes.len()), _ => cmp, } } } /// Compute the k-shortest paths using the [Yen's search /// algorithm](https://en.wikipedia.org/wiki/Yen%27s_algorithm). /// /// The `k`-shortest paths starting from `start` up to a node for which `success` returns `true` /// are computed along with their total cost. The result is return as a vector of (path, cost). /// /// - `start` is the starting node. /// - `successors` returns a list of successors for a given node, along with the cost of moving from /// the node to the successor. Costs MUST be positive. /// - `success` checks weather the goal has been reached. /// - `k` is the amount of paths requests, including the shortest one. /// /// The returned paths include both the start and the end node and are ordered by their costs /// starting with the lowest cost. If there exist less paths than requested, only the existing /// ones (if any) are returned. /// /// # Example /// We will search the 3 shortest paths from node C to node H. See /// for a visualization. /// /// ``` /// use pathfinding::prelude::yen; /// // Find 3 shortest paths from 'c' to 'h' /// let paths = yen( /// &'c', /// |c| match c { /// 'c' => vec![('d', 3), ('e', 2)], /// 'd' => vec![('f', 4)], /// 'e' => vec![('d', 1), ('f', 2), ('g', 3)], /// 'f' => vec![('g', 2), ('h', 1)], /// 'g' => vec![('h', 2)], /// 'h' => vec![], /// _ => panic!(""), /// }, /// |c| *c == 'h', /// 3); /// assert_eq!(paths.len(), 3); /// assert_eq!(paths[0], (vec!['c', 'e', 'f', 'h'], 5)); /// assert_eq!(paths[1], (vec!['c', 'e', 'g', 'h'], 7)); /// assert_eq!(paths[2], (vec!['c', 'd', 'f', 'h'], 8)); /// /// // An example of a graph that has no path from 'c' to 'h'. /// let empty = yen( /// &'c', /// |c| match c { /// 'c' => vec![('d', 3)], /// 'd' => vec![], /// _ => panic!(""), /// }, /// |c| *c == 'h', /// 2); /// assert!(empty.is_empty()); /// ``` pub fn yen( start: &N, mut successors: FN, mut success: FS, k: usize, ) -> Vec<(Vec, C)> where N: Eq + Hash + Clone, C: Zero + Ord + Copy, FN: FnMut(&N) -> IN, IN: IntoIterator, FS: FnMut(&N) -> bool, { let Some((n, c)) = dijkstra_internal(start, &mut successors, &mut success) else { return vec![]; }; let mut visited = HashSet::new(); // A vector containing our paths. let mut routes = vec![Path { nodes: n, cost: c }]; // A min-heap to store our lowest-cost route candidate let mut k_routes = BinaryHeap::new(); for ki in 0..(k - 1) { if routes.len() <= ki || routes.len() == k { // We have no more routes to explore, or we have found enough. break; } // Take the most recent route to explore new spurs. let previous = &routes[ki].nodes; // Iterate over every node except the sink node. for i in 0..(previous.len() - 1) { let spur_node = &previous[i]; let root_path = &previous[0..i]; let mut filtered_edges = HashSet::new(); for path in &routes { if path.nodes.len() > i + 1 && &path.nodes[0..i] == root_path && &path.nodes[i] == spur_node { filtered_edges.insert((&path.nodes[i], &path.nodes[i + 1])); } } let filtered_nodes: HashSet<&N> = HashSet::from_iter(root_path); // We are creating a new successor function that will not return the // filtered edges and nodes that routes already used. let mut filtered_successor = |n: &N| { successors(n) .into_iter() .filter(|(n2, _)| { !filtered_nodes.contains(&n2) && !filtered_edges.contains(&(n, n2)) }) .collect::>() }; // Let us find the spur path from the spur node to the sink using. if let Some((spur_path, _)) = dijkstra_internal(spur_node, &mut filtered_successor, &mut success) { let nodes: Vec = root_path.iter().cloned().chain(spur_path).collect(); // If we have found the same path before, we will not add it. if !visited.contains(&nodes) { // Since we don't know the root_path cost, we need to recalculate. let cost = make_cost(&nodes, &mut successors); let path = Path { nodes, cost }; // Mark as visited visited.insert(path.nodes.clone()); // Build a min-heap k_routes.push(Reverse(path)); } } } if let Some(k_route) = k_routes.pop() { let route = k_route.0; let cost = route.cost; routes.push(route); // If we have other potential best routes with the same cost, we can insert // them in the found routes since we will not find a better alternative. while routes.len() < k { let Some(k_route) = k_routes.peek() else { break; }; if k_route.0.cost == cost { let Some(k_route) = k_routes.pop() else { break; // Cannot break }; routes.push(k_route.0); } else { break; // Other routes have higher cost } } } } routes.sort_unstable(); routes .into_iter() .map(|Path { nodes, cost }| (nodes, cost)) .collect() } fn make_cost(nodes: &[N], successors: &mut FN) -> C where N: Eq, C: Zero, FN: FnMut(&N) -> IN, IN: IntoIterator, { let mut cost = C::zero(); for edge in nodes.windows(2) { for (n, c) in successors(&edge[0]) { if n == edge[1] { cost = cost + c; } } } cost } pathfinding-4.14.0/src/grid.rs000064400000000000000000000532431046102023000142760ustar 00000000000000//! Rectangular grid in which vertices can be added or removed, with or //! without diagonal links. use super::matrix::Matrix; use crate::directed::bfs::bfs_reach; use crate::directed::dfs::dfs_reach; use crate::utils::constrain; use crate::FxIndexSet; use num_traits::ToPrimitive; use std::collections::BTreeSet; use std::fmt; use std::iter::FusedIterator; use std::ops::Sub; #[derive(Clone)] /// A rectangular grid. /// /// Representation of a rectangular grid in which vertices can be added /// or removed. Edges are automatically created between adjacent vertices. /// By default, only vertical and horizontal edges are created, unless /// diagonal mode is enabled. /// /// The coordinate system is of the form `(x, y)`, where `x` is the column /// and `y` is the row. `(0, 0)` corresponds to the top-left corner. /// /// Internally, a Grid is represented either as a collection of vertices /// or as a collection of absent vertices, depending on the density of /// the grid. The switch between both representations is done automatically /// when vertices are added or removed, or when the grid is resized. /// /// `Grid` implements `Debug` and represents the content using `#` and `.` /// characters. Alternate block characters `â–“` and `â–‘` can be selected by /// using the alternate debug format (`{:#?}`): /// /// ``` /// use pathfinding::prelude::Grid; /// /// let mut g = Grid::new(3, 4); /// g.add_borders(); /// /// assert_eq!(&format!("{g:?}"), "\ /// #### /// #.# /// #.# /// ####"); /// /// assert_eq!(&format!("{g:#?}"), "\ /// â–“â–“â–“ /// â–“â–‘â–“ /// â–“â–‘â–“ /// â–“â–“â–“"); /// ``` /// /// One of the ways to build a `Grid` is to start from an iterator of /// `(usize, usize)` representing the `(x, y)` coordinates: /// /// ``` /// use pathfinding::prelude::Grid; /// /// let g = vec![(0, 0), (2, 2), (3, 2)].into_iter().collect::(); /// assert_eq!(format!("{g:?}"), "\ /// #... /// .... /// ..##"); /// ``` /// /// To be able to easily use the grid as a visualization tool for /// arbitrary types of coordinates, a [`from_coordinates`](Grid::from_coordinates) /// method will build a grid and remap the top-left most coordinate as `(0, 0)`: /// /// ``` /// use pathfinding::prelude::Grid; /// /// let g = Grid::from_coordinates(&[(-16, -15), (-16, -16), (-15, -16)]).unwrap(); /// assert_eq!(format!("{g:#?}"), "\ /// â–“â–“ /// â–“â–‘"); /// ``` /// Also, the order of lines can be inverted by using the `-` sign modifier while /// displaying: /// /// ``` /// # use pathfinding::prelude::Grid; /// # /// # let g = Grid::from_coordinates(&[(-16, -15), (-16, -16), (-15, -16)]).unwrap(); /// assert_eq!(format!("{g:-#?}"), "\ /// â–“â–‘ /// â–“â–“"); /// ``` pub struct Grid { /// The grid width. pub width: usize, /// The grid height. pub height: usize, diagonal_mode: bool, // `dense` is true if the grid is full by default and `exclusions` // contains absent vertices. It is false if the grid is empty by default // and `exclusions` contains the vertices. dense: bool, exclusions: FxIndexSet<(usize, usize)>, } impl Grid { /// Create a new empty grid object of the given dimensions, with /// diagonal mode disabled. #[must_use] pub fn new(width: usize, height: usize) -> Self { Self { width, height, diagonal_mode: false, dense: false, exclusions: FxIndexSet::default(), } } /// Check if a (possibly removed) vertex belongs to the grid or if it /// is located outside the grid. #[inline] #[must_use] pub const fn is_inside(&self, vertex: (usize, usize)) -> bool { vertex.0 < self.width && vertex.1 < self.height } /// Enable diagonal mode. Diagonal edges will be created between /// adjacent vertices. pub fn enable_diagonal_mode(&mut self) { self.diagonal_mode = true; } /// Disable diagonal mode. Only horizontal and vertical edges will /// be created between adjacent vertices. pub fn disable_diagonal_mode(&mut self) { self.diagonal_mode = false; } /// Resize the grid to the given dimensions. Return `true` if this /// caused any existing vertex to be discarded. pub fn resize(&mut self, width: usize, height: usize) -> bool { let mut truncated = false; if width < self.width { truncated |= (width..self.width).any(|c| (0..self.height).any(|r| self.has_vertex((c, r)))); } if height < self.height { truncated |= (0..self.width).any(|c| (height..self.height).any(|r| self.has_vertex((c, r)))); } self.exclusions.retain(|&(x, y)| x < width && y < height); if self.dense { for c in self.width..width { for r in 0..height { self.exclusions.insert((c, r)); } } for c in 0..self.width.min(width) { for r in self.height..height { self.exclusions.insert((c, r)); } } } self.width = width; self.height = height; self.rebalance(); truncated } /// Return the number of positions in this grid. #[must_use] pub const fn size(&self) -> usize { self.width * self.height } /// Return the number of vertices. #[must_use] pub fn vertices_len(&self) -> usize { if self.dense { self.size() - self.exclusions.len() } else { self.exclusions.len() } } /// Add a new vertex. Return `true` if the vertex did not previously /// exist and has been added. Return `false` if the vertex exists /// already or would be outside the grid. pub fn add_vertex(&mut self, vertex: (usize, usize)) -> bool { if !self.is_inside(vertex) { return false; } let r = if self.dense { self.exclusions.swap_remove(&vertex) } else { self.exclusions.insert(vertex) }; self.rebalance(); r } /// Remove a vertex. Return `true` if the vertex did previously exist /// and has been removed. pub fn remove_vertex(&mut self, vertex: (usize, usize)) -> bool { if !self.is_inside(vertex) { return false; } let r = if self.dense { self.exclusions.insert(vertex) } else { self.exclusions.swap_remove(&vertex) }; self.rebalance(); r } /// Return an iterator over the border vertices. The grid must not have /// a zero width or height. fn borders(&self) -> impl Iterator { let width = self.width; let height = self.height; (0..width) .flat_map(move |x| vec![(x, 0), (x, height - 1)].into_iter()) .chain((1..height - 1).flat_map(move |y| vec![(0, y), (width - 1, y)].into_iter())) } /// Add the borders of the grid. Return the number of added vertices. pub fn add_borders(&mut self) -> usize { if self.width == 0 || self.height == 0 { return 0; } let count = if self.dense { self.borders() .filter(|v| self.exclusions.swap_remove(v)) .count() } else { self.borders() .filter(|v| self.exclusions.insert(*v)) .count() }; self.rebalance(); count } /// Remove the borders of the grid. Return the number of removed vertices. pub fn remove_borders(&mut self) -> usize { if self.width == 0 || self.height == 0 { return 0; } let count = if self.dense { self.borders() .filter(|v| self.exclusions.insert(*v)) .count() } else { self.borders() .filter(|v| self.exclusions.swap_remove(v)) .count() }; self.rebalance(); count } fn rebalance(&mut self) { if self.exclusions.len() > self.width * self.height / 2 { self.exclusions = (0..self.width) .flat_map(|c| (0..self.height).map(move |r| (c, r))) .filter(|v| !self.exclusions.contains(v)) .collect(); self.dense = !self.dense; } } /// Remove all vertices from the grid. Return `true` if the grid /// previously contained at least one vertex. pub fn clear(&mut self) -> bool { let r = !self.is_empty(); self.dense = false; self.exclusions.clear(); r } /// Fill the grid with all possible vertices. Return `true` if /// this caused the addition of at least one vertex. pub fn fill(&mut self) -> bool { let r = !self.is_full(); self.clear(); self.invert(); r } /// Return `true` if the grid contains no vertices. #[must_use] pub fn is_empty(&self) -> bool { if self.dense { self.exclusions.len() == self.size() } else { self.exclusions.is_empty() } } /// Return `true` if no additional vertices can be set /// (because they are all already set). #[must_use] pub fn is_full(&self) -> bool { if self.dense { self.exclusions.is_empty() } else { self.exclusions.len() == self.size() } } /// Remove every existing vertex, and add all absent vertices. /// If you see the grid as a black and white array, imagine that /// the color are exchanged. pub fn invert(&mut self) { self.dense = !self.dense; } /// Check if a vertex is present. #[must_use] pub fn has_vertex(&self, vertex: (usize, usize)) -> bool { self.is_inside(vertex) && (self.exclusions.contains(&vertex) ^ self.dense) } /// Check if an edge is present. #[must_use] pub fn has_edge(&self, v1: (usize, usize), v2: (usize, usize)) -> bool { if !self.has_vertex(v1) || !self.has_vertex(v2) { return false; } let x = v1.0.abs_diff(v2.0); let y = v1.1.abs_diff(v2.1); x + y == 1 || (x == 1 && y == 1 && self.diagonal_mode) } /// Iterate over edges. #[must_use] pub const fn edges(&self) -> EdgesIterator { EdgesIterator { grid: self, x: 0, y: 0, i: 0, } } /// Return the list of neighbours of a given vertex. If `vertex` is absent /// from the grid, an empty list is returned. Only existing vertices will /// be returned. #[must_use] pub fn neighbours(&self, vertex: (usize, usize)) -> Vec<(usize, usize)> { if !self.has_vertex(vertex) { return vec![]; } let (x, y) = vertex; let mut candidates = Vec::with_capacity(8); if x > 0 { candidates.push((x - 1, y)); if self.diagonal_mode { if y > 0 { candidates.push((x - 1, y - 1)); } if y + 1 < self.height { candidates.push((x - 1, y + 1)); } } } if x + 1 < self.width { candidates.push((x + 1, y)); if self.diagonal_mode { if y > 0 { candidates.push((x + 1, y - 1)); } if y + 1 < self.height { candidates.push((x + 1, y + 1)); } } } if y > 0 { candidates.push((x, y - 1)); } if y + 1 < self.height { candidates.push((x, y + 1)); } candidates.retain(|&v| self.has_vertex(v)); candidates } /// Return a set of the indices reachable from a candidate starting point /// and for which the given predicate is valid using BFS. This can be used for example /// to implement a flood-filling algorithm. Since the indices are collected /// into a collection, they can later be used without keeping a reference on the /// matrix itself, e.g., to modify the grid. /// /// The search is done using a breadth first search (BFS) algorithm. /// /// # See also /// /// The [`dfs_reachable()`](`Self::dfs_reachable`) method performs a DFS search instead. pub fn bfs_reachable

( &self, start: (usize, usize), mut predicate: P, ) -> BTreeSet<(usize, usize)> where P: FnMut((usize, usize)) -> bool, { bfs_reach(start, |&n| { self.neighbours(n) .into_iter() .filter(|&n| predicate(n)) .collect::>() }) .collect() } /// Return a set of the indices reachable from a candidate starting point /// and for which the given predicate is valid using BFS. This can be used for example /// to implement a flood-filling algorithm. Since the indices are collected /// into a collection, they can later be used without keeping a reference on the /// matrix itself, e.g., to modify the grid. /// /// The search is done using a depth first search (DFS) algorithm. /// /// # See also /// /// The [`bfs_reachable()`](`Self::bfs_reachable`) method performs a BFS search instead. pub fn dfs_reachable

( &self, start: (usize, usize), mut predicate: P, ) -> BTreeSet<(usize, usize)> where P: FnMut((usize, usize)) -> bool, { dfs_reach(start, |&n| { self.neighbours(n) .into_iter() .filter(|&n| predicate(n)) .collect::>() }) .collect() } /// Iterate over vertices. #[must_use] pub fn iter(&self) -> GridIterator { self.into_iter() } /// Distance between two potential vertices. If diagonal mode is /// enabled, this is the maximum of both coordinates difference. /// If diagonal mode is disabled, this is the Manhattan distance. #[must_use] pub fn distance(&self, a: (usize, usize), b: (usize, usize)) -> usize { let (dx, dy) = (a.0.abs_diff(b.0), a.1.abs_diff(b.1)); if self.diagonal_mode { dx.max(dy) } else { dx + dy } } /// Build a grid from an arbitrary set of `(x, y)` coordinates. Coordinates will /// be adjusted so that the returned grid is the smallest one containing /// all the points while conserving horizontal and vertical distances /// between them. /// /// This can be used for example to visualize data whose coordinates are /// expressed using a non-usize integer type, such as `(isize, isize)`. /// /// This method returns `None` if any axis of any coordinate cannot be /// represented as an `usize` once the minimum for this axis has been /// subtracted. /// /// # Example /// /// ``` /// use pathfinding::prelude::Grid; /// /// let grid = Grid::from_coordinates(&[(2, 2), (3, 4)]).unwrap(); /// assert_eq!(vec![(0, 0), (1, 2)], grid.iter().collect::>()); /// ``` pub fn from_coordinates(points: &[(T, T)]) -> Option where T: Ord + Sub + Copy + Default + ToPrimitive, { let (min_x, min_y) = ( points .iter() .map(|(x, _)| x) .min() .copied() .unwrap_or_default(), points .iter() .map(|(_, y)| y) .min() .copied() .unwrap_or_default(), ); points .iter() .map(|(x, y)| Some(((*x - min_x).to_usize()?, (*y - min_y).to_usize()?))) .collect() } /// Constrain a wrapped-around index so that it falls inside the /// grid. /// /// # Examples /// /// ```rust /// use pathfinding::grid::Grid; /// /// let grid = Grid::new(3, 5); /// assert_eq!(grid.constrain((1, 2)), (1, 2)); /// assert_eq!(grid.constrain((10, -53)), (1, 2)); /// ``` #[must_use] pub const fn constrain(&self, vertex: (isize, isize)) -> (usize, usize) { ( constrain(vertex.0, self.width), constrain(vertex.1, self.height), ) } } impl FromIterator<(usize, usize)> for Grid { fn from_iter(iter: T) -> Self where T: IntoIterator, { let vertices = iter.into_iter().collect(); let mut width = 0; let mut height = 0; for &(x, y) in &vertices { if x + 1 > width { width = x + 1; } if y + 1 > height { height = y + 1; } } let mut grid = Self { width, height, diagonal_mode: false, dense: false, exclusions: vertices, }; grid.rebalance(); grid } } /// Iterator returned by calling `.into_iter()` on a grid. pub struct GridIntoIterator { grid: Grid, x: usize, y: usize, } impl Iterator for GridIntoIterator { type Item = (usize, usize); fn next(&mut self) -> Option { if self.grid.dense { loop { if self.y == self.grid.height { return None; } let r = (self.grid.has_vertex((self.x, self.y))).then_some((self.x, self.y)); self.x += 1; if self.x == self.grid.width { self.x = 0; self.y += 1; } if r.is_some() { return r; } } } else { self.grid.exclusions.pop() } } } impl FusedIterator for GridIntoIterator {} impl IntoIterator for Grid { type Item = (usize, usize); type IntoIter = GridIntoIterator; #[must_use] fn into_iter(self) -> Self::IntoIter { GridIntoIterator { grid: self, x: 0, y: 0, } } } /// Iterator returned by calling `.iter()` on a grid. pub struct GridIterator<'a> { grid: &'a Grid, x: usize, y: usize, } impl Iterator for GridIterator<'_> { type Item = (usize, usize); fn next(&mut self) -> Option { if self.grid.dense { loop { if self.y == self.grid.height { return None; } let r = (self.grid.has_vertex((self.x, self.y))).then_some((self.x, self.y)); self.x += 1; if self.x == self.grid.width { self.x = 0; self.y += 1; } if r.is_some() { return r; } } } else { self.grid .exclusions .get_index(self.x) .inspect(|_| { self.x += 1; }) .copied() } } } impl FusedIterator for GridIterator<'_> {} impl<'a> IntoIterator for &'a Grid { type Item = (usize, usize); type IntoIter = GridIterator<'a>; #[must_use] fn into_iter(self) -> Self::IntoIter { GridIterator { grid: self, x: 0, y: 0, } } } /// Iterator returned by calling `.edges()` on a grid. pub struct EdgesIterator<'a> { grid: &'a Grid, x: usize, y: usize, i: usize, } impl Iterator for EdgesIterator<'_> { type Item = ((usize, usize), (usize, usize)); fn next(&mut self) -> Option { loop { if self.y == self.grid.height { return None; } let x = self.x; let y = self.y; let other = match self.i { 0 => (x + 1, y), 1 => (x, y + 1), 2 => (x + 1, y + 1), _ => (x - 1, y + 1), }; self.i += 1; if (x == 0 && self.i == 3) || self.i == 4 { self.i = 0; self.x += 1; if self.x == self.grid.width { self.x = 0; self.y += 1; } } if self.grid.has_edge((x, y), other) { return Some(((x, y), other)); } } } } impl FusedIterator for EdgesIterator<'_> {} impl fmt::Debug for Grid { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let (present, absent) = if f.alternate() { ('▓', '░') } else { ('#', '.') }; let lines: Vec<_> = if f.sign_minus() { (0..self.height).rev().collect() } else { (0..self.height).collect() }; let last = *lines.last().unwrap(); for y in lines { for x in 0..self.width { write!( f, "{}", if self.has_vertex((x, y)) { present } else { absent } )?; } if y != last { writeln!(f)?; } } Ok(()) } } impl From<&Matrix> for Grid { fn from(matrix: &Matrix) -> Self { let mut grid = Self::new(matrix.columns, matrix.rows); for ((r, c), &v) in matrix.items() { if v { grid.add_vertex((c, r)); } } grid } } impl From> for Grid { fn from(matrix: Matrix) -> Self { Self::from(&matrix) } } impl PartialEq for Grid { fn eq(&self, other: &Self) -> bool { self.vertices_len() == other.vertices_len() && self.iter().zip(other.iter()).all(|(a, b)| a == b) } } impl Eq for Grid {} pathfinding-4.14.0/src/kuhn_munkres.rs000064400000000000000000000231531046102023000160570ustar 00000000000000//! Compute a maximum weight maximum matching between two disjoints sets of //! vertices using the //! [Kuhn-Munkres algorithm](https://en.wikipedia.org/wiki/Hungarian_algorithm) //! (also known as Hungarian algorithm). use crate::{matrix::Matrix, FxIndexSet}; use num_traits::{Bounded, Signed, Zero}; use std::iter::Sum; /// Adjacency matrix for weights. pub trait Weights { /// Return the number of rows. #[must_use] fn rows(&self) -> usize; /// Return the number of columns. #[must_use] fn columns(&self) -> usize; /// Return the element at position. #[must_use] fn at(&self, row: usize, col: usize) -> C; /// Return the negated weights. #[must_use] fn neg(&self) -> Self where Self: Sized, C: Signed; } impl Weights for Matrix { fn rows(&self) -> usize { self.rows } fn columns(&self) -> usize { self.columns } fn at(&self, row: usize, col: usize) -> C { self[(row, col)] } fn neg(&self) -> Self where C: Signed, { -self.clone() } } /// Compute a maximum weight maximum matching between two disjoints sets of /// vertices using the /// [Kuhn-Munkres algorithm](https://en.wikipedia.org/wiki/Hungarian_algorithm) /// (also known as Hungarian algorithm). /// /// The weights between the first and second sets are given into the /// `weights` adjacency matrix. The return value is a pair with /// the total assignments weight, and a vector containing the column /// corresponding the every row. /// /// For this reason, the number of rows must not be larger than the number of /// columns as no row will be left unassigned. /// /// This algorithm executes in O(n³) where n is the cardinality of the sets. /// /// # Example /// /// Three people in an art gallery are interested by the same three pieces. /// Each of them has a budget of $300, and as if the world was perfect they /// each determine that this corresponds to what they are ready to pay for /// every piece: /// /// - Ann estimates the Cloth to $100, the Statue to $110, and the Painting to $90 /// - Bernard estimates the Cloth to $95, the Statue to $130, and the Painting to $75 /// - Claude estimates the Cloth to $95, the Statue to $140 and the Painting to $65 /// /// The gallery owner doesn't want to totally frustrate any customer and decides to /// sell one piece of art to each one of them. What would be the best way to maximize /// the cash flow? /// /// ``` /// use pathfinding::prelude::{kuhn_munkres, Matrix, Weights}; /// /// // Assign weights to everybody choices /// let weights = Matrix::from_rows(vec![ /// // Cloth, Statue, Painting /// vec![100, 110, 90], // Ann /// vec![95, 130, 75], // Bernard /// vec![95, 140, 65], // Claude /// ]).unwrap(); /// /// // Find the maximum bipartite matching /// let (cash_flow, assignments) = kuhn_munkres(&weights); /// /// // Gallery owner receives $325, this is the maximum they can get /// assert_eq!(cash_flow, 325); /// /// // Ann gets the Painting for $90, Bernard gets the Cloth for $95, /// // Claude gets the Statue for $140, which makes a total of $325 /// assert_eq!(assignments, vec![2, 0, 1]); /// ``` /// /// # See also /// /// To minimize the sum of weights instead of maximizing it, use the /// [`kuhn_munkres_min()`] function. /// /// # Panics /// /// This function panics if the number of rows is larger than the number of /// columns, or if the total assignments weight overflows or underflows. /// /// Also, using indefinite values such as positive or negative infinity or /// NaN can cause this function to loop endlessly. pub fn kuhn_munkres(weights: &W) -> (C, Vec) where C: Bounded + Sum + Signed + Zero + Ord + Copy, W: Weights, { // We call x the rows and y the columns. (nx, ny) is the size of the matrix. let nx = weights.rows(); let ny = weights.columns(); assert!( nx <= ny, "number of rows must not be larger than number of columns" ); // xy represents matching for x, yz matching for y let mut xy: Vec> = vec![None; nx]; let mut yx: Vec> = vec![None; ny]; // lx is the labelling for x nodes, ly the labelling for y nodes. We start // with an acceptable labelling with the maximum possible values for lx // and 0 for ly. let mut lx: Vec = (0..nx) .map(|row| (0..ny).map(|col| weights.at(row, col)).max().unwrap()) .collect::>(); let mut ly: Vec = vec![Zero::zero(); ny]; // s, augmenting, and slack will be reset every time they are reused. augmenting // contains Some(prev) when the corresponding node belongs to the augmenting path. let mut s = FxIndexSet::::default(); let mut alternating = Vec::with_capacity(ny); let mut slack = vec![Zero::zero(); ny]; let mut slackx = Vec::with_capacity(ny); for root in 0..nx { alternating.clear(); alternating.resize(ny, None); // Find y such that the path is augmented. This will be set when breaking for the // loop below. Above the loop is some code to initialize the search. let mut y = { s.clear(); s.insert(root); // Slack for a vertex y is, initially, the margin between the // sum of the labels of root and y, and the weight between root and y. // As we add x nodes to the alternating path, we update the slack to // represent the smallest margin between one of the x nodes and y. for y in 0..ny { slack[y] = lx[root] + ly[y] - weights.at(root, y); } slackx.clear(); slackx.resize(ny, root); Some(loop { let mut delta = Bounded::max_value(); let mut x = 0; let mut y = 0; // Select one of the smallest slack delta and its edge (x, y) // for y not in the alternating path already. for yy in 0..ny { if alternating[yy].is_none() && slack[yy] < delta { delta = slack[yy]; x = slackx[yy]; y = yy; } } // If some slack has been found, remove it from x nodes in the // alternating path, and add it to y nodes in the alternating path. // The slack of y nodes outside the alternating path will be reduced // by this minimal slack as well. if delta > Zero::zero() { for &x in &s { lx[x] = lx[x] - delta; } for y in 0..ny { if alternating[y].is_some() { ly[y] = ly[y] + delta; } else { slack[y] = slack[y] - delta; } } } // Add (x, y) to the alternating path. alternating[y] = Some(x); if yx[y].is_none() { // We have found an augmenting path. break y; } // This y node had a predecessor, add it to the set of x nodes // in the augmenting path. let x = yx[y].unwrap(); s.insert(x); // Update slack because of the added vertex in s might contain a // greater slack than with previously inserted x nodes in the augmenting // path. for y in 0..ny { if alternating[y].is_none() { let alternate_slack = lx[x] + ly[y] - weights.at(x, y); if slack[y] > alternate_slack { slack[y] = alternate_slack; slackx[y] = x; } } } }) }; // Inverse edges along the augmenting path. while y.is_some() { let x = alternating[y.unwrap()].unwrap(); let prec = xy[x]; yx[y.unwrap()] = Some(x); xy[x] = y; y = prec; } } ( lx.into_iter().sum::() + ly.into_iter().sum(), xy.into_iter().map(Option::unwrap).collect::>(), ) } /// Compute a minimum weight maximum matching between two disjoints sets of /// vertices using the /// [Kuhn-Munkres algorithm](https://en.wikipedia.org/wiki/Hungarian_algorithm) /// (also known as Hungarian algorithm). /// /// The weights between the first and second sets are given into the /// `weights` adjacency matrix. The return value is a pair with /// the total assignments weight, and a vector containing the column /// corresponding the every row. /// /// For this reason, the number of rows must not be larger than the number of /// columns as no row will be left unassigned. /// /// This algorithm executes in O(n³) where n is the cardinality of the sets. /// /// # See also /// /// To maximize the sum of weights instead of minimizing it, use the /// [`kuhn_munkres()`] function. /// /// # Panics /// /// This function panics if the number of rows is larger than the number of /// columns, or if the total assignments weight overflows or underflows. /// /// Also, using indefinite values such as positive or negative infinity or /// NaN can cause this function to loop endlessly. pub fn kuhn_munkres_min(weights: &W) -> (C, Vec) where C: Bounded + Sum + Zero + Signed + Ord + Copy, W: Weights, { let (total, assignments) = kuhn_munkres(&weights.neg()); (-total, assignments) } pathfinding-4.14.0/src/lib.rs000064400000000000000000000171311046102023000141130ustar 00000000000000#![forbid(missing_docs)] //! # pathfinding //! //! [![Current Version](https://img.shields.io/crates/v/pathfinding.svg)](https://crates.io/crates/pathfinding) //! [![Documentation](https://docs.rs/pathfinding/badge.svg)](https://docs.rs/pathfinding) //! [![License: Apache-2.0/MIT](https://img.shields.io/crates/l/pathfinding.svg)](#license) //! //! This crate implements several pathfinding, flow, and graph algorithms in [Rust][Rust]. //! //! ## Algorithms //! //! The algorithms are generic over their arguments. //! //! ### Directed graphs //! //! - [A*](directed/astar/index.html): find the shortest path in a weighted graph using an heuristic to guide the process ([⇒ Wikipedia][A*]) //! - [BFS](directed/bfs/index.html): explore nearest successors first, then widen the search ([⇒ Wikipedia][BFS]) //! - [Bidirectional search](directed/bfs/fn.bfs_bidirectional.html): simultaneously explore paths forwards from the start and backwards from the goal ([=> Wikipedia][Bidirectional search]) //! - [Brent](directed/cycle_detection/index.html): find a cycle in an infinite sequence ([⇒ Wikipedia][Brent]) //! - [DFS](directed/dfs/index.html): explore a graph by going as far as possible, then backtrack ([⇒ Wikipedia][DFS]) //! - [Dijkstra](directed/dijkstra/index.html): find the shortest path in a weighted graph ([⇒ Wikipedia][Dijkstra]) //! - [Edmonds Karp](directed/edmonds_karp/index.html): find the maximum flow in a weighted graph ([⇒ Wikipedia][Edmonds Karp]) //! - [Floyd](directed/cycle_detection/index.html): find a cycle in an infinite sequence ([⇒ Wikipedia][Floyd]) //! - [Fringe](directed/fringe/index.html): find the shortest path in a weighted graph using an heuristic to guide the process ([⇒ Wikipedia][Fringe]) //! - [IDA*](directed/idastar/index.html): explore longer and longer paths in a weighted graph at the cost of multiple similar examinations ([⇒ Wikipedia][IDA*]) //! - [IDDFS](directed/iddfs/index.html): explore longer and longer paths in an unweighted graph at the cost of multiple similar examinations ([⇒ Wikipedia][IDDFS]) //! - [paths counting](directed/count_paths/index.html): count the paths to the destination in an acyclic graph //! - [strongly connected components](directed/strongly_connected_components/index.html): find strongly connected components in a directed graph ([⇒ Wikipedia][Strongly connected components]) //! - [topological sorting](directed/topological_sort/index.html): find an acceptable topological order in a directed graph ([⇒ Wikipedia][Topological sorting]) //! - [Yen](directed/yen/index.html): find k-shortest paths using Dijkstra ([⇒ Wikipedia][Yen]) //! //! ### Undirected graphs //! //! - [connected components](undirected/connected_components/index.html): find disjoint connected sets of vertices ([⇒ Wikipedia][Connected components]) //! - [Kruskal](undirected/kruskal/index.html): find a minimum-spanning-tree ([⇒ Wikipedia][Kruskal]) //! - [Prim](undirected/prim/index.html): find a minimum-spanning-tree ([⇒ Wikipedia][Prim]) //! - [cliques]: find maximum cliques in a graph ([= Wikipedia][BronKerbosch]) //! //! ### Matching //! //! - [Kuhn-Munkres](kuhn_munkres/index.html) (Hungarian algorithm): find the maximum (or minimum) matching in a weighted bipartite graph ([⇒ Wikipedia][Kuhn-Munkres]) //! //! ### Miscellaneous structures //! //! - A [`Grid`](grid/index.html) type representing a rectangular grid in which vertices can be added or removed, with automatic creation of edges between adjacent vertices. //! - A [`Matrix`](matrix/index.html) type to store data of arbitrary types, with neighbour-aware methods. //! //! ## Example //! //! We will search the shortest path on a chess board to go from (1, 1) to (4, 6) doing only knight //! moves. //! //! ``` rust //! use pathfinding::prelude::bfs; //! //! #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] //! struct Pos(i32, i32); //! //! impl Pos { //! fn successors(&self) -> Vec { //! let &Pos(x, y) = self; //! vec![Pos(x+1,y+2), Pos(x+1,y-2), Pos(x-1,y+2), Pos(x-1,y-2), //! Pos(x+2,y+1), Pos(x+2,y-1), Pos(x-2,y+1), Pos(x-2,y-1)] //! } //! } //! //! static GOAL: Pos = Pos(4, 6); //! let result = bfs(&Pos(1, 1), |p| p.successors(), |p| *p == GOAL); //! assert_eq!(result.expect("no path found").len(), 5); //! ``` //! //! ## Note on floating-point types //! //! Several algorithms require that the numerical types used to describe //! edge weights implement `Ord`. If you wish to use Rust built-in //! floating-point types (such as `f32`) that implement `PartialOrd` //! in this context, you can wrap them into compliant types using the //! [ordered-float](https://crates.io/crates/ordered-float) crate. //! //! The minimum supported Rust version (MSRV) is Rust 1.77.2. //! //! [A*]: https://en.wikipedia.org/wiki/A*_search_algorithm //! [BFS]: https://en.wikipedia.org/wiki/Breadth-first_search //! [Bidirectional search]: https://en.wikipedia.org/wiki/Bidirectional_search //! [Brent]: https://en.wikipedia.org/wiki/Cycle_detection#Brent's_algorithm //! [BronKerbosch]: https://en.wikipedia.org/wiki/Bron%E2%80%93Kerbosch_algorithm //! [Connected components]: https://en.wikipedia.org/wiki/Connected_component_(graph_theory) //! [DFS]: https://en.wikipedia.org/wiki/Depth-first_search //! [Dijkstra]: https://en.wikipedia.org/wiki/Dijkstra's_algorithm //! [Edmonds Karp]: https://en.wikipedia.org/wiki/Edmonds–Karp_algorithm //! [Floyd]: https://en.wikipedia.org/wiki/Cycle_detection#Floyd's_tortoise_and_hare //! [Fringe]: https://en.wikipedia.org/wiki/Fringe_search //! [IDA*]: https://en.wikipedia.org/wiki/Iterative_deepening_A* //! [IDDFS]: https://en.wikipedia.org/wiki/Iterative_deepening_depth-first_search //! [Kruskal]: https://en.wikipedia.org/wiki/Kruskal's_algorithm //! [Kuhn-Munkres]: https://en.wikipedia.org/wiki/Hungarian_algorithm //! [Prim]: https://en.wikipedia.org/wiki/Prim's_algorithm //! [Rust]: https://rust-lang.org/ //! [Strongly connected components]: https://en.wikipedia.org/wiki/Strongly_connected_component //! [Topological sorting]: https://en.wikipedia.org/wiki/Topological_sorting //! [Yen]: https://en.wikipedia.org/wiki/Yen's_algorithm use deprecate_until::deprecate_until; pub use num_traits; pub mod directed; pub mod grid; pub mod kuhn_munkres; pub mod matrix; pub mod undirected; pub mod utils; use indexmap::{IndexMap, IndexSet}; use rustc_hash::FxHasher; use std::hash::BuildHasherDefault; type FxIndexMap = IndexMap>; type FxIndexSet = IndexSet>; /// Export all public functions and structures for an easy access. pub mod prelude { pub use crate::directed::astar::*; pub use crate::directed::bfs::*; pub use crate::directed::count_paths::*; pub use crate::directed::cycle_detection::*; pub use crate::directed::dfs::*; pub use crate::directed::dijkstra::*; pub use crate::directed::edmonds_karp::*; pub use crate::directed::fringe::*; pub use crate::directed::idastar::*; pub use crate::directed::iddfs::*; pub use crate::directed::strongly_connected_components::*; pub use crate::directed::topological_sort::*; pub use crate::directed::yen::*; pub use crate::grid::*; pub use crate::kuhn_munkres::*; pub use crate::matrix::*; pub use crate::undirected::cliques::*; pub use crate::undirected::connected_components::*; pub use crate::undirected::kruskal::*; pub use crate::utils::*; } /// Deprecated: moved into the `directed` module. #[deprecate_until( note = "use directed::cycle_detection or the prelude instead", since = "4.3.1", remove = "> 4.x" )] pub mod cycle_detection { pub use crate::directed::cycle_detection::*; } pathfinding-4.14.0/src/matrix.rs000064400000000000000000000757751046102023000146730ustar 00000000000000//! Matrix of an arbitrary type and utilities to rotate, transpose, etc. use crate::directed::bfs::bfs_reach; use crate::directed::dfs::dfs_reach; use crate::utils::{constrain, in_direction, move_in_direction, uint_sqrt}; use deprecate_until::deprecate_until; use num_traits::Signed; use std::collections::BTreeSet; use std::iter::FusedIterator; use std::ops::{Deref, DerefMut, Index, IndexMut, Neg, Range}; use std::slice::{Iter, IterMut}; use thiserror::Error; /// Matrix of an arbitrary type. Data are stored consecutively in /// memory, by rows. Raw data can be accessed using `as_ref()` /// or `as_mut()`. /// /// Coordinates within the matrix are represented as (row, column) tuples #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct Matrix { /// Rows pub rows: usize, /// Columns pub columns: usize, data: Vec, } impl Matrix { /// Create new matrix with an initial value. /// /// # Panics /// /// This function panics if the number of rows is greater than 0 /// and the number of columns is 0. If you need to build a matrix /// column by column, build it row by row and call transposition /// or rotation functions on it. pub fn new(rows: usize, columns: usize, value: C) -> Self { assert!( rows == 0 || columns > 0, "unable to create a matrix with empty rows" ); Self { rows, columns, data: vec![value; rows * columns], } } /// Create new matrix with each cell's initial value given by a /// function of its position. /// /// # Panics /// /// This function panics if the number of rows is greater than 0 /// and the number of columns is 0. If you need to build a matrix /// column by column, build it row by row and call transposition /// or rotation functions on it. pub fn from_fn(rows: usize, columns: usize, cb: impl FnMut((usize, usize)) -> C) -> Self { assert!( rows == 0 || columns > 0, "unable to create a matrix with empty rows" ); Self { rows, columns, data: (0..rows) .flat_map(move |row| (0..columns).map(move |column| (row, column))) .map(cb) .collect(), } } /// Create new square matrix with initial value. pub fn new_square(size: usize, value: C) -> Self { Self::new(size, size, value) } /// Fill with a known value. pub fn fill(&mut self, value: C) { self.data.fill(value); } /// Return a copy of a sub-matrix. /// /// # Errors /// /// [`MatrixFormatError::WrongIndex`] if the ranges /// are outside the original matrix. pub fn slice( &self, rows: Range, columns: Range, ) -> Result { if rows.end > self.rows || columns.end > self.columns { return Err(MatrixFormatError::WrongIndex); } let height = rows.end - rows.start; let width = columns.end - columns.start; let mut v = Vec::with_capacity(height * width); for r in rows { v.extend( self.data[r * self.columns + columns.start..r * self.columns + columns.end] .iter() .cloned(), ); } Self::from_vec(height, width, v) } /// Return a copy of a matrix rotated clock-wise /// a number of times. #[must_use] pub fn rotated_cw(&self, times: usize) -> Self { if self.is_square() { let mut copy = self.clone(); copy.rotate_cw(times); copy } else { match times % 4 { 0 => self.clone(), 1 => { let mut copy = self.transposed(); copy.flip_lr(); copy } 2 => { let mut copy = self.clone(); copy.data.reverse(); copy } _ => { let mut copy = self.transposed(); copy.flip_ud(); copy } } } } /// Return a copy of a matrix rotated counter-clock-wise /// a number of times. #[must_use] pub fn rotated_ccw(&self, times: usize) -> Self { self.rotated_cw(4 - (times % 4)) } /// Return a copy of the matrix flipped along the vertical axis. #[must_use] pub fn flipped_lr(&self) -> Self { let mut copy = self.clone(); copy.flip_lr(); copy } /// Return a copy of the matrix flipped along the horizontal axis. #[must_use] pub fn flipped_ud(&self) -> Self { let mut copy = self.clone(); copy.flip_ud(); copy } /// Return a copy of the matrix after transposition. /// /// # Panics /// /// This function will panic if the transposed matrix would end /// up with empty rows. #[must_use] pub fn transposed(&self) -> Self { assert!( self.rows != 0 || self.columns == 0, "this operation would create a matrix with empty rows" ); Self { rows: self.columns, columns: self.rows, data: (0..self.columns) .flat_map(|c| (0..self.rows).map(move |r| self.data[r * self.columns + c].clone())) .collect(), } } /// Extend the matrix in place by adding one full row. /// /// # Errors /// /// - [`MatrixFormatError::WrongLength`] if the row does not have /// the expected number of elements. /// - [`MatrixFormatError::EmptyRow`] if an empty row is passed. pub fn extend(&mut self, row: &[C]) -> Result<(), MatrixFormatError> { if row.is_empty() { return Err(MatrixFormatError::EmptyRow); } if self.columns != row.len() { return Err(MatrixFormatError::WrongLength); } self.rows += 1; for e in row { self.data.push(e.clone()); } Ok(()) } /// Swap two elements of the matrix. /// /// If `a` equals to `b`, it's guaranteed that elements won't change value. /// /// # Panics /// /// Panics if `a` or `b` are out of bounds. /// /// # Example /// /// ``` /// use pathfinding::matrix::*; /// /// let mut matrix = Matrix::square_from_vec(vec![1, 2, 10, 20]).unwrap(); /// matrix.swap((0, 0), (0, 1)); /// assert_eq!(matrix, Matrix::square_from_vec(vec![2, 1, 10, 20]).unwrap()); /// ``` pub fn swap(&mut self, a: (usize, usize), b: (usize, usize)) { let (a, b) = (self.idx(a), self.idx(b)); self.data.swap(a, b); } /// Transform the matrix into another matrix with the same shape /// after applying a transforming function to every elements. pub fn map(self, transform: F) -> Matrix where F: FnMut(C) -> O, { Matrix { rows: self.rows, columns: self.columns, data: self.data.into_iter().map(transform).collect(), } } } impl Matrix { /// Replace a slice of the current matrix with the content of another one. /// Only the relevant cells will be extracted if the slice goes outside the /// original matrix. pub fn set_slice(&mut self, pos: (usize, usize), slice: &Self) { let (row, column) = pos; let height = (self.rows - row).min(slice.rows); let width = (self.columns - column).min(slice.columns); for r in 0..height { self.data[(row + r) * self.columns + column..(row + r) * self.columns + column + width] .copy_from_slice(&slice.data[r * slice.columns..r * slice.columns + width]); } } } impl Neg for Matrix { type Output = Self; #[must_use] fn neg(self) -> Self { Self { rows: self.rows, columns: self.columns, data: self.data.iter().map(|x| -x.clone()).collect::>(), } } } impl Matrix { /// Create new matrix from vector values. The first value /// will be assigned to index (0, 0), the second one to index (0, 1), /// and so on. /// /// # Errors /// /// - [`MatrixFormatError::WrongLength`] if the data length does not /// correspond to the announced size /// - [`MatrixFormatError::EmptyRow`] if the matrix would contain /// an empty row pub fn from_vec( rows: usize, columns: usize, values: Vec, ) -> Result { if rows * columns != values.len() { return Err(MatrixFormatError::WrongLength); } if rows != 0 && columns == 0 { return Err(MatrixFormatError::EmptyRow); } Ok(Self { rows, columns, data: values, }) } /// Create new square matrix from vector values. The first value /// will be assigned to index (0, 0), the second one to index (0, 1), /// and so on. /// /// # Errors /// /// [`MatrixFormatError::WrongLength`] if the number of values is not a /// square number or if `values` is empty. pub fn square_from_vec(values: Vec) -> Result { let Some(size) = uint_sqrt(values.len()) else { return Err(MatrixFormatError::WrongLength); }; Self::from_vec(size, size, values) } /// Create new empty matrix with a predefined number of columns. /// This is useful to gradually build the matrix and extend it /// later using [`extend`](Matrix::extend) and does not require /// a filler element compared to [`Matrix::new`]. #[must_use] pub const fn new_empty(columns: usize) -> Self { Self { rows: 0, columns, data: vec![], } } /// Check if the matrix is empty. #[must_use] pub const fn is_empty(&self) -> bool { self.rows == 0 } /// Create a matrix from something convertible to an iterator on rows, /// each row being convertible to an iterator on columns. /// /// # Errors /// /// [`MatrixFormatError::WrongLength`] if length of rows differ or /// the rows are empty. /// /// # Example /// /// ``` /// use pathfinding::matrix::*; /// /// let input = "abc\ndef"; /// let matrix = Matrix::from_rows(input.lines().map(|l| l.chars()))?; /// assert_eq!(matrix.rows, 2); /// assert_eq!(matrix.columns, 3); /// assert_eq!(matrix[(1, 1)], 'e'); /// # Ok::<_, MatrixFormatError>(()) /// ``` pub fn from_rows(rows: IR) -> Result where IR: IntoIterator, IC: IntoIterator, { let mut rows = rows.into_iter(); if let Some(first_row) = rows.next() { let mut data = first_row.into_iter().collect::>(); let number_of_columns = data.len(); let mut number_of_rows = 1; for row in rows { number_of_rows += 1; data.extend(row); if number_of_rows * number_of_columns != data.len() { return Err(MatrixFormatError::WrongLength); } } Self::from_vec(number_of_rows, number_of_columns, data) } else { Ok(Self::new_empty(0)) } } /// Check if a matrix is a square one. #[must_use] pub const fn is_square(&self) -> bool { self.rows == self.columns } /// Index in raw data of a given position. /// /// # Safety /// /// This function returns a meaningless result if the /// coordinates do not designate a cell. #[must_use] pub const unsafe fn idx_unchecked(&self, i: (usize, usize)) -> usize { i.0 * self.columns + i.1 } /// Index in raw data of a given position. /// /// # Panics /// /// This function panics if the coordinates do not designate a cell. #[must_use] pub fn idx(&self, i: (usize, usize)) -> usize { assert!( i.0 < self.rows, "trying to access row {} (max {})", i.0, self.rows - 1 ); assert!( i.1 < self.columns, "trying to access column {} (max {})", i.1, self.columns - 1 ); unsafe { self.idx_unchecked(i) } } /// Constrain a wrapped-around index so that it falls inside the /// matrix. /// /// # Examples /// /// ```rust /// use pathfinding::matrix::Matrix; /// /// let matrix = Matrix::new(3, 5, 0); /// assert_eq!(matrix.constrain((1, 2)), (1, 2)); /// assert_eq!(matrix.constrain((10, -53)), (1, 2)); /// ``` #[must_use] pub const fn constrain(&self, (row, column): (isize, isize)) -> (usize, usize) { (constrain(row, self.rows), constrain(column, self.columns)) } /// Check if the coordinates designate a matrix cell. #[must_use] pub const fn within_bounds(&self, (row, column): (usize, usize)) -> bool { row < self.rows && column < self.columns } /// Access an element if the coordinates designate a matrix cell. #[must_use] pub fn get(&self, i: (usize, usize)) -> Option<&C> { self.within_bounds(i) .then(|| &self.data[unsafe { self.idx_unchecked(i) }]) } /// Mutably access an element if the coordinates designate a matrix cell. #[must_use] pub fn get_mut(&mut self, i: (usize, usize)) -> Option<&mut C> { self.within_bounds(i).then(|| { let idx = unsafe { self.idx_unchecked(i) }; &mut self.data[idx] }) } /// Flip the matrix around the vertical axis. pub fn flip_lr(&mut self) { for r in 0..self.rows { self.data[r * self.columns..(r + 1) * self.columns].reverse(); } } /// Flip the matrix around the horizontal axis. pub fn flip_ud(&mut self) { for r in 0..self.rows / 2 { for c in 0..self.columns { self.data .swap(r * self.columns + c, (self.rows - 1 - r) * self.columns + c); } } } /// Rotate a square matrix clock-wise a number of times. /// /// # Panics /// /// This function panics if the matrix is not square. pub fn rotate_cw(&mut self, times: usize) { assert!( self.rows == self.columns, "attempt to rotate a non-square matrix" ); match times % 4 { 0 => (), 2 => self.data.reverse(), n => { for r in 0..self.rows / 2 { for c in 0..(self.columns + 1) / 2 { // i1 … i2 // … … … // i4 … i3 let i1 = r * self.columns + c; let i2 = c * self.columns + self.columns - 1 - r; let i3 = (self.rows - 1 - r) * self.columns + self.columns - 1 - c; let i4 = (self.rows - 1 - c) * self.columns + r; if n == 1 { // i1 … i2 i4 … i1 // … … … => … … … // i4 … i3 i3 … i2 self.data.swap(i1, i2); self.data.swap(i1, i4); self.data.swap(i3, i4); } else { // i1 … i2 i2 … i3 // … … … => … … … // i4 … i3 i1 … i4 self.data.swap(i3, i4); self.data.swap(i1, i4); self.data.swap(i1, i2); } } } } } } /// Rotate a square matrix counter-clock-wise a number of times. /// /// # Panics /// /// This function panics if the matrix is not square. pub fn rotate_ccw(&mut self, times: usize) { self.rotate_cw(4 - (times % 4)); } /// Return an iterator on neighbours of a given matrix cell, with or /// without considering diagonals. The neighbours list is determined /// at the time of calling this method and will not change even if new /// rows are added between the method call and the iterator consumption. /// /// This function returns an empty iterator if the reference position does /// not correspond to an existing matrix element. pub fn neighbours( &self, (r, c): (usize, usize), diagonals: bool, ) -> impl Iterator { let (row_range, col_range) = if r < self.rows && c < self.columns { ( r.saturating_sub(1)..(self.rows).min(r + 2), c.saturating_sub(1)..(self.columns).min(c + 2), ) } else { (0..0, 0..0) }; row_range .flat_map(move |r| col_range.clone().map(move |c| (r, c))) .filter(move |&(rr, cc)| (rr != r || cc != c) && (diagonals || rr == r || cc == c)) } /// Return the next cells in a given direction starting from /// a given cell. Any direction (including with values greater than 1) can be /// given. `(0, 0)` is not a valid direction. /// /// # Examples /// /// Starting from square `(1, 1)` in a 8×8 chessboard, move like a knight /// by steps of two rows down and one column right: /// /// ``` /// use pathfinding::prelude::Matrix; /// let m = Matrix::new_square(8, '.'); /// assert_eq!(m.move_in_direction((1, 1), (2, 1)), Some((3, 2))); /// ``` #[must_use] pub fn move_in_direction( &self, start: (usize, usize), direction: (isize, isize), ) -> Option<(usize, usize)> { move_in_direction(start, direction, (self.rows, self.columns)) } /// Return an iterator of cells in a given direction starting from /// a given cell. Any direction (including with values greater than 1) can be /// given. The starting cell is not included in the results. /// /// # Examples /// /// Starting from square `(1, 1)` in a 8×8 chessboard, move like a knight /// by steps of two rows down and one column right: /// /// ``` /// use pathfinding::prelude::Matrix; /// let m = Matrix::new_square(8, '.'); /// assert_eq!(m.in_direction((1, 1), (2, 1)).collect::>(), /// vec![(3, 2), (5, 3), (7, 4)]); /// ``` /// /// Starting from square `(3, 2)` in the same chessboard, move diagonally in /// the North-West direction: /// /// ``` /// use pathfinding::prelude::{Matrix, directions}; /// let m = Matrix::new_square(8, '.'); /// assert_eq!(m.in_direction((3, 2), directions::NW).collect::>(), /// vec![(2, 1), (1, 0)]); /// ``` pub fn in_direction( &self, start: (usize, usize), direction: (isize, isize), ) -> impl Iterator { in_direction(start, direction, (self.rows, self.columns)) } /// Return an iterator on rows of the matrix. #[must_use] pub fn iter(&self) -> RowIterator<'_, C> { self.into_iter() } /// Return an iterator on content of columns of the matrix. /// /// This operation is more costly than using a row iterator, as it /// requires building vectors of column data which are not stored /// consecutively in memory. #[must_use] pub const fn column_iter(&self) -> ColumnIterator<'_, C> { ColumnIterator { matrix: self, column: 0, } } /// Return an iterator on the Matrix indices, first row first. The values are /// computed when this method is called and will not change even if new rows are /// added before the iterator is consumed. #[deprecate_until( note = "use the .keys() method instead", since = "4.1.0", remove = "> 4.x" )] pub fn indices(&self) -> impl Iterator { self.keys() } /// Return an iterator on the Matrix indices, first row first. The values are /// computed when this method is called and will not change even if new rows are /// added before the iterator is consumed. pub fn keys(&self) -> impl Iterator { let columns = self.columns; (0..self.rows).flat_map(move |r| (0..columns).map(move |c| (r, c))) } /// Return an iterator on values, first row first. pub fn values(&self) -> Iter { self.data.iter() } /// Return a mutable iterator on values, first row first. pub fn values_mut(&mut self) -> IterMut { self.data.iter_mut() } /// Return an iterator on the Matrix coordinates and values, first row first. pub fn items(&self) -> impl Iterator { self.keys().zip(self.values()) } /// Return an iterator on the Matrix coordinates and mutable values, /// first row first. pub fn items_mut(&mut self) -> impl Iterator { self.keys().zip(self.values_mut()) } /// Return a set of the indices reachable from a candidate starting point /// and for which the given predicate is valid. This can be used for example /// to implement a flood-filling algorithm. Since the indices are collected /// into a collection, they can later be used without keeping a reference on the /// matrix itself, e.g., to modify the matrix. /// /// The search is done using a breadth first search (BFS) algorithm. /// /// # See also /// /// The [`dfs_reachable()`](`Self::dfs_reachable`) method performs a DFS search instead. pub fn bfs_reachable

( &self, start: (usize, usize), diagonals: bool, mut predicate: P, ) -> BTreeSet<(usize, usize)> where P: FnMut((usize, usize)) -> bool, { bfs_reach(start, |&n| { self.neighbours(n, diagonals) .filter(|&n| predicate(n)) .collect::>() }) .collect() } /// Return a set of the indices reachable from a candidate starting point /// and for which the given predicate is valid. This can be used for example /// to implement a flood-filling algorithm. Since the indices are collected /// into a vector, they can later be used without keeping a reference on the /// matrix itself, e.g., to modify the matrix. /// /// The search is done using a depth first search (DFS) algorithm. /// /// # See also /// /// The [`bfs_reachable()`](`Self::bfs_reachable`) method performs a BFS search instead. pub fn dfs_reachable

( &self, start: (usize, usize), diagonals: bool, mut predicate: P, ) -> BTreeSet<(usize, usize)> where P: FnMut((usize, usize)) -> bool, { dfs_reach(start, |&n| { self.neighbours(n, diagonals) .filter(|&n| predicate(n)) .collect::>() }) .collect() } /// Transposes any matrix in place. fn transpose_in_place_non_square(&mut self) { let m = self.columns; let n = self.rows; // Adjusted cycle length excluding the fixed point at 0, 0 let mn1 = m * n - 1; // Scratch array for recording visited locations let mut visited = vec![0u8; (m * n + 7).div_ceil(8)]; for s in 1..self.data.len() { if visited[s / 8] & (1 << (s % 8)) != 0 { continue; } // Identified an unvisited start point in a cycle let mut x = s; loop { // Calculate the next position 'x' for the element to be moved. // If it is in the last position, then there is nothing to do. // Otherwise, calculate the new position using the formula (n * x) % mn1. // This will ensure we visit all positions in a way that eventually visits // and transposes every element, without exceeding the matrix's bounds. if x != mn1 { x = (n * x) % mn1; } self.data.swap(x, s); visited[x / 8] |= 1 << (x % 8); // Stop when we're back at the start of the cycle if x == s { break; } } } // The matrix is now transposed, so we can swap the rows and columns self.rows = m; self.columns = n; } /// Transpose a matrix in place. /// /// For more information refer to /// [In-place matrix transposition](https://en.wikipedia.org/wiki/In-place_matrix_transposition). pub fn transpose(&mut self) { // Transposing square matrices in place is significantly more efficient than non- // square matrices, so we handle that special case separately. if self.rows == self.columns { for r in 0..self.rows { for c in r + 1..self.columns { self.data.swap(r * self.columns + c, c * self.columns + r); } } } else { self.transpose_in_place_non_square(); } } } impl Index<(usize, usize)> for Matrix { type Output = C; #[must_use] fn index(&self, index: (usize, usize)) -> &C { &self.data[self.idx(index)] } } impl Index<&(usize, usize)> for Matrix { type Output = C; #[must_use] fn index(&self, index: &(usize, usize)) -> &C { &self[*index] } } impl IndexMut<(usize, usize)> for Matrix { fn index_mut(&mut self, index: (usize, usize)) -> &mut C { let i = self.idx(index); &mut self.data[i] } } impl IndexMut<&(usize, usize)> for Matrix { fn index_mut(&mut self, index: &(usize, usize)) -> &mut C { &mut self[*index] } } impl Deref for Matrix { type Target = [C]; #[must_use] fn deref(&self) -> &[C] { &self.data } } impl DerefMut for Matrix { fn deref_mut(&mut self) -> &mut [C] { &mut self.data } } impl FromIterator for Matrix where IC: IntoIterator, { fn from_iter>(iter: T) -> Self { match Self::from_rows(iter) { Ok(matrix) => matrix, Err(e) => panic!("{e}"), } } } /// The matrix! macro allows the declaration of a Matrix from static data. /// All rows must have the same number of columns. The data will be copied /// into the matrix. There exist two forms: /// /// - `matrix![(row1, row2, …, rowN)]`, each row being an array /// - `matrix![r1c1, r1c2, …, r1cN; r2c1, …,r2cN; …; rNc1, …, rNcN]` /// - `matrix![]` creates an empty matrix with a column size of 0 /// /// # Panics /// /// This macro panics if the rows have an inconsistent number of columns. /// /// # Example /// /// ``` /// use pathfinding::matrix; /// /// let m1 = matrix![[10, 20, 30], [40, 50, 60]]; /// assert_eq!(m1.columns, 3); /// assert_eq!(m1.rows, 2); /// /// let m2 = matrix![10, 20, 30; 40, 50, 60]; /// assert_eq!(m1, m2); /// ``` #[macro_export] macro_rules! matrix { () => { pathfinding::matrix::Matrix::new_empty(0) }; ($a:expr $(, $b: expr)*$(,)?) => {{ let mut m = pathfinding::matrix::Matrix::new_empty($a.len()); m.extend(&$a).unwrap(); $( match m.extend(&$b) { Ok(row) => row, Err(_) => panic!("all rows must have the same width"), } )* m }}; ($($($a:expr),+$(,)?);+$(;)?) => { matrix![$([$($a),+]),+] }; } /// Format error encountered while attempting to build a Matrix. #[derive(Debug, Error)] pub enum MatrixFormatError { /// Attempt to build a matrix containing an empty row #[error("matrix rows cannot be empty")] EmptyRow, /// Attempt to access elements not inside the matrix #[error("index does not point to data inside the matrix")] WrongIndex, /// Attempt to build a matrix or a row from data with the wrong length #[error("provided data does not correspond to the expected length")] WrongLength, } /// Row iterator returned by `iter()` on a matrix. pub struct RowIterator<'a, C> { matrix: &'a Matrix, row: usize, } impl<'a, C> Iterator for RowIterator<'a, C> { type Item = &'a [C]; fn next(&mut self) -> Option { (self.row < self.matrix.rows).then(|| { self.row += 1; &self.matrix.data[(self.row - 1) * self.matrix.columns..self.row * self.matrix.columns] }) } } impl DoubleEndedIterator for RowIterator<'_, C> { fn next_back(&mut self) -> Option { (self.row < self.matrix.rows).then(|| { let row = self.matrix.rows - self.row; self.row += 1; &self.matrix.data[(row - 1) * self.matrix.columns..row * self.matrix.columns] }) } } impl FusedIterator for RowIterator<'_, C> {} impl<'a, C> IntoIterator for &'a Matrix { type IntoIter = RowIterator<'a, C>; type Item = &'a [C]; #[must_use] fn into_iter(self) -> RowIterator<'a, C> { RowIterator { matrix: self, row: 0, } } } /// Column iterator returned by `column_iter()` on a matrix. pub struct ColumnIterator<'a, C> { matrix: &'a Matrix, column: usize, } impl<'a, C> Iterator for ColumnIterator<'a, C> { type Item = Vec<&'a C>; fn next(&mut self) -> Option { (self.column < self.matrix.columns).then(|| { self.column += 1; (0..self.matrix.rows) .map(|r| &self.matrix[(r, self.column - 1)]) .collect() }) } } impl DoubleEndedIterator for ColumnIterator<'_, C> { fn next_back(&mut self) -> Option { (self.column < self.matrix.columns).then(|| { self.column += 1; let column = self.matrix.columns - self.column; (0..self.matrix.rows) .map(|r| &self.matrix[(r, column)]) .collect() }) } } impl FusedIterator for ColumnIterator<'_, C> {} /// Directions usable for [`Matrix::in_direction()`] second argument. pub mod directions { /// East pub const E: (isize, isize) = (0, 1); /// South pub const S: (isize, isize) = (1, 0); /// West pub const W: (isize, isize) = (0, -1); /// North pub const N: (isize, isize) = (-1, 0); /// North-East pub const NE: (isize, isize) = (-1, 1); /// South-East pub const SE: (isize, isize) = (1, 1); /// North-West pub const NW: (isize, isize) = (-1, -1); /// South-West pub const SW: (isize, isize) = (1, -1); /// Four main directions pub const DIRECTIONS_4: [(isize, isize); 4] = [E, S, W, N]; /// Eight main directions with diagonals pub const DIRECTIONS_8: [(isize, isize); 8] = [NE, E, SE, S, SW, W, NW, N]; } pathfinding-4.14.0/src/undirected/cliques.rs000064400000000000000000000072701046102023000171430ustar 00000000000000//! Find cliques in an undirected graph. use std::collections::HashSet; use std::hash::Hash; /// Find all maximal cliques in an undirected graph. /// /// That is, it lists all subsets of vertices with the two properties that each pair of vertices in /// one of the listed subsets is connected by an edge, and no listed subset can have /// any additional vertices added to it while preserving its complete connectivity. /// [Bron-Kerbosch algorithm](https://en.wikipedia.org/wiki/Bron%E2%80%93Kerbosch_algorithm). /// /// /// - `vertices` is the list of all nodes. /// - `connected` returns true if the two given node is connected. /// - return a list of cliques. pub fn maximal_cliques_collect(vertices: IN, connected: &mut FN) -> Vec> where N: Eq + Hash + Clone, FN: FnMut(&N, &N) -> bool, IN: IntoIterator, { let mut result = Vec::new(); let mut consumer = |n: &HashSet| result.push(n.to_owned()); let mut remaining_nodes: HashSet = vertices.into_iter().collect::>(); bron_kerbosch( connected, &HashSet::new(), &mut remaining_nodes, &mut HashSet::new(), &mut consumer, ); result } /// Find all maximal cliques in an undirected graph. /// /// That is, it lists all subsets of vertices with the two properties that each pair of vertices in /// one of the listed subsets is connected by an edge, and no listed subset can have /// any additional vertices added to it while preserving its complete connectivity. /// [Bron-Kerbosch algorithm](https://en.wikipedia.org/wiki/Bron%E2%80%93Kerbosch_algorithm). /// /// /// - `vertices` is the list of all nodes. /// - `connected` returns true if the two given node is connected. /// - 'consumer' function which called for each clique. /// pub fn maximal_cliques(vertices: IN, connected: &mut FN, consumer: &mut CO) where N: Eq + Hash + Clone, FN: FnMut(&N, &N) -> bool, IN: IntoIterator, CO: FnMut(&HashSet), { let mut remaining_nodes: HashSet = vertices.into_iter().collect(); bron_kerbosch( connected, &HashSet::new(), &mut remaining_nodes, &mut HashSet::new(), consumer, ); } fn bron_kerbosch( connected: &mut FN, potential_clique: &HashSet, remaining_nodes: &mut HashSet, skip_nodes: &mut HashSet, consumer: &mut CO, ) where N: Eq + Hash + Clone, FN: FnMut(&N, &N) -> bool, CO: FnMut(&HashSet), { if remaining_nodes.is_empty() && skip_nodes.is_empty() { consumer(potential_clique); return; } let nodes_to_check = remaining_nodes.clone(); for node in &nodes_to_check { let mut new_potential_clique = potential_clique.clone(); new_potential_clique.insert(node.to_owned()); let mut new_remaining_nodes: HashSet = remaining_nodes .iter() .filter(|n| *n != node && connected(node, n)) .cloned() .collect(); let mut new_skip_list: HashSet = skip_nodes .iter() .filter(|n| *n != node && connected(node, n)) .cloned() .collect(); bron_kerbosch( connected, &new_potential_clique, &mut new_remaining_nodes, &mut new_skip_list, consumer, ); // We're done considering this node. If there was a way to form a clique with it, we // already discovered its maximal clique in the recursive call above. So, go ahead // and remove it from the list of remaining nodes and add it to the skip list. remaining_nodes.remove(node); skip_nodes.insert(node.to_owned()); } } pathfinding-4.14.0/src/undirected/connected_components.rs000064400000000000000000000205761046102023000217110ustar 00000000000000//! Separate components of an undirected graph into disjoint sets. use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::collections::{HashMap, HashSet}; use std::hash::Hash; use std::iter::once; use std::marker::PhantomData; use rustc_hash::{FxHashMap, FxHashSet}; /// A connected component implementation for various generic types. /// /// This structure is only useful if the default collections used by /// the various functions of the [`connected_components`](self) module /// do not fit your needs. pub struct ConnectedComponents< N, It = Vec, It2 = HashSet, C1 = HashSet, C2 = Vec, C3 = HashMap, > { _n: PhantomData, _it: PhantomData, _it2: PhantomData, _c1: PhantomData, _c2: PhantomData, _c3: PhantomData, } impl ConnectedComponents where N: Hash + Eq + Clone, It: IntoIterator + Clone, for<'it> &'it It: IntoIterator, for<'it> &'it It2: IntoIterator, C1: FromIterator, C2: FromIterator, C3: FromIterator<(N, usize)>, { /// Separate components of an undirected graph into disjoint sets. /// /// - `groups` is a set of group of vertices connected together. It is /// acceptable for a group to contain only one node. Empty groups /// receive special treatment (see below). /// /// This function returns a pair containing: /// /// - A mapping from every vertex to its set identifier. The set identifiers are /// opaque and will not necessarily be compact. However, it is guaranteed that /// they will not be greater than the number of groups. /// - A mapping from every group to its set identifier, with the identifiers being /// the same ones as the ones in the previous mapping. Each group corresponds to /// the identifier at the same index, except for empty group whose identifier is /// set to `usize::MAX`. /// /// Note that if you have a raw undirected graph, you can build /// such a structure by creating a group for every vertex containing /// the vertex itself and its immediate neighbours. #[must_use] pub fn separate_components(groups: &[It]) -> (HashMap<&N, usize>, Vec) { let mut table = (0..groups.len()).collect::>(); let mut indices = HashMap::new(); for (mut group_index, group) in groups.iter().enumerate() { let mut is_empty = true; for element in group { is_empty = false; match indices.entry(element) { Occupied(e) => { table[group_index] = find(&mut table, *e.get()); group_index = table[group_index]; } Vacant(e) => { e.insert(group_index); } } } if is_empty { table[group_index] = usize::MAX; } } for group_index in indices.values_mut() { *group_index = find(&mut table, *group_index); } for group_index in 0..groups.len() { if table[group_index] != usize::MAX { let target = find(&mut table, group_index); // Due to path halving, this particular entry might not // be up-to-date yet. table[group_index] = target; } } (indices, table) } /// Separate components of an undirected graph into disjoint sets. /// /// - `groups` is a set of group of vertices connected together. It is /// acceptable for a group to contain only one node. /// /// This function returns a list of sets of nodes forming disjoint connected /// sets. #[must_use] pub fn components(groups: &[It]) -> C2 { let (_, gindices) = Self::separate_components(groups); let mut gb: FxHashMap> = FxHashMap::default(); for (i, n) in gindices .into_iter() .enumerate() .filter(|&(_, n)| n != usize::MAX) { let set = gb.entry(n).or_default(); for e in groups[i].clone() { set.insert(e); } } gb.into_values().map(|v| v.into_iter().collect()).collect() } /// Extract connected components from a graph. /// /// - `starts` is a collection of vertices to be considered as start points. /// - `neighbours` is a function returning the neighbours of a given node. /// /// This function returns a list of sets of nodes forming disjoint connected /// sets. pub fn connected_components(starts: &[N], mut neighbours: FN) -> C2 where FN: FnMut(&N) -> IN, IN: IntoIterator, { ConnectedComponents::, It2, C1, C2, C3>::components( &starts .iter() .map(|s| { neighbours(s) .into_iter() .chain(once(s.clone())) .collect::>() }) .collect::>(), ) } /// Locate vertices amongst disjoint sets. /// /// - `components` are disjoint vertices sets. /// /// This function returns a map between every vertex and the index of /// the set it belongs to in the `components` list. #[must_use] pub fn component_index(components: &[It2]) -> C3 { components .iter() .enumerate() .flat_map(|(i, c)| c.into_iter().map(move |n| (n.clone(), i))) .collect() } } fn find(table: &mut [usize], mut x: usize) -> usize { while table[x] != x { let t = table[x]; table[x] = table[table[x]]; x = t; } x } /// Separate components of an undirected graph into disjoint sets. /// /// - `groups` is a set of group of vertices connected together. It is /// acceptable for a group to contain only one node. Empty groups /// receive special treatment (see below). /// /// This function returns a pair containing: /// /// - A mapping from every vertex to its set identifier. The set identifiers are /// opaque and will not necessarily be compact. However, it is guaranteed that /// they will not be greater than the number of groups. /// - A mapping from every group to its set identifier, with the identifiers being /// the same ones as the ones in the previous mapping. Each group corresponds to /// the identifier at the same index, except for empty group whose identifier is /// set to `usize::MAX`. /// /// Note that if you have a raw undirected graph, you can build /// such a structure by creating a group for every vertex containing /// the vertex itself and its immediate neighbours. #[must_use] pub fn separate_components(groups: &[Vec]) -> (HashMap<&N, usize>, Vec) where N: Hash + Eq + Clone, { ConnectedComponents::::separate_components(groups) } /// Separate components of an undirected graph into disjoint sets. /// /// - `groups` is a set of group of vertices connected together. It is /// acceptable for a group to contain only one node. /// /// This function returns a list of sets of nodes forming disjoint connected /// sets. #[must_use] pub fn components(groups: &[Vec]) -> Vec> where N: Clone + Hash + Eq, { ConnectedComponents::::components(groups) } /// Extract connected components from a graph. /// /// - `starts` is a collection of vertices to be considered as start points. /// - `neighbours` is a function returning the neighbours of a given node. /// /// This function returns a list of sets of nodes forming disjoint connected /// sets. pub fn connected_components(starts: &[N], neighbours: FN) -> Vec> where N: Clone + Hash + Eq, FN: FnMut(&N) -> IN, IN: IntoIterator, { ConnectedComponents::::connected_components(starts, neighbours) } /// Locate vertices amongst disjoint sets. /// /// - `components` are disjoint vertices sets. /// /// This function returns a map between every vertex and the index of /// the set it belongs to in the `components` list. #[must_use] #[allow(clippy::implicit_hasher)] pub fn component_index(components: &[HashSet]) -> HashMap where N: Clone + Hash + Eq, { ConnectedComponents::::component_index(components) } pathfinding-4.14.0/src/undirected/kruskal.rs000064400000000000000000000057271046102023000171570ustar 00000000000000//! Find minimum-spanning-tree in an undirected graph using //! [Kruskal's algorithm](https://en.wikipedia.org/wiki/Kruskal's_algorithm). use crate::FxIndexSet; use std::hash::Hash; use std::mem; // Find parent and compress path by path halving. fn find(parents: &mut [usize], mut node: usize) -> usize { while parents[node] != node { parents[node] = parents[parents[node]]; node = parents[node]; } node } fn union(parents: &mut [usize], ranks: &mut [usize], mut a: usize, mut b: usize) { if ranks[a] < ranks[b] { mem::swap(&mut a, &mut b); } parents[b] = a; if ranks[a] == ranks[b] { ranks[a] += 1; } } /// Minimal-spanning-tree for nodes with integer indices. The nodes must have /// consecutives indices between 0 and `number_of_nodes`-1. /// /// # Panics /// /// This function panics if a node is outside the range [0, `number_of_nodes`-1]. pub fn kruskal_indices( number_of_nodes: usize, edges: impl AsRef<[(usize, usize, C)]>, ) -> impl Iterator where C: Clone + Ord, { let mut parents = (0..number_of_nodes).collect::>(); let mut ranks = vec![1; number_of_nodes]; let mut edges = edges.as_ref().to_vec(); edges.sort_unstable_by(|a, b| a.2.cmp(&b.2)); edges.into_iter().filter_map(move |(a, b, w)| { let ra = find(&mut parents, a); let rb = find(&mut parents, b); if ra == rb { None } else { union(&mut parents, &mut ranks, ra, rb); Some((a, b, w)) } }) } /// Find a minimum-spanning-tree. From a collection of /// weighted edges, return a vector of edges forming /// a minimum-spanning-tree. pub fn kruskal(edges: &[(N, N, C)]) -> impl Iterator where N: Hash + Eq, C: Clone + Ord, { let mut nodes = FxIndexSet::default(); let edges = edges .iter() .map(|(a, b, w)| { let ia = nodes.insert_full(a).0; let ib = nodes.insert_full(b).0; (ia, ib, w.clone()) }) .collect::>(); kruskal_indices(nodes.len(), edges).filter_map(move |(ia, ib, w)| { Some(( <&N>::clone(nodes.get_index(ia)?), // Cannot fail <&N>::clone(nodes.get_index(ib)?), // Cannot fail w, )) }) } #[cfg(test)] mod tests { use super::find; #[test] fn path_halving() { let mut parents = vec![0, 0, 1, 2, 3, 4, 5, 6]; assert_eq!(find(&mut parents, 7), 0); assert_eq!(parents, vec![0, 0, 1, 1, 3, 3, 5, 5]); assert_eq!(find(&mut parents, 7), 0); assert_eq!(parents, vec![0, 0, 1, 0, 3, 3, 5, 3]); assert_eq!(find(&mut parents, 7), 0); assert_eq!(parents, vec![0, 0, 1, 0, 3, 3, 5, 0]); assert_eq!(find(&mut parents, 6), 0); assert_eq!(parents, vec![0, 0, 1, 0, 3, 3, 3, 0]); assert_eq!(find(&mut parents, 6), 0); assert_eq!(parents, vec![0, 0, 1, 0, 3, 3, 0, 0]); } } pathfinding-4.14.0/src/undirected/mod.rs000064400000000000000000000001651046102023000162510ustar 00000000000000//! Algorithms for undirected graphs. pub mod cliques; pub mod connected_components; pub mod kruskal; pub mod prim; pathfinding-4.14.0/src/undirected/prim.rs000064400000000000000000000024331046102023000164410ustar 00000000000000//! Find minimum-spanning-tree in an undirected graph using [Prim's //! algorithm](https://en.wikipedia.org/wiki/Prim%27s_algorithm). use std::cmp::Reverse; use std::collections::{BinaryHeap, HashSet}; use std::hash::Hash; /// Find a minimum-spanning-tree. From a collection of weighted edges, /// return a vector of edges forming a minimum-spanning-tree. pub fn prim(edges: &[(N, N, C)]) -> Vec<(&N, &N, C)> where N: Hash + Eq + Ord, C: Clone + Ord, { let Some((start, ..)) = edges.first() else { return vec![]; }; let mut priority_queue = edges .iter() .filter_map(|(n, n1, c)| (n == start).then_some(Reverse((c, n, n1)))) .collect::>(); let (mut mst, mut visited) = (Vec::new(), HashSet::new()); visited.insert(start); while let Some(Reverse((c, n, n1))) = priority_queue.pop() { if visited.contains(n1) { continue; } mst.push((n, n1, c.clone())); for (n2, n3, c) in edges { if n1 == n2 && !visited.contains(n3) { priority_queue.push(Reverse((c, n1, n3))); } else if n1 == n3 && !visited.contains(n2) { priority_queue.push(Reverse((c, n1, n2))); } } visited.insert(n1); } mst } pathfinding-4.14.0/src/utils.rs000064400000000000000000000052741046102023000145120ustar 00000000000000//! Miscellaneous utilities use integer_sqrt::IntegerSquareRoot; use num_traits::{PrimInt, Unsigned}; /// Return the square root of `n` if `n` is square, `None` otherwise. /// /// # Example /// /// ``` /// use pathfinding::utils::uint_sqrt; /// /// assert_eq!(uint_sqrt(100usize), Some(10)); /// assert_eq!(uint_sqrt(10usize), None); /// ``` pub fn uint_sqrt(n: T) -> Option where T: PrimInt + Unsigned, { let root = n.integer_sqrt(); (n == root * root).then_some(root) } /// Move a two-dimensional coordinate into a given direction provided that: /// - The `start` point is valid (given the `dimensions`). /// - The `direction` is not `(0,0)` /// - The target point is valid (given the `dimensions`). /// /// # Example /// /// ``` /// use pathfinding::utils::move_in_direction; /// /// let board = (8, 8); /// assert_eq!(move_in_direction((5, 5), (-1, -2), board), Some((4, 3))); /// assert_eq!(move_in_direction((1, 1), (-1, -2), board), None); /// ``` #[must_use] #[allow(clippy::cast_possible_wrap, clippy::cast_sign_loss)] pub fn move_in_direction( start: (usize, usize), direction: (isize, isize), dimensions: (usize, usize), ) -> Option<(usize, usize)> { let (row, col) = start; if row >= dimensions.0 || col >= dimensions.1 || direction == (0, 0) { return None; } let (new_row, new_col) = (row as isize + direction.0, col as isize + direction.1); (new_row >= 0 && (new_row as usize) < dimensions.0 && new_col >= 0 && (new_col as usize) < dimensions.1) .then_some((new_row as usize, new_col as usize)) } /// Repeatedly call [`move_in_direction`] until the returned value /// is `None`. /// /// # Example /// /// ``` /// use pathfinding::utils::in_direction; /// /// let board = (8, 8); /// let positions = in_direction((0, 0), (1, 2), board).collect::>(); /// assert_eq!(positions, vec![(1, 2), (2, 4), (3, 6)]); /// ``` pub fn in_direction( start: (usize, usize), direction: (isize, isize), dimensions: (usize, usize), ) -> impl Iterator { std::iter::successors(Some(start), move |current| { move_in_direction(*current, direction, dimensions) }) .skip(1) } /// Constrain `value` into `0..upper` by adding or subtracting `upper` /// as many times as necessary. /// /// # Examples /// /// ``` /// use pathfinding::utils::constrain; /// /// assert_eq!(constrain(5, 7), 5); /// assert_eq!(constrain(30, 7), 2); /// assert_eq!(constrain(-30, 7), 5); /// ``` #[must_use] #[allow(clippy::cast_sign_loss)] pub const fn constrain(value: isize, upper: usize) -> usize { if value > 0 { value as usize % upper } else { (upper - (-value) as usize % upper) % upper } } pathfinding-4.14.0/tests/A-small-practice.in000064400000000000000000005221431046102023000167640ustar 00000000000000100 4 4 8 15 16 23 42 8 6 7 5 30 9 1 2 3 4 55 6 2 10 18 36 54 86 2 1 2 3 4 5 6 60 50 40 30 20 10 3 1 2 3 4 5 6 1 2 3 4 5 6 1 4 2 6 5 3 30 7564 7565 7567 7563 7568 7566 7567 7564 7568 7563 7565 7566 7564 7568 7567 7566 7563 7565 7568 7564 7563 7567 7565 7566 7565 7566 7568 7563 7564 7567 7564 7563 7566 7568 7567 7565 7568 7565 7567 7566 7563 7564 7567 7564 7568 7566 7563 7565 7564 7568 7567 7565 7566 7563 7564 7568 7566 7565 7567 7563 7563 7564 7565 7567 7566 7568 7566 7568 7567 7565 7563 7564 7566 7565 7563 7564 7567 7568 7568 7567 7564 7566 7565 7563 7568 7564 7567 7566 7563 7565 7568 7565 7566 7567 7563 7564 7563 7568 7566 7567 7565 7564 7566 7563 7567 7564 7568 7565 7565 7567 7564 7566 7568 7563 7563 7566 7567 7568 7564 7565 7563 7567 7566 7564 7568 7565 7563 7564 7565 7568 7566 7567 7563 7566 7568 7564 7565 7567 7566 7568 7565 7567 7563 7564 7566 7565 7568 7567 7564 7563 7565 7566 7568 7564 7563 7567 7563 7565 7564 7567 7566 7568 7563 7567 7564 7568 7566 7565 7564 7565 7568 7563 7567 7566 7564 7568 7565 7567 7566 7563 30 9484 9487 9488 9482 9485 9486 9489 9494 9496 9491 9495 9493 9497 9499 9495 9494 9498 9496 9483 9486 9482 9480 9479 9484 9498 9493 9496 9495 9500 9492 9494 9491 9493 9496 9497 9495 9496 9495 9499 9503 9500 9497 9496 9497 9494 9495 9498 9500 9491 9493 9486 9488 9494 9489 9493 9499 9501 9498 9500 9494 9485 9482 9490 9487 9489 9483 9487 9494 9490 9488 9492 9491 9483 9482 9484 9481 9477 9479 9480 9478 9477 9481 9476 9482 9471 9474 9472 9473 9468 9467 9469 9473 9468 9470 9475 9476 9486 9489 9487 9485 9488 9484 9491 9485 9487 9493 9486 9492 9490 9487 9491 9485 9489 9483 9480 9476 9477 9483 9481 9482 9498 9502 9503 9499 9496 9501 9486 9487 9483 9480 9485 9484 9472 9478 9473 9471 9474 9476 9488 9490 9495 9491 9494 9493 9474 9477 9475 9479 9472 9476 9477 9470 9476 9471 9474 9473 9483 9482 9479 9481 9478 9480 9485 9478 9480 9481 9483 9479 9477 9471 9470 9473 9474 9478 9476 9475 9479 9478 9474 9480 10 9553 9554 9548 9551 9558 9557 9557 9554 9552 9556 9549 9548 9554 9557 9550 9555 9556 9549 9550 9554 9557 9556 9555 9553 9549 9557 9553 9551 9556 9552 9555 9551 9556 9557 9553 9552 9552 9548 9555 9554 9553 9551 9550 9555 9549 9556 9557 9552 9554 9556 9552 9551 9557 9548 9549 9557 9548 9558 9553 9552 30 3349 3353 3352 3351 3348 3350 3353 3347 3354 3348 3350 3352 3349 3347 3355 3348 3352 3354 3355 3349 3354 3347 3352 3351 3353 3347 3355 3352 3350 3349 3352 3349 3347 3355 3348 3353 3347 3349 3352 3355 3353 3348 3347 3349 3352 3350 3351 3353 3352 3347 3355 3349 3350 3348 3351 3349 3352 3353 3350 3348 3351 3353 3355 3348 3354 3349 3354 3348 3351 3350 3352 3353 3354 3347 3349 3348 3352 3353 3355 3347 3353 3349 3354 3352 3351 3350 3355 3354 3347 3353 3355 3350 3354 3352 3353 3351 3354 3350 3348 3355 3349 3351 3351 3347 3353 3352 3355 3349 3355 3354 3347 3351 3352 3349 3352 3347 3348 3350 3353 3354 3354 3353 3347 3355 3349 3351 3347 3355 3352 3354 3350 3348 3352 3353 3349 3348 3354 3351 3351 3347 3349 3348 3355 3350 3354 3352 3348 3355 3347 3350 3348 3353 3350 3347 3355 3354 3349 3355 3351 3348 3350 3347 3352 3350 3354 3355 3353 3347 3355 3349 3347 3354 3351 3352 3353 3348 3349 3350 3352 3351 98 6802 6864 6836 6871 6841 6855 6790 6765 6745 6833 6769 6819 6822 6868 6845 6796 6770 6766 6805 6872 6853 6848 6759 6795 6868 6780 6834 6732 6758 6803 6827 6748 6762 6859 6745 6755 6864 6760 6755 6766 6817 6753 6792 6822 6854 6774 6742 6731 6872 6818 6816 6728 6826 6845 6759 6730 6773 6805 6774 6842 6745 6746 6867 6766 6832 6740 6779 6846 6731 6811 6782 6762 6824 6731 6763 6848 6741 6733 6766 6835 6736 6820 6841 6861 6743 6757 6821 6835 6804 6791 6773 6798 6737 6806 6782 6736 6776 6807 6739 6827 6792 6734 6762 6817 6770 6831 6872 6822 6800 6736 6769 6790 6868 6849 6727 6832 6767 6755 6761 6752 6801 6848 6727 6800 6797 6817 6803 6762 6832 6727 6802 6729 6753 6740 6847 6822 6801 6807 6820 6799 6744 6786 6764 6787 6858 6754 6791 6784 6827 6783 6787 6816 6851 6751 6836 6775 6745 6781 6868 6852 6747 6787 6834 6855 6806 6727 6818 6762 6870 6731 6808 6757 6794 6832 6739 6810 6855 6753 6826 6780 6820 6781 6792 6835 6872 6837 6817 6788 6808 6821 6799 6751 6842 6853 6828 6776 6855 6754 6816 6740 6784 6778 6805 6751 6866 6855 6870 6863 6765 6828 6767 6794 6752 6780 6829 6815 6808 6769 6861 6831 6865 6842 6785 6727 6864 6774 6733 6741 6756 6810 6739 6793 6778 6765 6828 6850 6729 6820 6733 6849 6827 6807 6727 6736 6777 6744 6864 6836 6787 6870 6736 6847 6829 6803 6786 6800 6804 6755 6753 6835 6824 6841 6787 6813 6777 6842 6811 6820 6735 6772 6772 6828 6830 6758 6855 6862 6846 6788 6763 6737 6810 6837 6830 6774 6728 6739 6863 6746 6867 6845 6767 6749 6812 6813 6737 6792 6862 6853 6791 6832 6814 6784 6811 6732 6731 6758 6759 6806 6796 6827 6758 6731 6859 6764 6779 6729 6787 6762 6830 6797 6764 6773 6854 6807 6801 6779 6759 6766 6854 6793 6811 6867 6854 6809 6825 6739 6865 6800 6866 6785 6871 6730 6757 6785 6752 6824 6807 6863 6816 6819 6727 6822 6850 6742 6734 6741 6775 6795 6803 6780 6862 6732 6755 6768 6757 6844 6790 6782 6810 6825 6803 6781 6870 6844 6747 6840 6777 6868 6726 6783 6861 6776 6827 6778 6871 6753 6801 6821 6758 6825 6793 6857 6810 6771 6785 6731 6809 6797 6838 6803 6816 6750 6841 6765 6829 6803 6791 6831 6761 6838 6753 6763 6726 6856 6758 6778 6820 6761 6732 6727 6733 6807 6795 6800 6822 6818 6729 6814 6728 6800 6855 6755 6815 6758 6728 6820 6737 6773 6844 6870 6746 6865 6779 6847 6747 6848 6830 6807 6831 6790 6797 6862 6750 6847 6740 6781 6809 6837 6815 6735 6811 6840 6864 6822 6746 6839 6785 6810 6739 6856 6791 6744 6747 6818 6728 6836 6746 6824 6809 6832 6828 6812 6866 6832 6819 6846 6762 6803 6742 6848 6732 6749 6843 6728 6864 6788 6856 6857 6769 6854 6853 6825 6805 6750 6825 6839 6734 6855 6779 6795 6851 6762 6817 6865 6739 6801 6799 6811 6767 6797 6776 6775 6787 6796 6853 6808 6763 6833 6825 6788 6746 6843 6864 6856 6814 6792 6824 6853 6770 6825 6869 6810 6830 6791 6735 6853 6812 6863 6794 6804 6820 6742 6811 6730 6832 6796 6848 6734 6771 6823 6733 6760 6734 6806 6866 6727 6741 6852 6822 6863 6854 6799 6860 6831 6771 6855 6780 6871 6823 6799 6750 6776 6769 6825 6757 6795 6869 6808 99 4465 4429 4442 4509 4521 4403 4485 4490 4421 4412 4481 4503 4472 4443 4470 4388 4452 4503 4492 4449 4439 4438 4398 4456 4531 4486 4444 4450 4462 4476 4416 4435 4503 4468 4430 4440 4462 4390 4519 4466 4414 4475 4520 4439 4395 4408 4490 4442 4413 4476 4510 4385 4440 4472 4392 4393 4428 4478 4528 4449 4520 4422 4525 4396 4451 4475 4495 4492 4403 4488 4463 4458 4425 4412 4524 4410 4530 4517 4445 4504 4392 4527 4476 4430 4426 4490 4418 4497 4486 4390 4478 4509 4417 4427 4392 4523 4404 4399 4410 4432 4388 4431 4510 4388 4446 4459 4488 4476 4434 4442 4512 4467 4458 4428 4429 4436 4403 4440 4501 4522 4443 4469 4396 4493 4394 4451 4451 4522 4428 4437 4460 4420 4424 4494 4524 4523 4528 4418 4513 4441 4455 4472 4461 4524 4427 4405 4486 4525 4472 4410 4476 4471 4428 4509 4483 4419 4399 4506 4487 4411 4499 4465 4404 4408 4519 4520 4491 4479 4516 4506 4405 4481 4412 4450 4402 4456 4422 4491 4406 4479 4437 4447 4416 4408 4449 4482 4390 4500 4526 4403 4482 4392 4462 4426 4481 4459 4395 4491 4482 4437 4452 4447 4525 4442 4459 4488 4434 4489 4492 4509 4460 4475 4476 4465 4436 4480 4447 4393 4511 4407 4491 4518 4497 4438 4420 4531 4501 4441 4430 4492 4489 4518 4420 4458 4452 4531 4407 4415 4478 4522 4468 4482 4411 4427 4439 4403 4403 4454 4461 4452 4421 4443 4455 4492 4461 4519 4428 4411 4523 4507 4448 4505 4460 4442 4402 4478 4452 4479 4392 4386 4447 4409 4387 4521 4433 4466 4427 4481 4506 4412 4466 4438 4489 4411 4397 4436 4414 4504 4408 4530 4484 4386 4398 4394 4402 4530 4518 4417 4398 4521 4462 4525 4468 4475 4490 4427 4465 4471 4410 4483 4504 4399 4462 4421 4477 4499 4457 4506 4495 4456 4420 4450 4385 4392 4529 4519 4409 4494 4459 4429 4412 4475 4398 4387 4503 4421 4482 4447 4476 4415 4417 4408 4463 4437 4524 4412 4484 4514 4508 4410 4454 4479 4478 4503 4532 4387 4486 4509 4504 4414 4490 4482 4492 4478 4397 4432 4486 4529 4435 4393 4421 4452 4495 4516 4424 4413 4508 4486 4461 4445 4469 4436 4478 4497 4392 4455 4387 4453 4469 4420 4388 4456 4399 4447 4458 4532 4416 4451 4524 4494 4408 4492 4526 4445 4456 4488 4478 4521 4420 4457 4447 4438 4487 4412 4510 4404 4450 4466 4400 4411 4485 4510 4433 4455 4404 4475 4516 4451 4452 4446 4415 4510 4503 4442 4443 4441 4530 4429 4478 4445 4468 4522 4410 4460 4438 4488 4435 4418 4462 4388 4464 4527 4404 4431 4412 4522 4528 4487 4412 4395 4520 4512 4463 4495 4428 4443 4524 4406 4437 4476 4466 4414 4477 4468 4505 4520 4424 4403 4412 4488 4465 4412 4387 4422 4507 4392 4503 4452 4398 4437 4422 4446 4478 4424 4402 4471 4464 4426 4424 4447 4457 4498 4483 4403 4500 4498 4411 4522 4473 4405 4501 4495 4437 4431 4407 4494 4415 4469 4409 4474 4440 4461 4438 4499 4409 4390 4508 4456 4500 4497 4445 4481 4521 4435 4465 4498 4522 4520 4478 4529 4386 4427 4393 4520 4431 4396 4424 4525 4389 4410 4385 4405 4394 4487 4434 4420 4451 4459 4518 4425 4532 4455 4515 4458 4391 4446 4509 4501 4440 4423 4386 4512 4459 4425 4430 4499 4463 4438 4436 4459 4521 4429 4427 4503 4498 4512 4524 4468 4522 4512 4489 4461 4503 4451 75 5188 5199 5200 5191 5202 5194 5194 5201 5203 5202 5199 5186 5197 5187 5195 5185 5198 5196 5205 5204 5198 5185 5196 5206 5192 5185 5189 5195 5196 5187 5194 5199 5190 5203 5188 5186 5203 5201 5202 5194 5200 5191 5199 5190 5194 5201 5203 5202 5186 5201 5190 5194 5193 5203 5201 5191 5194 5188 5190 5202 5190 5193 5201 5200 5188 5199 5191 5203 5188 5202 5201 5194 5199 5201 5202 5186 5188 5194 5199 5190 5186 5203 5188 5191 5199 5186 5191 5201 5203 5193 5198 5196 5206 5192 5185 5197 5199 5200 5193 5194 5191 5188 5206 5204 5195 5187 5189 5185 5189 5187 5185 5196 5206 5204 5193 5202 5199 5186 5188 5191 5204 5206 5196 5205 5189 5185 5195 5205 5192 5198 5206 5197 5193 5199 5188 5191 5203 5186 5201 5191 5190 5200 5194 5188 5202 5191 5200 5193 5203 5190 5192 5204 5197 5187 5196 5206 5206 5192 5187 5185 5197 5195 5202 5199 5194 5203 5200 5186 5201 5202 5200 5190 5186 5193 5190 5188 5203 5191 5200 5186 5188 5193 5186 5201 5194 5200 5203 5201 5202 5186 5199 5191 5199 5200 5190 5186 5202 5193 5186 5201 5199 5190 5203 5200 5203 5194 5191 5200 5199 5193 5186 5199 5202 5194 5188 5191 5204 5192 5195 5205 5189 5197 5201 5199 5188 5186 5191 5194 5194 5202 5200 5188 5201 5186 5194 5199 5202 5190 5193 5188 5199 5202 5200 5201 5194 5203 5199 5188 5202 5190 5186 5201 5201 5203 5194 5190 5202 5191 5193 5186 5200 5194 5202 5191 5191 5200 5186 5193 5190 5202 5206 5205 5196 5204 5192 5187 5185 5187 5195 5205 5204 5196 5204 5195 5192 5187 5198 5185 5193 5194 5202 5200 5201 5199 5200 5194 5199 5203 5191 5202 5199 5188 5194 5193 5201 5190 5198 5197 5196 5189 5187 5205 5192 5185 5196 5187 5198 5197 5200 5203 5194 5193 5191 5186 5188 5186 5199 5193 5194 5202 5192 5206 5198 5185 5189 5187 5201 5193 5203 5186 5200 5188 5199 5201 5193 5200 5203 5191 5198 5206 5204 5192 5197 5187 5203 5188 5200 5199 5201 5193 5201 5200 5188 5203 5194 5202 5205 5196 5187 5198 5192 5195 5195 5198 5197 5192 5196 5189 5203 5200 5199 5201 5193 5202 5205 5206 5198 5195 5196 5189 5199 5200 5186 5194 5188 5193 5205 5198 5197 5206 5204 5185 5190 5191 5193 5201 5200 5194 5194 5203 5193 5190 5201 5202 5191 5201 5199 5202 5190 5186 5205 5192 5204 5187 5206 5195 5190 5194 5202 5191 5203 5188 5189 5192 5185 5196 5197 5195 5204 5185 5187 5198 5205 5189 5201 5188 5194 5200 5203 5199 100 5890 5896 5895 5894 5893 5892 5893 5895 5894 5890 5896 5891 5890 5892 5894 5893 5896 5891 5925 5924 5926 5927 5929 5930 5905 5904 5901 5903 5906 5907 5884 5887 5882 5888 5883 5885 5920 5916 5919 5922 5917 5921 5890 5896 5895 5893 5894 5892 5921 5926 5923 5925 5927 5922 5895 5892 5891 5890 5893 5894 5894 5890 5892 5895 5896 5891 5890 5895 5896 5891 5892 5893 5892 5891 5894 5890 5893 5896 5890 5896 5891 5895 5894 5893 5895 5894 5891 5892 5896 5893 5931 5932 5930 5929 5935 5933 5890 5892 5894 5893 5895 5891 5903 5900 5901 5904 5898 5899 5917 5920 5916 5921 5919 5918 5905 5908 5903 5907 5909 5904 5890 5894 5892 5896 5893 5891 5928 5929 5930 5932 5926 5927 5895 5899 5898 5897 5900 5896 5892 5896 5891 5890 5894 5893 5895 5891 5892 5896 5894 5893 5898 5897 5902 5903 5899 5900 5891 5893 5896 5890 5892 5895 5895 5893 5896 5891 5890 5894 5890 5892 5894 5895 5891 5896 5910 5909 5911 5912 5914 5913 5911 5916 5917 5912 5914 5915 5935 5934 5932 5933 5936 5930 5895 5890 5891 5896 5894 5892 5914 5919 5918 5917 5915 5913 5912 5913 5911 5914 5916 5910 5890 5896 5892 5894 5891 5895 5892 5894 5893 5897 5895 5896 5895 5892 5893 5890 5894 5896 5907 5904 5910 5909 5905 5906 5893 5895 5891 5894 5896 5892 5891 5895 5890 5896 5893 5892 5892 5891 5893 5895 5896 5890 5887 5888 5886 5889 5891 5892 5896 5895 5894 5891 5893 5890 5886 5883 5889 5887 5888 5884 5893 5895 5890 5896 5892 5894 5899 5900 5895 5896 5897 5898 5930 5929 5927 5931 5932 5928 5891 5895 5894 5896 5892 5890 5894 5895 5890 5896 5891 5892 5893 5891 5892 5890 5896 5895 5890 5894 5891 5896 5893 5895 5920 5923 5921 5922 5926 5924 5925 5928 5922 5924 5926 5927 5891 5892 5894 5893 5890 5888 5894 5891 5890 5895 5896 5893 5907 5910 5909 5905 5908 5906 5894 5892 5891 5890 5896 5893 5892 5890 5893 5894 5896 5891 5895 5892 5891 5896 5894 5890 5896 5895 5892 5893 5890 5894 5923 5924 5928 5925 5926 5927 5926 5930 5927 5928 5925 5929 5922 5920 5921 5918 5917 5919 5901 5903 5906 5902 5904 5900 5887 5890 5893 5889 5891 5888 5913 5912 5907 5909 5908 5911 5917 5916 5915 5920 5914 5919 5894 5897 5896 5892 5893 5895 5903 5905 5902 5904 5900 5899 5890 5896 5893 5895 5892 5891 5890 5896 5894 5892 5891 5895 5896 5892 5894 5891 5895 5893 5921 5922 5919 5918 5920 5924 5903 5906 5907 5905 5904 5908 5896 5890 5892 5895 5894 5891 5894 5892 5893 5896 5895 5891 5897 5899 5895 5896 5893 5898 5901 5898 5896 5902 5897 5900 5914 5912 5911 5908 5913 5910 5892 5896 5890 5893 5894 5891 5895 5893 5890 5894 5891 5892 5896 5892 5891 5890 5893 5894 5884 5885 5889 5886 5888 5887 5892 5893 5896 5891 5894 5890 5893 5891 5894 5896 5895 5892 5896 5895 5891 5890 5892 5893 5925 5919 5920 5924 5921 5922 5893 5892 5895 5890 5891 5896 5891 5895 5893 5892 5890 5896 5896 5890 5892 5891 5894 5895 5891 5892 5895 5896 5890 5894 5885 5887 5889 5888 5886 5890 5896 5894 5890 5891 5892 5895 5917 5916 5912 5915 5918 5913 5929 5934 5930 5928 5932 5933 5893 5896 5891 5894 5890 5892 5934 5935 5933 5932 5936 5931 5894 5893 5891 5890 5889 5892 5911 5906 5908 5910 5912 5909 30 144 142 140 141 143 139 148 149 144 147 146 150 144 143 141 142 139 145 143 144 142 140 145 141 142 143 141 145 144 139 144 145 143 142 139 141 144 145 140 139 142 143 140 141 142 138 136 137 141 139 145 142 144 140 142 145 141 139 143 140 145 144 142 140 139 143 139 141 145 144 140 143 144 141 138 142 139 140 135 134 136 133 139 137 145 148 147 144 142 143 143 142 137 140 139 138 140 139 143 141 142 145 144 145 143 140 139 142 140 137 139 141 135 136 143 141 145 142 144 140 141 140 144 139 142 145 149 148 146 145 150 151 145 140 143 144 142 139 141 146 142 143 145 144 134 133 132 138 136 135 146 145 143 147 149 144 140 144 142 139 145 141 137 131 132 134 136 135 141 142 144 139 143 140 137 140 134 138 135 136 99 1321 1301 1306 1218 1228 1278 1302 1322 1253 1219 1184 1241 1227 1201 1325 1185 1198 1307 1235 1227 1261 1231 1290 1296 1191 1209 1187 1198 1261 1247 1268 1276 1264 1195 1287 1286 1311 1230 1194 1244 1241 1269 1316 1204 1303 1196 1252 1234 1314 1263 1186 1308 1228 1241 1283 1230 1224 1331 1201 1315 1277 1210 1256 1205 1249 1280 1308 1320 1208 1233 1252 1212 1226 1322 1222 1199 1232 1303 1281 1218 1276 1304 1286 1252 1231 1210 1211 1277 1325 1323 1186 1233 1305 1235 1291 1223 1306 1328 1291 1279 1242 1329 1288 1265 1310 1216 1200 1277 1242 1184 1273 1270 1190 1202 1201 1289 1234 1199 1244 1230 1211 1196 1270 1198 1225 1221 1188 1296 1227 1291 1309 1202 1330 1218 1306 1195 1221 1208 1233 1291 1315 1268 1186 1265 1267 1189 1226 1274 1223 1232 1251 1212 1286 1223 1254 1314 1299 1239 1202 1261 1211 1232 1289 1293 1274 1215 1314 1279 1297 1213 1307 1247 1194 1266 1315 1224 1220 1254 1298 1307 1204 1234 1184 1258 1195 1319 1320 1255 1258 1227 1193 1274 1238 1217 1306 1288 1324 1239 1223 1259 1330 1263 1250 1234 1240 1203 1190 1198 1325 1228 1213 1243 1328 1237 1212 1250 1281 1190 1203 1293 1298 1268 1276 1325 1323 1192 1267 1277 1284 1295 1204 1238 1259 1224 1281 1287 1251 1270 1302 1255 1283 1288 1221 1227 1327 1292 1210 1226 1308 1296 1203 1254 1231 1187 1318 1293 1206 1255 1320 1216 1331 1257 1228 1305 1230 1219 1221 1222 1288 1248 1237 1294 1247 1203 1184 1223 1189 1282 1303 1284 1204 1320 1195 1280 1298 1240 1244 1268 1318 1281 1295 1202 1321 1203 1291 1331 1197 1206 1285 1227 1192 1262 1206 1267 1318 1255 1200 1307 1261 1295 1268 1209 1279 1207 1213 1250 1262 1203 1287 1210 1298 1302 1321 1199 1294 1276 1319 1226 1291 1258 1286 1188 1221 1301 1299 1295 1304 1309 1258 1220 1187 1231 1203 1265 1289 1244 1255 1272 1298 1315 1291 1309 1209 1293 1240 1231 1274 1296 1226 1310 1198 1188 1228 1199 1278 1324 1230 1269 1284 1262 1271 1306 1293 1203 1196 1329 1207 1237 1297 1272 1199 1282 1217 1261 1331 1197 1295 1237 1254 1238 1193 1272 1239 1235 1270 1315 1288 1197 1296 1200 1204 1280 1229 1323 1226 1212 1281 1264 1305 1300 1203 1230 1184 1264 1279 1315 1224 1317 1272 1281 1241 1292 1216 1283 1223 1301 1261 1185 1323 1194 1231 1326 1317 1215 1282 1292 1304 1192 1186 1210 1282 1311 1277 1218 1262 1197 1243 1229 1248 1234 1192 1323 1189 1316 1310 1197 1219 1284 1205 1318 1300 1236 1261 1299 1274 1194 1276 1317 1268 1200 1269 1233 1230 1315 1287 1252 1300 1202 1307 1289 1184 1212 1272 1266 1279 1283 1294 1307 1273 1326 1203 1202 1302 1242 1319 1204 1230 1278 1262 1195 1223 1302 1314 1240 1210 1247 1212 1245 1306 1316 1195 1265 1261 1277 1201 1218 1264 1197 1239 1288 1218 1285 1191 1190 1226 1218 1292 1185 1228 1185 1301 1291 1230 1208 1240 1252 1226 1278 1271 1267 1219 1240 1248 1223 1275 1197 1318 1320 1314 1328 1219 1292 1281 1197 1243 1240 1256 1301 1279 1327 1271 1328 1275 1246 1243 1238 1225 1250 1260 1230 1205 1242 1265 1230 1235 1281 1205 1251 1279 1230 1301 1256 1201 1231 1319 1193 1188 1203 1312 1205 1288 1275 1251 1262 7 9620 9623 9621 9619 9624 9622 9621 9620 9622 9624 9623 9619 9622 9620 9619 9624 9621 9623 9624 9623 9621 9619 9620 9622 9619 9622 9620 9624 9621 9623 9619 9621 9623 9622 9620 9624 9623 9620 9621 9624 9622 9619 1 9219 9217 9218 9216 9214 9215 100 1865 1864 1879 1875 1882 1874 1877 1881 1878 1873 1866 1870 1879 1865 1876 1864 1869 1874 1874 1864 1865 1882 1867 1869 1869 1865 1867 1875 1864 1874 1880 1871 1877 1870 1873 1868 1868 1866 1870 1872 1881 1871 1864 1869 1876 1879 1874 1865 1878 1880 1877 1871 1881 1872 1881 1866 1877 1880 1878 1871 1873 1881 1878 1871 1868 1877 1869 1874 1879 1865 1867 1876 1881 1873 1866 1877 1880 1868 1878 1868 1870 1871 1866 1877 1864 1865 1875 1882 1876 1867 1881 1870 1880 1878 1872 1873 1871 1868 1870 1881 1880 1873 1865 1864 1875 1869 1882 1876 1872 1881 1880 1870 1868 1873 1878 1866 1872 1877 1870 1868 1882 1874 1879 1869 1875 1876 1882 1869 1879 1874 1875 1867 1870 1873 1877 1866 1880 1881 1864 1865 1882 1876 1874 1867 1870 1881 1873 1878 1866 1880 1875 1869 1865 1867 1874 1879 1867 1865 1882 1874 1864 1875 1874 1875 1864 1865 1867 1882 1865 1879 1867 1874 1876 1882 1870 1880 1866 1873 1872 1881 1878 1880 1868 1871 1870 1873 1875 1865 1876 1874 1864 1869 1876 1874 1875 1879 1882 1869 1872 1880 1871 1870 1877 1868 1879 1876 1882 1875 1865 1869 1865 1879 1867 1876 1874 1882 1874 1882 1865 1864 1875 1876 1879 1867 1882 1864 1865 1876 1882 1876 1864 1874 1879 1867 1864 1875 1867 1879 1865 1882 1873 1880 1872 1870 1868 1881 1882 1879 1869 1876 1865 1864 1870 1871 1873 1881 1872 1880 1872 1870 1880 1873 1881 1866 1864 1865 1875 1867 1869 1874 1870 1880 1873 1866 1872 1878 1871 1880 1877 1866 1873 1878 1880 1866 1868 1870 1873 1877 1868 1878 1881 1866 1871 1880 1865 1875 1864 1867 1876 1874 1864 1874 1867 1879 1869 1876 1881 1880 1877 1873 1866 1871 1864 1879 1869 1875 1867 1882 1875 1874 1876 1867 1864 1882 1871 1873 1866 1878 1868 1872 1868 1870 1872 1873 1878 1866 1866 1872 1871 1877 1881 1873 1864 1876 1882 1879 1865 1867 1879 1874 1875 1876 1867 1869 1872 1870 1868 1878 1873 1880 1879 1867 1874 1882 1864 1876 1879 1865 1876 1867 1864 1875 1877 1880 1872 1878 1868 1881 1868 1866 1870 1872 1881 1878 1873 1880 1871 1881 1868 1872 1866 1881 1880 1872 1868 1870 1867 1879 1864 1876 1875 1865 1864 1879 1865 1875 1876 1869 1873 1871 1878 1870 1881 1866 1866 1868 1881 1872 1870 1878 1874 1865 1864 1875 1867 1876 1870 1866 1872 1881 1878 1873 1865 1876 1864 1875 1879 1867 1880 1878 1870 1877 1881 1873 1868 1881 1870 1877 1872 1880 1877 1868 1873 1872 1870 1878 1865 1876 1875 1869 1874 1867 1869 1874 1875 1876 1865 1882 1865 1874 1867 1876 1869 1864 1882 1867 1869 1874 1876 1865 1864 1865 1869 1882 1874 1867 1869 1876 1874 1882 1875 1867 1879 1865 1869 1875 1867 1874 1874 1865 1875 1867 1864 1882 1866 1873 1871 1881 1870 1868 1880 1866 1870 1877 1871 1873 1882 1876 1867 1869 1875 1874 1873 1871 1866 1872 1877 1870 1878 1881 1872 1873 1880 1866 1866 1870 1880 1877 1881 1868 1867 1882 1876 1865 1875 1874 1877 1872 1866 1881 1870 1873 1879 1876 1874 1867 1882 1864 1873 1871 1877 1868 1878 1866 1872 1878 1871 1877 1868 1880 1869 1876 1865 1875 1864 1879 1872 1866 1873 1878 1881 1871 1865 1882 1879 1867 1876 1874 1872 1868 1877 1880 1866 1878 1871 1872 1877 1881 1880 1866 60 5523 5532 5528 5530 5531 5524 5523 5532 5527 5528 5524 5531 5531 5523 5528 5532 5530 5524 5524 5523 5531 5528 5527 5532 5527 5532 5530 5524 5531 5523 5525 5521 5529 5522 5526 5520 5522 5529 5521 5533 5526 5525 5526 5521 5529 5522 5525 5533 5531 5532 5527 5523 5528 5530 5523 5524 5531 5528 5530 5532 5526 5525 5521 5533 5522 5529 5525 5526 5533 5520 5529 5521 5530 5532 5523 5527 5531 5524 5520 5533 5526 5521 5522 5529 5526 5521 5525 5533 5522 5529 5530 5532 5523 5524 5528 5527 5526 5520 5529 5521 5525 5522 5523 5532 5531 5528 5530 5527 5531 5532 5527 5530 5523 5524 5528 5523 5527 5531 5530 5532 5523 5532 5524 5527 5528 5530 5527 5523 5528 5524 5530 5532 5526 5533 5522 5525 5520 5521 5528 5530 5532 5527 5531 5523 5525 5529 5526 5533 5520 5521 5532 5527 5531 5528 5530 5524 5530 5524 5527 5532 5531 5523 5531 5528 5524 5527 5523 5530 5527 5531 5524 5530 5528 5532 5520 5526 5533 5521 5525 5529 5528 5532 5524 5530 5523 5527 5530 5523 5527 5532 5531 5528 5523 5530 5527 5532 5531 5524 5523 5531 5530 5524 5527 5528 5521 5525 5533 5526 5520 5529 5523 5532 5528 5527 5524 5531 5526 5525 5520 5522 5533 5529 5533 5521 5520 5522 5529 5526 5527 5528 5524 5531 5523 5530 5520 5521 5525 5522 5533 5526 5528 5523 5530 5531 5527 5524 5533 5521 5526 5522 5525 5520 5520 5522 5533 5521 5526 5529 5527 5528 5531 5523 5530 5532 5531 5528 5527 5530 5532 5523 5530 5532 5527 5523 5528 5524 5531 5528 5527 5524 5523 5530 5530 5524 5532 5531 5523 5527 5521 5525 5526 5520 5533 5522 5528 5524 5527 5531 5532 5523 5530 5527 5523 5531 5524 5532 5531 5523 5532 5524 5528 5530 5528 5531 5523 5530 5524 5527 5524 5527 5532 5528 5530 5531 5527 5530 5532 5523 5524 5528 5525 5522 5521 5526 5529 5520 5527 5523 5530 5528 5524 5532 5529 5521 5526 5525 5520 5522 5523 5528 5531 5532 5524 5530 5524 5528 5527 5531 5523 5532 10 6552 6553 6557 6551 6555 6558 6561 6566 6565 6560 6564 6563 6559 6562 6561 6560 6563 6564 6564 6566 6561 6567 6560 6565 6560 6555 6562 6554 6557 6558 6563 6559 6561 6562 6557 6560 6557 6560 6556 6558 6554 6561 6562 6564 6563 6558 6557 6559 6554 6555 6557 6552 6553 6559 6563 6556 6562 6559 6561 6557 10 7974 7973 7970 7968 7975 7971 7961 7962 7963 7966 7960 7968 7971 7968 7973 7970 7976 7975 7976 7971 7970 7974 7972 7969 7970 7973 7969 7976 7971 7968 7966 7965 7963 7968 7962 7964 7965 7964 7967 7962 7960 7966 7975 7974 7972 7973 7969 7968 7963 7967 7966 7965 7964 7969 7965 7960 7964 7966 7963 7959 60 5020 5030 5029 5034 5023 5031 5022 5026 5024 5028 5032 5033 5025 5027 5033 5016 5024 5032 5026 5024 5016 5025 5033 5028 5025 5033 5032 5022 5027 5024 5031 5017 5034 5018 5023 5029 5022 5025 5028 5027 5024 5026 5018 5020 5023 5019 5034 5030 5024 5032 5022 5026 5028 5027 5018 5017 5030 5021 5020 5029 5020 5017 5029 5034 5023 5021 5028 5027 5024 5026 5033 5032 5030 5031 5020 5019 5017 5034 5026 5033 5032 5028 5025 5016 5024 5032 5025 5028 5022 5027 5023 5031 5019 5020 5030 5017 5034 5030 5017 5020 5018 5023 5034 5031 5029 5030 5018 5020 5027 5016 5028 5022 5033 5025 5031 5029 5030 5020 5017 5023 5017 5019 5021 5031 5020 5029 5026 5025 5032 5033 5022 5027 5023 5029 5020 5034 5031 5021 5019 5023 5020 5034 5030 5017 5025 5024 5022 5032 5033 5028 5019 5018 5030 5034 5029 5023 5018 5020 5029 5023 5017 5021 5024 5028 5033 5032 5022 5026 5033 5025 5026 5022 5027 5024 5020 5017 5019 5034 5021 5030 5017 5019 5018 5021 5020 5034 5018 5023 5020 5019 5031 5034 5022 5027 5025 5032 5024 5028 5022 5025 5016 5028 5026 5032 5025 5032 5022 5033 5016 5026 5025 5027 5028 5022 5033 5032 5026 5016 5032 5027 5028 5024 5030 5020 5023 5019 5031 5018 5023 5030 5018 5029 5021 5031 5030 5020 5021 5034 5019 5031 5029 5021 5030 5017 5018 5034 5024 5016 5028 5026 5022 5027 5022 5024 5025 5026 5033 5027 5032 5022 5028 5024 5033 5025 5021 5031 5034 5017 5030 5018 5025 5024 5033 5026 5027 5016 5033 5025 5016 5026 5022 5027 5023 5030 5020 5019 5031 5017 5022 5033 5024 5027 5032 5026 5033 5032 5016 5022 5028 5026 5030 5029 5031 5023 5018 5021 5020 5029 5030 5021 5018 5031 5031 5020 5017 5021 5029 5030 5029 5034 5018 5020 5019 5021 5027 5033 5025 5024 5016 5028 5030 5018 5019 5034 5029 5017 5026 5033 5024 5025 5022 5027 5027 5026 5032 5016 5024 5033 5016 5028 5026 5032 5027 5033 5023 5030 5029 5018 5020 5034 10 1465 1460 1463 1462 1458 1457 1460 1464 1469 1470 1461 1465 1480 1479 1477 1474 1469 1475 1470 1476 1478 1469 1477 1472 1467 1459 1463 1469 1464 1466 1459 1461 1457 1463 1462 1466 1473 1476 1478 1477 1475 1479 1470 1480 1477 1471 1472 1479 1468 1466 1463 1465 1459 1461 1479 1474 1476 1478 1472 1473 30 6954 6945 6946 6950 6949 6947 6947 6950 6952 6945 6949 6948 6950 6947 6948 6955 6945 6953 6949 6954 6948 6951 6947 6952 6947 6955 6952 6948 6945 6954 6951 6946 6949 6947 6945 6954 6947 6946 6954 6951 6950 6948 6945 6951 6946 6949 6953 6947 6953 6954 6947 6952 6950 6955 6951 6950 6947 6949 6952 6954 6952 6949 6948 6953 6947 6945 6955 6951 6949 6953 6950 6954 6950 6949 6955 6947 6948 6945 6952 6945 6951 6946 6948 6949 6947 6955 6952 6950 6945 6954 6945 6953 6955 6951 6949 6946 6947 6950 6949 6953 6954 6945 6953 6954 6952 6955 6951 6947 6953 6947 6945 6948 6951 6950 6951 6954 6953 6950 6955 6952 6954 6949 6945 6953 6952 6955 6948 6955 6952 6953 6947 6950 6953 6948 6950 6949 6952 6947 6948 6951 6953 6954 6947 6950 6948 6945 6951 6952 6950 6949 6950 6954 6952 6947 6953 6946 6948 6954 6949 6945 6952 6946 6952 6946 6945 6948 6950 6954 6952 6945 6951 6954 6946 6955 6949 6945 6953 6955 6950 6946 100 3359 3361 3360 3364 3363 3362 3340 3336 3338 3337 3339 3335 3386 3390 3391 3388 3387 3389 3390 3387 3391 3388 3389 3392 3366 3363 3368 3367 3364 3365 3316 3318 3321 3317 3320 3319 3323 3321 3325 3320 3322 3324 3347 3350 3348 3345 3349 3346 3408 3404 3407 3403 3405 3406 3360 3356 3357 3359 3361 3358 3312 3311 3316 3313 3314 3315 3346 3344 3348 3343 3347 3345 3407 3409 3411 3406 3408 3410 3372 3376 3375 3373 3377 3374 3352 3355 3356 3354 3353 3351 3358 3354 3357 3355 3356 3359 3379 3378 3375 3380 3377 3376 3400 3396 3401 3397 3398 3399 3329 3331 3326 3328 3330 3327 3383 3384 3382 3386 3387 3385 3328 3332 3330 3331 3329 3333 3378 3381 3379 3382 3380 3377 3353 3354 3356 3355 3358 3357 3361 3357 3359 3360 3358 3362 3357 3356 3359 3358 3355 3360 3335 3337 3336 3334 3339 3338 3374 3371 3373 3375 3372 3376 3393 3392 3390 3391 3394 3389 3380 3379 3378 3377 3376 3381 3395 3393 3397 3394 3392 3396 3355 3354 3352 3357 3353 3356 3396 3395 3398 3397 3394 3399 3370 3373 3374 3371 3372 3369 3405 3406 3403 3401 3404 3402 3406 3407 3404 3402 3403 3405 3310 3312 3314 3315 3313 3311 3362 3361 3365 3364 3363 3360 3381 3383 3380 3382 3384 3379 3343 3344 3339 3341 3342 3340 3320 3319 3317 3318 3322 3321 3393 3391 3395 3390 3394 3392 3326 3324 3325 3327 3322 3323 3382 3383 3380 3378 3381 3379 3346 3345 3347 3349 3344 3348 3349 3351 3353 3354 3352 3350 3315 3317 3318 3316 3319 3314 3369 3371 3370 3366 3368 3367 3362 3364 3367 3365 3363 3366 3331 3334 3332 3329 3333 3330 3390 3389 3387 3386 3385 3388 3412 3413 3408 3411 3409 3410 3314 3316 3318 3317 3315 3313 3340 3344 3341 3342 3343 3345 3331 3335 3334 3336 3333 3332 3338 3343 3342 3339 3340 3341 3352 3353 3349 3350 3351 3348 3373 3371 3368 3370 3369 3372 3370 3369 3372 3371 3367 3368 3366 3365 3368 3367 3370 3369 3342 3347 3343 3344 3346 3345 3373 3378 3375 3377 3376 3374 3374 3376 3377 3378 3375 3379 3336 3335 3333 3334 3337 3332 3333 3335 3331 3332 3330 3334 3401 3403 3400 3399 3402 3404 3411 3409 3407 3412 3410 3408 3368 3366 3367 3364 3369 3365 3364 3363 3365 3362 3366 3361 3403 3398 3401 3400 3402 3399 3325 3327 3324 3328 3323 3326 3388 3392 3391 3390 3389 3393 3341 3337 3339 3336 3338 3340 3395 3397 3394 3393 3396 3398 3336 3335 3337 3338 3333 3334 3386 3384 3383 3382 3385 3381 3402 3400 3397 3401 3398 3399 3343 3342 3345 3341 3346 3344 3384 3387 3389 3388 3386 3385 3312 3317 3313 3315 3316 3314 3407 3404 3409 3405 3406 3408 3323 3326 3321 3324 3322 3325 3406 3407 3409 3405 3408 3410 3402 3401 3405 3400 3404 3403 3373 3374 3371 3375 3372 3370 3325 3328 3326 3330 3329 3327 3380 3382 3383 3384 3381 3385 3385 3386 3387 3388 3384 3383 3320 3322 3321 3323 3318 3319 3350 3351 3347 3349 3346 3348 3347 3351 3349 3350 3352 3348 3321 3319 3320 3323 3324 3322 3328 3329 3327 3330 3332 3331 3363 3359 3360 3358 3362 3361 3339 3340 3338 3337 3341 3342 3318 3316 3315 3317 3320 3319 3392 3396 3393 3391 3395 3394 3411 3414 3410 3413 3412 3409 3351 3354 3352 3350 3353 3355 3328 3325 3324 3327 3326 3329 3395 3397 3396 3399 3398 3400 10 7743 7741 7740 7738 7737 7736 7744 7740 7747 7746 7739 7736 7747 7740 7746 7741 7744 7742 7737 7739 7738 7729 7732 7735 7741 7737 7740 7747 7744 7745 7738 7739 7741 7732 7736 7737 7736 7739 7733 7740 7741 7734 7738 7735 7746 7739 7743 7741 7739 7741 7740 7742 7733 7735 7740 7733 7742 7732 7736 7739 30 8126 8128 8129 8123 8130 8127 8115 8122 8114 8118 8117 8116 8120 8116 8119 8118 8114 8121 8123 8127 8128 8131 8130 8124 8122 8120 8123 8125 8118 8121 8123 8125 8124 8131 8129 8127 8123 8129 8124 8131 8125 8130 8124 8127 8128 8130 8125 8123 8123 8127 8126 8125 8124 8129 8127 8131 8126 8125 8123 8129 8124 8128 8127 8125 8131 8123 8122 8124 8116 8117 8118 8123 8129 8130 8125 8124 8131 8128 8123 8121 8122 8116 8117 8119 8129 8131 8125 8124 8128 8126 8122 8120 8119 8125 8121 8118 8126 8131 8130 8125 8129 8123 8127 8126 8123 8131 8129 8128 8129 8135 8131 8133 8128 8130 8133 8126 8132 8129 8134 8130 8125 8124 8127 8128 8126 8122 8121 8119 8123 8125 8122 8124 8131 8130 8127 8125 8123 8128 8128 8124 8125 8127 8123 8130 8126 8131 8127 8129 8128 8124 8131 8124 8129 8127 8128 8125 8124 8129 8131 8132 8128 8125 8126 8123 8128 8125 8127 8129 8132 8131 8125 8127 8128 8130 8127 8123 8124 8130 8125 8129 100 6404 6398 6407 6402 6401 6408 6478 6468 6470 6477 6469 6471 6410 6416 6413 6414 6411 6415 6432 6431 6427 6430 6433 6436 6386 6388 6394 6387 6384 6391 6461 6457 6458 6453 6460 6459 6392 6395 6401 6394 6393 6400 6414 6417 6422 6416 6420 6413 6387 6382 6386 6384 6379 6385 6402 6410 6404 6409 6403 6411 6472 6468 6475 6465 6466 6471 6434 6429 6438 6431 6436 6428 6394 6399 6396 6398 6397 6395 6455 6464 6456 6458 6459 6457 6443 6438 6433 6442 6441 6440 6478 6472 6469 6479 6477 6470 6433 6426 6428 6427 6430 6429 6414 6407 6405 6412 6410 6413 6425 6432 6433 6428 6426 6430 6416 6409 6413 6412 6418 6414 6407 6405 6400 6408 6410 6406 6469 6464 6470 6472 6465 6463 6416 6415 6418 6417 6411 6412 6470 6465 6461 6464 6460 6466 6389 6391 6394 6392 6393 6386 6477 6467 6472 6468 6473 6470 6390 6393 6397 6389 6392 6398 6431 6430 6426 6425 6427 6432 6417 6427 6422 6420 6418 6424 6479 6480 6478 6477 6470 6474 6433 6437 6431 6438 6434 6439 6454 6453 6451 6450 6445 6448 6448 6456 6450 6451 6455 6457 6450 6445 6446 6455 6447 6454 6446 6450 6453 6447 6451 6443 6458 6463 6460 6459 6464 6456 6466 6462 6471 6464 6465 6461 6413 6406 6411 6407 6415 6410 6418 6412 6414 6415 6421 6411 6463 6467 6461 6462 6460 6464 6466 6461 6457 6458 6459 6462 6381 6379 6386 6389 6385 6388 6446 6443 6444 6447 6448 6449 6428 6426 6435 6433 6431 6429 6425 6428 6419 6426 6420 6418 6440 6438 6442 6444 6439 6437 6477 6480 6473 6481 6475 6478 6460 6458 6461 6453 6457 6454 6388 6392 6395 6386 6393 6385 6471 6472 6474 6476 6478 6475 6439 6443 6440 6448 6444 6445 6393 6396 6402 6399 6395 6400 6455 6460 6451 6450 6452 6453 6440 6439 6446 6438 6436 6441 6463 6468 6462 6458 6467 6460 6386 6384 6383 6388 6387 6381 6429 6439 6435 6437 6436 6432 6442 6435 6434 6441 6436 6437 6415 6420 6416 6424 6421 6422 6389 6390 6383 6393 6392 6385 6394 6397 6392 6399 6393 6398 6423 6433 6424 6432 6431 6425 6411 6410 6409 6408 6414 6412 6444 6445 6443 6439 6440 6442 6476 6486 6482 6477 6483 6485 6410 6409 6408 6403 6405 6404 6400 6398 6405 6401 6397 6402 6407 6402 6404 6403 6409 6400 6408 6405 6411 6403 6413 6409 6483 6474 6482 6477 6476 6481 6451 6456 6448 6455 6446 6449 6480 6475 6478 6477 6484 6479 6484 6474 6477 6478 6483 6479 6442 6447 6437 6446 6445 6443 6402 6395 6401 6404 6397 6398 6406 6405 6414 6412 6407 6410 6433 6439 6432 6436 6435 6438 6473 6472 6471 6464 6467 6465 6417 6416 6418 6421 6423 6414 6397 6404 6403 6399 6400 6401 6387 6392 6386 6391 6383 6389 6475 6476 6473 6467 6472 6470 6419 6428 6421 6427 6426 6420 6397 6392 6391 6398 6394 6389 6452 6446 6450 6449 6444 6442 6452 6451 6457 6453 6454 6456 6390 6380 6381 6384 6386 6385 6428 6422 6425 6420 6430 6421 6415 6414 6419 6416 6420 6424 6417 6416 6420 6418 6426 6423 6400 6394 6397 6393 6395 6402 6459 6461 6451 6456 6453 6455 6454 6452 6455 6449 6458 6450 6388 6397 6391 6396 6389 6387 6484 6479 6483 6478 6481 6482 6446 6450 6441 6444 6442 6448 6470 6468 6467 6469 6471 6466 6457 6464 6459 6458 6462 6463 6442 6445 6449 6448 6447 6451 6422 6425 6429 6427 6421 6424 100 9356 9355 9354 9358 9352 9353 9353 9354 9358 9356 9357 9355 9352 9356 9357 9354 9355 9353 9355 9357 9358 9352 9354 9356 9356 9352 9355 9357 9358 9353 9354 9352 9358 9355 9356 9353 9357 9356 9353 9358 9352 9355 9357 9356 9354 9352 9353 9358 9353 9356 9352 9357 9355 9354 9356 9357 9353 9352 9355 9358 9352 9358 9357 9356 9355 9354 9355 9358 9353 9356 9352 9354 9357 9355 9358 9354 9353 9356 9357 9352 9358 9355 9354 9356 9357 9353 9354 9355 9358 9356 9356 9357 9352 9358 9353 9355 9353 9358 9352 9354 9355 9357 9357 9354 9355 9356 9352 9358 9357 9358 9356 9353 9355 9354 9354 9353 9356 9352 9358 9355 9352 9356 9358 9357 9353 9354 9356 9357 9355 9354 9353 9352 9358 9352 9353 9357 9356 9354 9356 9354 9357 9352 9358 9355 9353 9354 9358 9352 9355 9357 9352 9357 9355 9358 9356 9353 9354 9356 9352 9355 9353 9358 9357 9356 9352 9353 9358 9354 9352 9356 9353 9354 9357 9358 9356 9357 9355 9354 9352 9358 9356 9354 9353 9358 9357 9352 9354 9353 9356 9355 9358 9352 9355 9353 9354 9356 9358 9352 9357 9353 9358 9355 9354 9352 9352 9354 9358 9353 9357 9355 9356 9358 9354 9352 9353 9357 9353 9352 9355 9357 9354 9356 9357 9358 9355 9356 9354 9353 9356 9354 9353 9358 9352 9355 9357 9355 9352 9358 9353 9354 9357 9352 9354 9358 9355 9353 9355 9358 9357 9352 9354 9353 9355 9352 9358 9354 9353 9357 9352 9355 9353 9354 9357 9358 9357 9356 9352 9355 9354 9353 9354 9352 9358 9356 9355 9357 9358 9352 9355 9357 9354 9353 9356 9353 9355 9352 9358 9357 9354 9352 9356 9358 9353 9355 9352 9354 9356 9358 9353 9355 9352 9355 9356 9357 9353 9358 9355 9354 9357 9358 9353 9352 9358 9352 9353 9355 9357 9356 9353 9352 9356 9357 9354 9358 9358 9356 9355 9357 9353 9352 9357 9353 9354 9358 9356 9355 9356 9352 9358 9354 9353 9355 9357 9358 9352 9356 9355 9353 9358 9352 9355 9357 9353 9356 9353 9357 9355 9352 9354 9358 9358 9357 9354 9356 9353 9355 9352 9356 9354 9358 9357 9355 9358 9353 9354 9352 9357 9356 9353 9355 9357 9352 9354 9358 9355 9358 9353 9356 9352 9357 9358 9353 9356 9355 9352 9357 9354 9357 9352 9353 9355 9356 9352 9353 9356 9354 9357 9355 9357 9356 9353 9355 9352 9354 9352 9358 9353 9355 9356 9354 9352 9353 9355 9358 9354 9356 9353 9354 9352 9357 9358 9356 9356 9353 9355 9358 9354 9352 9355 9354 9352 9356 9358 9353 9353 9357 9355 9356 9358 9354 9353 9354 9356 9355 9358 9357 9352 9354 9358 9357 9353 9356 9354 9356 9358 9353 9352 9357 9357 9355 9352 9353 9358 9356 9355 9352 9357 9356 9358 9354 9353 9354 9358 9355 9356 9357 9358 9354 9355 9352 9353 9357 9358 9353 9354 9352 9355 9356 9352 9354 9357 9356 9358 9353 9358 9357 9353 9356 9354 9352 9356 9358 9355 9352 9354 9353 9357 9354 9355 9356 9352 9353 9356 9355 9358 9354 9353 9352 9355 9357 9352 9356 9354 9358 9358 9355 9356 9354 9357 9353 9358 9357 9354 9352 9353 9356 9353 9352 9355 9358 9356 9357 9355 9354 9353 9357 9358 9352 9354 9357 9358 9355 9353 9352 9352 9353 9357 9354 9356 9355 9352 9358 9356 9354 9357 9355 9353 9357 9356 9355 9354 9358 9356 9357 9353 9352 9358 9355 9352 9357 9353 9358 9355 9354 9356 9357 9355 9352 9358 9354 10 1478 1475 1481 1477 1479 1480 1477 1478 1481 1479 1480 1476 1479 1478 1476 1481 1475 1480 1479 1477 1481 1475 1476 1478 1475 1480 1476 1478 1477 1481 1476 1475 1477 1478 1480 1479 1479 1480 1476 1477 1478 1481 1478 1475 1479 1477 1476 1480 1477 1480 1478 1476 1475 1479 1475 1479 1480 1478 1476 1481 60 5860 5866 5868 5864 5857 5856 5859 5862 5870 5869 5865 5861 5857 5858 5866 5864 5856 5868 5860 5864 5856 5857 5858 5863 5868 5866 5863 5864 5857 5860 5866 5856 5857 5863 5858 5864 5862 5867 5870 5859 5869 5865 5863 5857 5864 5860 5858 5868 5863 5866 5857 5858 5856 5864 5870 5865 5859 5862 5861 5867 5861 5859 5869 5865 5870 5862 5861 5862 5870 5865 5859 5869 5857 5856 5858 5860 5863 5866 5865 5859 5869 5861 5870 5867 5866 5856 5857 5868 5863 5858 5869 5867 5862 5859 5870 5861 5856 5866 5864 5863 5858 5860 5865 5870 5859 5861 5867 5869 5856 5858 5857 5860 5864 5863 5862 5870 5865 5859 5869 5861 5859 5862 5861 5869 5870 5865 5859 5861 5865 5870 5862 5869 5865 5869 5862 5867 5870 5859 5868 5857 5866 5856 5863 5860 5866 5863 5864 5868 5857 5856 5869 5859 5862 5867 5865 5861 5867 5861 5869 5865 5862 5870 5864 5863 5868 5866 5856 5860 5862 5869 5859 5865 5870 5867 5860 5868 5858 5866 5864 5857 5864 5868 5858 5860 5866 5856 5869 5859 5870 5862 5865 5861 5857 5856 5860 5868 5863 5864 5862 5867 5859 5870 5865 5861 5858 5868 5863 5866 5864 5856 5870 5865 5867 5862 5869 5861 5857 5856 5866 5860 5864 5863 5864 5856 5860 5863 5858 5868 5864 5858 5866 5856 5857 5863 5869 5865 5870 5861 5859 5867 5858 5860 5863 5857 5864 5856 5869 5870 5867 5862 5859 5861 5863 5866 5857 5860 5858 5856 5857 5864 5863 5856 5858 5868 5867 5869 5862 5859 5870 5865 5869 5859 5870 5862 5861 5865 5863 5868 5864 5858 5856 5857 5858 5864 5863 5857 5856 5860 5867 5862 5861 5859 5869 5870 5857 5858 5860 5856 5864 5866 5856 5857 5866 5858 5864 5863 5856 5868 5858 5857 5864 5866 5857 5866 5858 5856 5864 5868 5862 5861 5869 5865 5867 5870 5862 5867 5865 5861 5859 5869 5859 5869 5867 5865 5862 5870 5862 5865 5867 5869 5861 5859 5861 5867 5869 5859 5862 5865 5859 5867 5861 5862 5865 5870 5869 5865 5870 5867 5861 5859 75 9913 9908 9901 9916 9920 9918 9918 9911 9913 9904 9906 9917 9900 9903 9921 9914 9922 9899 9902 9914 9910 9905 9922 9921 9908 9915 9916 9911 9906 9920 9902 9900 9899 9903 9914 9919 9905 9899 9907 9921 9903 9919 9900 9902 9922 9899 9914 9907 9920 9912 9908 9916 9906 9901 9918 9911 9908 9920 9913 9912 9913 9901 9911 9917 9916 9906 9905 9903 9900 9910 9921 9907 9904 9908 9916 9913 9920 9912 9899 9910 9907 9909 9900 9921 9913 9911 9901 9912 9915 9908 9912 9913 9916 9920 9901 9904 9902 9907 9914 9905 9909 9903 9911 9901 9917 9915 9904 9913 9916 9913 9920 9912 9911 9915 9917 9904 9918 9901 9913 9911 9912 9920 9915 9917 9901 9918 9908 9920 9906 9901 9904 9916 9913 9918 9901 9904 9916 9912 9899 9907 9921 9922 9900 9914 9914 9899 9919 9909 9907 9910 9912 9917 9906 9920 9908 9904 9917 9918 9904 9901 9913 9912 9904 9908 9912 9915 9901 9911 9906 9918 9912 9913 9920 9911 9912 9916 9917 9911 9918 9913 9920 9916 9918 9913 9901 9917 9911 9917 9915 9918 9901 9912 9905 9922 9900 9910 9919 9914 9907 9910 9902 9909 9903 9921 9912 9908 9906 9920 9911 9918 9919 9921 9900 9899 9907 9903 9914 9899 9909 9921 9922 9910 9909 9899 9907 9905 9922 9902 9904 9908 9918 9912 9913 9920 9915 9917 9911 9916 9908 9904 9902 9907 9903 9905 9910 9919 9908 9901 9911 9915 9917 9916 9903 9905 9922 9899 9919 9914 9903 9905 9909 9899 9902 9921 9917 9912 9920 9918 9908 9915 9906 9915 9901 9911 9917 9912 9905 9910 9900 9899 9919 9909 9915 9911 9912 9918 9908 9916 9906 9904 9917 9912 9915 9908 9905 9909 9902 9919 9922 9903 9910 9899 9902 9921 9905 9922 9916 9901 9913 9911 9915 9908 9920 9918 9917 9901 9912 9915 9899 9902 9922 9914 9921 9905 9920 9904 9917 9912 9915 9911 9915 9913 9916 9912 9908 9918 9913 9915 9904 9918 9912 9911 9915 9901 9911 9913 9912 9918 9904 9906 9920 9908 9911 9901 9918 9913 9904 9911 9920 9912 9911 9920 9904 9918 9908 9913 9908 9913 9916 9920 9915 9912 9913 9917 9918 9906 9912 9901 9908 9920 9918 9917 9901 9912 9917 9911 9908 9915 9912 9913 9904 9912 9917 9920 9918 9911 9906 9912 9908 9911 9918 9917 9921 9903 9902 9914 9899 9910 9901 9920 9908 9916 9912 9906 9899 9903 9905 9902 9921 9914 9912 9908 9917 9911 9913 9920 9916 9911 9904 9920 9918 9908 9912 9913 9920 9901 9908 9916 9916 9904 9911 9915 9908 9901 9902 9914 9919 9910 9900 9903 30 2405 2410 2407 2406 2408 2409 2407 2409 2405 2408 2410 2412 2408 2411 2409 2413 2403 2414 2407 2403 2412 2413 2411 2409 2403 2411 2410 2404 2413 2414 2414 2406 2403 2408 2410 2411 2404 2401 2396 2397 2407 2403 2410 2406 2412 2411 2414 2407 2408 2412 2405 2413 2411 2410 2404 2408 2414 2405 2407 2409 2403 2413 2411 2404 2408 2414 2410 2404 2403 2408 2412 2414 2395 2394 2392 2402 2401 2400 2398 2395 2391 2390 2396 2394 2404 2411 2409 2414 2407 2406 2405 2406 2403 2407 2410 2399 2398 2399 2395 2400 2405 2397 2414 2406 2410 2404 2408 2407 2412 2411 2414 2405 2407 2413 2410 2406 2412 2405 2413 2414 2409 2414 2406 2405 2407 2403 2413 2414 2406 2404 2409 2415 2403 2409 2411 2404 2407 2406 2403 2395 2398 2393 2399 2404 2409 2404 2402 2408 2400 2401 2403 2408 2406 2400 2409 2402 2402 2403 2396 2395 2401 2397 2399 2394 2397 2401 2402 2395 2405 2410 2402 2412 2409 2404 2405 2407 2403 2404 2408 2402 100 5154 5164 5234 5160 5202 5236 5240 5272 5271 5256 5225 5266 5184 5179 5234 5207 5154 5195 5199 5179 5205 5188 5250 5184 5135 5162 5203 5139 5242 5251 5137 5185 5208 5268 5152 5212 5165 5253 5162 5223 5251 5188 5161 5271 5192 5247 5208 5152 5225 5210 5166 5186 5257 5233 5256 5165 5271 5145 5215 5157 5136 5210 5235 5147 5152 5175 5134 5136 5264 5272 5217 5198 5169 5254 5214 5185 5275 5217 5252 5169 5208 5253 5228 5269 5193 5174 5267 5167 5208 5222 5259 5225 5252 5190 5129 5203 5199 5177 5140 5231 5225 5146 5227 5134 5245 5161 5145 5192 5149 5230 5154 5134 5241 5162 5253 5130 5227 5202 5259 5197 5194 5254 5147 5166 5237 5162 5179 5242 5204 5227 5138 5199 5230 5248 5250 5225 5168 5204 5209 5220 5156 5207 5240 5158 5132 5226 5247 5184 5154 5164 5250 5195 5231 5236 5253 5239 5177 5207 5217 5209 5172 5199 5132 5204 5165 5191 5170 5136 5152 5188 5248 5277 5219 5269 5200 5191 5158 5250 5240 5129 5216 5158 5180 5135 5211 5191 5178 5253 5241 5140 5162 5227 5259 5192 5203 5255 5179 5174 5157 5220 5137 5184 5266 5259 5209 5274 5170 5182 5175 5268 5187 5256 5225 5229 5238 5203 5232 5247 5212 5262 5204 5131 5249 5266 5231 5271 5219 5269 5149 5237 5202 5265 5245 5165 5142 5170 5141 5264 5267 5223 5193 5188 5152 5224 5247 5234 5160 5196 5269 5134 5145 5184 5254 5180 5147 5240 5218 5175 5176 5145 5200 5265 5254 5166 5153 5254 5236 5155 5269 5165 5188 5182 5271 5266 5161 5195 5180 5265 5179 5187 5236 5157 5175 5241 5159 5145 5148 5227 5130 5226 5259 5218 5154 5207 5277 5268 5139 5186 5225 5228 5140 5259 5154 5179 5186 5196 5211 5146 5188 5222 5228 5144 5193 5177 5134 5164 5264 5234 5161 5148 5247 5248 5212 5258 5227 5212 5205 5199 5195 5273 5158 5216 5226 5230 5167 5228 5176 5263 5244 5257 5192 5211 5256 5182 5185 5266 5216 5241 5165 5219 5153 5156 5187 5271 5257 5232 5181 5202 5184 5161 5128 5187 5223 5169 5156 5196 5130 5141 5147 5148 5207 5244 5225 5172 5143 5224 5151 5210 5182 5192 5260 5217 5256 5168 5143 5170 5262 5261 5157 5216 5222 5136 5218 5220 5148 5144 5175 5211 5131 5243 5213 5258 5214 5250 5228 5213 5226 5225 5236 5174 5154 5187 5208 5181 5192 5179 5163 5196 5185 5155 5150 5248 5221 5143 5202 5276 5189 5205 5210 5273 5255 5263 5134 5234 5266 5231 5153 5277 5262 5221 5182 5184 5180 5149 5149 5204 5156 5227 5154 5185 5202 5176 5177 5194 5275 5173 5217 5277 5212 5207 5225 5150 5136 5253 5213 5242 5172 5202 5253 5232 5185 5243 5172 5266 5219 5217 5180 5255 5247 5216 5169 5191 5241 5156 5205 5242 5154 5268 5172 5180 5148 5275 5194 5167 5210 5249 5277 5141 5248 5154 5130 5206 5184 5153 5152 5154 5144 5211 5182 5155 5224 5144 5205 5207 5149 5186 5160 5170 5227 5182 5178 5196 5180 5148 5202 5147 5185 5263 5199 5268 5162 5260 5240 5205 5161 5213 5186 5232 5225 5128 5178 5253 5187 5204 5266 5137 5165 5203 5233 5167 5232 5265 5189 5137 5268 5142 5185 5154 5200 5191 5207 5180 5252 5142 5255 5256 5244 5148 5260 5131 5196 5162 5193 5233 5262 5231 5135 5195 5213 5164 5194 5189 5156 5139 5176 5244 5221 5140 5154 5145 5196 5187 5144 5148 5132 5217 5174 5192 5146 5147 99 879 935 905 880 896 998 894 877 884 922 941 959 999 882 996 980 962 907 883 919 1020 970 1008 888 932 1019 877 892 959 972 990 930 962 916 1007 891 960 965 1006 915 937 898 1008 960 970 917 921 930 879 963 926 893 975 937 956 946 959 1003 927 983 929 996 924 992 885 932 948 990 1002 1019 913 885 955 1005 885 894 926 941 1011 890 916 1000 972 921 981 973 984 911 909 879 1002 942 892 932 979 1019 918 965 933 1014 910 986 880 918 1012 916 905 936 964 967 960 938 951 1008 991 955 1013 990 933 893 962 1021 911 881 913 932 992 910 889 914 919 949 897 1022 940 931 878 893 1015 895 904 961 932 1005 993 896 992 947 982 980 942 905 935 952 988 973 1014 902 885 980 984 921 1018 935 976 1005 881 895 996 903 889 877 894 991 963 950 938 1001 904 919 998 990 1006 904 950 981 964 989 948 897 944 980 936 921 883 998 1011 917 1007 978 971 993 989 932 1010 919 894 903 964 975 877 946 894 890 935 969 879 972 936 960 918 930 1000 938 999 976 982 972 893 901 1003 944 990 904 929 880 988 947 977 987 964 949 926 1019 910 966 1006 917 970 1008 944 991 983 976 966 941 960 968 1021 921 965 953 1008 898 956 987 894 1020 878 924 925 880 982 885 996 1012 880 1004 902 885 985 916 990 980 989 965 992 895 986 898 954 973 918 983 1022 1012 970 1009 900 908 1016 890 971 920 911 993 923 917 914 994 905 1002 1005 1009 897 970 954 956 941 878 912 977 926 910 954 976 925 910 966 905 919 953 959 934 1002 946 883 996 884 890 916 1010 977 1010 959 946 875 905 930 900 995 971 981 992 1022 896 918 955 941 1003 988 938 985 912 1017 885 994 1016 1015 979 988 933 925 946 924 995 1010 880 887 934 894 924 930 992 958 933 984 943 978 992 898 900 941 908 944 943 943 945 905 939 966 875 907 967 908 956 881 957 1000 986 907 887 1011 952 971 914 975 905 983 987 921 962 956 944 1016 960 1018 964 892 928 886 881 879 918 1015 1000 875 985 970 965 978 973 902 975 955 949 922 947 909 957 1021 969 906 937 896 898 1009 943 981 906 946 897 922 944 896 892 948 1006 960 898 918 921 953 996 927 955 911 945 900 912 1020 901 943 888 907 967 1018 996 889 944 880 965 954 946 899 1022 996 894 976 945 1019 1013 996 875 1019 885 925 915 977 960 1020 894 925 913 970 891 922 999 890 1015 997 970 1015 950 967 891 893 961 898 945 907 947 993 1009 1015 932 907 955 889 962 914 976 992 935 892 936 917 942 922 969 893 989 975 889 898 1001 1003 875 890 932 995 900 881 893 937 879 985 990 900 886 995 1016 993 884 977 932 936 1006 882 977 952 927 1008 927 890 956 896 997 1004 910 908 955 959 1000 99 5592 5633 5593 5700 5674 5627 5633 5617 5710 5608 5678 5581 5599 5593 5674 5691 5613 5594 5722 5665 5716 5624 5657 5632 5659 5716 5655 5704 5627 5641 5713 5646 5580 5629 5665 5700 5664 5670 5597 5666 5674 5669 5636 5654 5610 5606 5603 5621 5636 5655 5586 5637 5687 5590 5704 5618 5659 5715 5699 5692 5592 5652 5591 5696 5693 5703 5590 5611 5626 5662 5657 5628 5586 5683 5658 5679 5702 5690 5710 5597 5705 5653 5587 5659 5681 5587 5705 5682 5640 5718 5655 5597 5664 5647 5615 5594 5593 5711 5687 5580 5719 5602 5594 5713 5609 5642 5718 5614 5628 5607 5604 5590 5612 5594 5691 5591 5610 5607 5642 5626 5662 5615 5639 5686 5626 5694 5604 5705 5715 5691 5636 5587 5620 5588 5656 5638 5697 5703 5687 5586 5661 5667 5617 5702 5712 5656 5708 5588 5590 5586 5611 5684 5584 5703 5585 5580 5613 5619 5695 5646 5590 5611 5696 5635 5596 5677 5602 5649 5599 5661 5670 5580 5680 5714 5658 5672 5710 5703 5649 5582 5676 5651 5672 5621 5718 5593 5705 5709 5671 5708 5689 5668 5720 5613 5679 5686 5656 5701 5585 5683 5706 5614 5605 5610 5720 5689 5679 5665 5703 5622 5671 5663 5686 5682 5586 5606 5587 5637 5585 5645 5703 5692 5705 5715 5630 5605 5644 5601 5581 5589 5692 5706 5653 5582 5658 5593 5581 5650 5690 5655 5691 5708 5699 5671 5590 5672 5616 5698 5647 5712 5651 5673 5695 5594 5630 5655 5679 5702 5619 5713 5653 5692 5642 5592 5715 5685 5671 5673 5701 5661 5639 5717 5678 5578 5710 5675 5622 5614 5712 5656 5687 5710 5612 5622 5587 5604 5623 5651 5647 5674 5696 5660 5717 5677 5665 5579 5686 5645 5636 5608 5605 5621 5613 5660 5676 5692 5650 5643 5639 5607 5592 5599 5590 5706 5593 5665 5657 5688 5658 5719 5582 5641 5677 5648 5583 5679 5686 5689 5614 5626 5592 5690 5643 5703 5617 5667 5663 5684 5681 5578 5600 5693 5664 5642 5640 5703 5675 5704 5665 5662 5603 5600 5643 5704 5604 5687 5593 5623 5634 5640 5621 5656 5627 5647 5603 5588 5641 5683 5634 5696 5593 5619 5665 5622 5672 5614 5676 5655 5634 5648 5602 5671 5717 5647 5666 5633 5690 5697 5613 5581 5626 5679 5661 5688 5629 5618 5580 5640 5604 5678 5629 5631 5589 5580 5647 5682 5644 5630 5642 5690 5707 5597 5590 5704 5647 5703 5628 5592 5607 5671 5713 5589 5575 5648 5591 5718 5664 5585 5595 5710 5669 5641 5630 5611 5663 5631 5706 5686 5621 5622 5703 5590 5645 5702 5688 5674 5722 5655 5619 5676 5595 5709 5704 5630 5671 5648 5649 5694 5585 5584 5717 5721 5673 5632 5616 5609 5636 5602 5709 5632 5634 5621 5636 5627 5687 5623 5659 5598 5714 5618 5707 5611 5713 5683 5671 5677 5633 5606 5605 5607 5660 5649 5575 5641 5715 5646 5599 5654 5608 5660 5674 5607 5640 5693 5609 5710 5721 5658 5578 5691 5599 5638 5707 5702 5644 5656 5685 5722 5581 5657 5667 5627 5695 5681 5637 5594 5720 5614 5609 5637 5649 5628 5633 5620 5686 5691 5579 5690 5623 5678 5618 5684 5614 5605 5629 5676 5596 5598 5582 5649 5591 5586 5589 5712 5608 5699 5701 5607 5661 5670 5673 5628 5665 5722 5624 5665 5611 5706 5629 5588 5672 5578 5696 5580 5648 5577 5607 5628 5601 5595 5597 5706 5598 5661 5644 5676 5722 5698 5694 5609 5717 5710 5677 5680 30 9822 9817 9820 9818 9819 9821 9826 9821 9825 9823 9824 9822 9839 9834 9836 9838 9837 9835 9820 9821 9824 9823 9825 9822 9831 9827 9829 9826 9830 9828 9836 9840 9837 9838 9839 9835 9815 9814 9813 9818 9817 9816 9841 9839 9837 9842 9840 9838 9832 9827 9829 9828 9830 9831 9816 9814 9813 9817 9812 9815 9811 9814 9816 9812 9815 9813 9834 9833 9830 9835 9832 9831 9826 9827 9824 9825 9822 9823 9828 9826 9827 9825 9829 9824 9830 9825 9826 9827 9828 9829 9813 9812 9814 9810 9811 9809 9824 9828 9827 9825 9823 9826 9830 9829 9833 9834 9832 9831 9828 9830 9832 9831 9833 9829 9822 9823 9820 9819 9821 9818 9833 9836 9835 9834 9832 9831 9836 9840 9838 9837 9839 9841 9812 9811 9809 9808 9810 9813 9814 9810 9813 9812 9815 9811 9837 9836 9832 9834 9835 9833 9820 9818 9815 9816 9819 9817 9816 9817 9814 9819 9818 9815 9822 9821 9824 9823 9820 9819 9816 9820 9821 9818 9817 9819 9834 9836 9833 9835 9838 9837 45 8452 8458 8445 8444 8450 8443 8456 8439 8447 8441 8442 8455 8458 8440 8459 8444 8460 8453 8439 8446 8442 8454 8449 8456 8444 8445 8459 8440 8450 8458 8445 8450 8443 8457 8444 8459 8451 8441 8454 8439 8448 8446 8443 8453 8444 8460 8458 8450 8459 8450 8445 8458 8440 8460 8445 8453 8457 8460 8450 8444 8444 8460 8453 8452 8443 8445 8460 8452 8443 8444 8445 8453 8445 8459 8453 8450 8460 8440 8443 8457 8458 8445 8440 8459 8458 8457 8453 8444 8440 8445 8440 8444 8460 8450 8453 8445 8457 8445 8444 8450 8440 8460 8453 8459 8450 8443 8458 8460 8459 8457 8453 8458 8450 8452 8453 8440 8458 8457 8445 8459 8456 8454 8439 8448 8451 8455 8457 8459 8443 8453 8460 8444 8459 8444 8452 8450 8440 8460 8459 8445 8443 8444 8458 8457 8456 8449 8439 8455 8442 8448 8450 8443 8458 8460 8459 8445 8441 8446 8449 8448 8439 8454 8457 8453 8460 8443 8445 8452 8454 8446 8456 8447 8449 8439 8452 8459 8453 8440 8445 8444 8441 8455 8454 8448 8439 8456 8449 8447 8454 8451 8455 8446 8439 8446 8455 8456 8451 8454 8450 8459 8458 8444 8457 8453 8452 8440 8444 8457 8445 8453 8455 8447 8448 8446 8454 8441 8458 8452 8444 8445 8453 8459 8446 8454 8448 8456 8442 8441 8459 8457 8452 8460 8453 8440 8454 8447 8451 8456 8439 8455 8444 8440 8460 8445 8457 8450 8454 8439 8455 8442 8456 8448 8450 8459 8443 8452 8440 8457 8447 8456 8451 8454 8439 8446 8458 8460 8443 8459 8444 8445 98 4050 4028 4041 4083 4022 4039 3989 4064 3987 4057 4017 4011 4016 3997 4058 4053 4066 4117 4083 4053 4054 4070 4030 4065 4077 4011 4041 4122 4128 4065 4002 4053 3989 4130 4066 4045 4115 4087 4007 4014 4079 4091 4107 4088 4045 4093 3996 4035 4010 3989 4071 4059 4006 4099 4113 4095 4027 4028 4100 4060 4111 4000 4052 4048 4075 4083 4011 4124 3991 4009 4037 4003 4028 4004 4112 4062 4007 3988 4032 4086 4081 4011 4118 4046 4099 4043 4071 4031 4085 4029 4082 4057 4020 4005 3985 3993 4129 4101 4040 4125 4126 4097 3995 4113 4072 4007 4104 3998 3998 4057 4108 4026 4027 4058 4107 4098 4084 4052 4073 4041 4117 4129 4119 4113 4069 4124 4067 4024 4071 3988 4069 4065 4010 4127 4112 4087 4094 4088 4084 4124 4101 4072 4047 4051 4043 4098 4087 4110 4022 4103 4042 4086 4035 3994 4091 4009 3990 4011 4129 4063 3992 4060 4059 4000 4026 3994 4009 3988 4104 4004 4095 3986 4054 4109 4047 4060 4079 4057 4073 3987 4049 4066 4112 4077 3989 4110 4066 4065 4036 4112 4087 3997 4028 4072 4119 4126 4114 4019 4003 4006 3990 4128 4029 4119 4042 4021 4052 4067 4008 4126 4054 3998 4058 4017 4101 4068 4129 4052 4108 4065 4126 4022 4118 4087 4022 4076 4109 3987 4089 4026 4075 4050 4061 4104 4009 4128 4092 4038 4114 4110 4004 4109 4032 4000 4035 4038 4104 4066 4043 4111 4021 4026 4121 4034 4005 4045 4118 4119 4097 4038 4113 4093 4122 4075 4088 4102 4015 4116 4123 4095 4078 4032 4002 4051 4009 4129 4058 4020 4121 4122 4047 4115 4108 4035 4131 4115 4032 3997 4022 4124 4013 4056 4010 4116 4063 4016 4079 4117 4067 4033 4115 4099 4038 4064 3998 4080 4080 4016 4100 4004 4041 4008 4110 4122 3997 4007 4074 4127 4130 4028 4032 4000 4009 4033 4037 4000 4041 4039 4094 4057 4067 4088 3991 4061 4099 4054 4083 4069 4058 4111 4017 4074 4016 4089 3989 4025 4087 4110 4100 4057 4050 4001 4009 4086 4092 4073 4117 4049 4122 4128 4013 4131 4073 4111 4102 4117 4018 4049 4103 4042 3992 4131 4010 4075 4002 4116 4012 4109 3996 4034 4108 4089 4016 4093 4046 4102 4116 4101 4091 4038 4060 4002 4036 4069 4089 4106 3995 4102 4043 3996 4059 4103 4047 4120 4095 4093 4081 4100 4023 4093 4039 4045 4099 4086 4013 4054 3985 4050 4051 4083 4053 4122 4002 3999 4032 4080 4101 4122 4077 4002 4108 4031 4058 4045 3997 4042 4117 4051 4030 4010 4000 4045 4070 4044 4039 4098 4059 4028 3985 4067 4128 4032 4040 4065 4090 4004 4017 4043 4066 4023 4124 4055 4068 4076 4102 4116 4120 3989 4054 4073 4068 4102 3995 3998 4009 4127 4010 4097 4070 4081 4075 4038 4004 4068 4120 4000 4018 4046 4005 4017 4065 3992 4126 4076 4050 4029 4047 4005 4071 4085 4090 4098 4103 4027 4043 4112 4122 4021 4010 4130 4038 4065 4099 4000 4056 4130 4064 4002 4085 3996 4074 4081 4096 4085 4063 3991 4032 4023 4104 4128 4087 4020 4054 4044 4054 4081 4027 4059 4112 4005 4030 3994 4089 4052 4024 4021 4033 3997 4074 4099 4094 4021 4063 3986 4101 3998 4064 3987 4045 4014 4094 4080 3992 4002 4077 4053 3996 4089 4125 4119 4095 4103 4038 3998 4092 4083 4118 4001 4053 3991 3992 4027 4072 4063 4040 4044 4032 4021 3 5288 5292 5287 5291 5290 5289 5292 5291 5287 5289 5288 5290 5296 5299 5297 5298 5295 5294 99 7527 7521 7585 7556 7567 7571 7547 7534 7523 7541 7565 7491 7553 7599 7535 7555 7591 7509 7556 7570 7562 7519 7507 7471 7506 7501 7587 7556 7472 7518 7550 7504 7558 7477 7537 7555 7535 7596 7505 7484 7590 7577 7606 7523 7581 7477 7577 7566 7561 7485 7578 7483 7528 7510 7594 7612 7516 7475 7573 7480 7533 7547 7566 7572 7542 7562 7507 7477 7609 7574 7527 7592 7477 7514 7605 7498 7469 7598 7582 7532 7589 7587 7536 7514 7525 7577 7561 7543 7488 7570 7584 7592 7600 7507 7612 7549 7482 7518 7550 7589 7551 7495 7535 7538 7513 7517 7530 7598 7528 7569 7593 7563 7567 7545 7538 7545 7573 7477 7483 7478 7571 7513 7531 7557 7601 7467 7605 7558 7600 7513 7534 7546 7579 7553 7473 7491 7572 7522 7526 7609 7594 7548 7504 7478 7533 7497 7526 7542 7545 7475 7480 7475 7536 7511 7532 7509 7500 7515 7505 7569 7550 7495 7607 7491 7592 7545 7471 7481 7486 7575 7475 7596 7554 7606 7531 7580 7487 7548 7519 7515 7489 7546 7526 7510 7470 7552 7536 7552 7575 7586 7502 7569 7587 7482 7469 7466 7498 7560 7485 7568 7596 7498 7532 7587 7518 7611 7593 7563 7490 7512 7555 7520 7561 7579 7544 7509 7514 7489 7609 7502 7591 7554 7565 7607 7581 7466 7485 7569 7605 7473 7531 7518 7511 7556 7494 7581 7522 7503 7493 7547 7534 7549 7608 7587 7507 7476 7493 7597 7526 7507 7495 7494 7544 7508 7515 7505 7483 7520 7505 7522 7545 7529 7588 7536 7595 7531 7478 7559 7517 7573 7602 7559 7550 7582 7600 7556 7588 7479 7587 7486 7598 7480 7544 7564 7572 7542 7596 7606 7496 7557 7538 7520 7588 7555 7534 7498 7592 7577 7597 7561 7509 7568 7480 7530 7524 7586 7537 7528 7591 7532 7592 7487 7493 7485 7557 7607 7605 7591 7508 7589 7549 7469 7466 7577 7484 7495 7515 7589 7552 7570 7542 7503 7478 7496 7531 7599 7511 7544 7569 7552 7532 7563 7598 7544 7529 7595 7547 7487 7471 7584 7521 7530 7568 7578 7528 7598 7557 7518 7603 7471 7573 7519 7475 7542 7556 7479 7506 7574 7488 7510 7611 7587 7516 7480 7523 7488 7604 7512 7551 7466 7547 7527 7490 7485 7605 7510 7508 7544 7500 7546 7523 7499 7552 7520 7564 7524 7508 7529 7552 7571 7480 7516 7544 7465 7571 7518 7598 7493 7502 7540 7507 7546 7539 7586 7506 7491 7528 7532 7466 7544 7485 7508 7555 7519 7582 7480 7483 7604 7471 7515 7601 7549 7524 7580 7465 7567 7596 7521 7574 7547 7603 7511 7541 7505 7491 7544 7487 7468 7550 7570 7484 7530 7499 7569 7487 7527 7594 7497 7483 7479 7563 7517 7493 7512 7582 7574 7515 7590 7528 7537 7567 7588 7472 7538 7596 7552 7538 7511 7489 7591 7566 7486 7471 7610 7512 7479 7562 7537 7605 7493 7601 7514 7487 7473 7514 7477 7573 7478 7516 7574 7590 7607 7554 7524 7558 7465 7475 7575 7470 7531 7494 7569 7600 7527 7568 7532 7471 7572 7573 7574 7508 7547 7550 7523 7505 7589 7520 7466 7582 7602 7548 7510 7603 7512 7590 7546 7611 7523 7530 7556 7597 7484 7502 7585 7539 7540 7582 7591 7584 7589 7588 7497 7550 7558 7584 7559 7523 7522 7485 7489 7508 7539 7536 7604 7552 7467 7544 7521 7510 7539 7513 7470 7491 7594 7522 7490 7558 7540 7565 7584 7511 7501 7549 7506 7540 7554 7471 7609 7486 7603 7588 7487 7517 7581 3 5648 5647 5651 5650 5646 5649 5871 5872 5874 5873 5875 5876 5874 5873 5872 5875 5871 5876 100 9580 9577 9578 9586 9587 9589 9587 9581 9580 9578 9598 9589 9594 9582 9584 9583 9592 9588 9590 9589 9591 9580 9586 9577 9580 9586 9589 9581 9578 9597 9582 9588 9585 9584 9593 9592 9577 9578 9591 9581 9589 9580 9589 9591 9586 9590 9597 9581 9585 9592 9588 9583 9593 9595 9581 9589 9591 9597 9596 9578 9586 9577 9591 9597 9590 9596 9586 9596 9578 9581 9597 9589 9596 9598 9597 9580 9590 9581 9595 9584 9594 9592 9583 9579 9577 9587 9596 9578 9590 9586 9578 9580 9590 9596 9586 9577 9577 9578 9590 9586 9591 9597 9579 9595 9592 9588 9582 9584 9586 9581 9587 9590 9577 9597 9586 9590 9580 9591 9598 9589 9582 9599 9585 9588 9593 9594 9596 9589 9580 9577 9590 9597 9593 9599 9595 9582 9579 9594 9596 9580 9591 9598 9590 9586 9592 9579 9582 9584 9583 9599 9590 9597 9589 9577 9591 9598 9585 9595 9593 9584 9579 9588 9597 9590 9591 9596 9578 9587 9584 9595 9579 9588 9592 9585 9577 9578 9596 9590 9597 9587 9596 9586 9598 9590 9580 9577 9584 9599 9588 9594 9579 9583 9584 9579 9599 9588 9594 9585 9597 9577 9586 9591 9578 9596 9580 9586 9596 9577 9590 9597 9579 9595 9582 9588 9584 9592 9598 9590 9577 9578 9589 9581 9588 9595 9583 9599 9594 9593 9577 9578 9587 9586 9590 9598 9577 9591 9590 9589 9581 9580 9579 9592 9595 9588 9584 9594 9599 9583 9588 9582 9595 9593 9598 9580 9589 9590 9587 9578 9583 9594 9595 9579 9585 9582 9586 9597 9578 9591 9596 9598 9578 9587 9591 9598 9586 9581 9586 9598 9591 9587 9596 9580 9584 9594 9585 9588 9595 9592 9584 9579 9592 9595 9594 9583 9585 9584 9588 9594 9579 9595 9588 9594 9584 9585 9582 9595 9587 9589 9598 9590 9581 9577 9578 9598 9581 9587 9586 9580 9593 9592 9582 9588 9579 9584 9597 9591 9587 9586 9598 9578 9581 9578 9589 9597 9586 9591 9587 9597 9596 9590 9591 9580 9584 9593 9595 9592 9588 9599 9593 9584 9582 9594 9595 9585 9579 9592 9582 9588 9595 9599 9577 9597 9590 9578 9591 9587 9593 9594 9584 9588 9592 9585 9584 9582 9593 9588 9595 9594 9577 9598 9586 9590 9578 9587 9582 9584 9599 9594 9588 9592 9579 9585 9595 9592 9584 9582 9586 9591 9580 9587 9589 9596 9594 9599 9595 9582 9593 9583 9583 9588 9592 9585 9594 9595 9577 9586 9580 9587 9598 9591 9597 9591 9581 9580 9598 9578 9599 9594 9582 9585 9579 9583 9592 9595 9584 9579 9585 9594 9583 9579 9592 9599 9595 9582 9592 9595 9593 9582 9583 9585 9583 9599 9593 9582 9579 9594 9577 9587 9598 9581 9597 9580 9584 9594 9585 9583 9595 9582 9578 9586 9590 9591 9597 9581 9599 9582 9588 9584 9585 9593 9584 9593 9592 9595 9594 9579 9597 9596 9598 9577 9590 9587 9588 9585 9579 9599 9593 9592 9580 9598 9591 9597 9577 9581 9593 9592 9599 9583 9579 9582 9595 9588 9583 9585 9592 9579 9598 9596 9589 9590 9597 9586 9591 9590 9587 9598 9581 9597 9588 9585 9594 9584 9579 9583 9596 9589 9597 9591 9590 9580 9593 9595 9583 9588 9579 9585 9592 9579 9599 9585 9584 9583 9592 9599 9594 9585 9593 9588 9592 9582 9583 9595 9588 9594 9580 9596 9590 9577 9581 9586 9591 9581 9596 9577 9590 9586 9593 9579 9582 9595 9599 9585 9577 9591 9597 9589 9578 9586 9595 9579 9584 9588 9583 9592 9582 9593 9592 9585 9579 9584 30 444 450 449 445 447 446 446 448 451 449 445 450 466 467 463 468 465 462 458 463 462 459 460 461 466 460 462 464 463 465 446 449 452 448 450 447 455 458 457 456 460 461 463 461 467 464 465 462 453 455 457 452 458 456 467 466 464 469 465 468 455 453 452 456 451 450 456 458 459 453 457 454 469 466 468 465 467 464 473 474 469 472 468 470 445 443 448 449 444 447 468 470 472 469 467 471 471 473 476 472 474 470 461 459 465 463 460 464 456 459 455 458 454 460 445 442 441 443 444 446 464 463 462 461 458 460 450 449 451 453 452 448 467 473 470 471 472 468 465 471 467 466 469 468 452 454 451 453 455 456 445 443 442 446 444 447 449 454 448 453 452 451 460 458 457 462 459 461 451 450 452 454 455 449 471 472 473 474 470 469 30 3311 3314 3309 3308 3313 3310 3310 3314 3308 3313 3312 3311 3314 3312 3309 3310 3313 3311 3310 3313 3312 3308 3311 3309 3308 3309 3310 3313 3314 3312 3314 3309 3311 3313 3308 3312 3311 3310 3314 3312 3313 3308 3310 3314 3308 3311 3313 3312 3310 3311 3312 3308 3314 3309 3313 3308 3314 3309 3310 3312 3312 3314 3311 3309 3308 3310 3312 3310 3308 3309 3313 3314 3309 3312 3311 3308 3313 3314 3311 3310 3309 3312 3314 3308 3311 3308 3312 3313 3309 3310 3314 3310 3309 3311 3313 3308 3311 3310 3314 3309 3313 3308 3312 3309 3311 3314 3310 3313 3312 3308 3314 3311 3310 3309 3311 3312 3314 3310 3308 3313 3310 3308 3312 3309 3311 3313 3313 3311 3314 3310 3308 3309 3309 3312 3310 3311 3314 3313 3313 3311 3314 3310 3308 3309 3314 3312 3311 3310 3309 3308 3314 3313 3312 3311 3310 3308 3309 3308 3311 3312 3310 3314 3314 3312 3309 3311 3313 3308 3313 3311 3309 3312 3314 3308 3313 3314 3310 3308 3312 3309 100 5089 5090 5087 5086 5088 5092 5086 5085 5093 5090 5092 5089 5090 5087 5093 5092 5091 5095 5085 5086 5090 5094 5087 5088 5088 5089 5095 5092 5086 5085 5088 5090 5087 5086 5091 5085 5095 5094 5088 5087 5091 5092 5095 5086 5085 5092 5088 5094 5092 5095 5091 5089 5093 5087 5095 5092 5089 5087 5091 5094 5090 5085 5093 5091 5094 5086 5086 5091 5089 5090 5092 5093 5093 5087 5092 5086 5089 5090 5087 5089 5090 5086 5094 5091 5091 5093 5088 5094 5089 5085 5086 5092 5088 5093 5089 5087 5093 5090 5087 5088 5094 5095 5094 5093 5086 5091 5087 5089 5090 5095 5085 5092 5094 5093 5088 5095 5090 5086 5092 5093 5094 5091 5088 5095 5090 5089 5094 5095 5085 5092 5090 5088 5092 5094 5087 5095 5089 5090 5091 5086 5088 5095 5087 5089 5088 5094 5086 5091 5090 5085 5085 5095 5086 5090 5088 5091 5094 5088 5085 5087 5095 5086 5085 5094 5090 5095 5087 5092 5094 5085 5087 5089 5093 5095 5088 5089 5090 5091 5095 5093 5092 5087 5089 5091 5085 5094 5089 5093 5087 5090 5094 5085 5092 5085 5086 5089 5087 5090 5092 5094 5091 5085 5087 5093 5086 5090 5093 5085 5087 5095 5087 5094 5093 5089 5090 5086 5087 5090 5092 5088 5086 5089 5091 5095 5088 5094 5093 5087 5091 5088 5089 5092 5094 5086 5092 5090 5094 5095 5087 5088 5093 5095 5094 5085 5087 5086 5086 5091 5093 5089 5094 5092 5090 5087 5095 5085 5088 5094 5088 5092 5087 5093 5090 5095 5091 5093 5094 5095 5092 5088 5094 5095 5089 5086 5087 5091 5091 5092 5095 5085 5094 5088 5088 5090 5093 5089 5095 5092 5086 5089 5087 5095 5090 5085 5090 5088 5086 5095 5093 5094 5094 5093 5085 5088 5087 5091 5088 5089 5087 5085 5091 5086 5091 5088 5093 5085 5089 5090 5088 5087 5095 5092 5093 5090 5088 5093 5086 5090 5095 5094 5091 5093 5088 5092 5094 5087 5094 5085 5090 5091 5086 5087 5087 5088 5085 5094 5089 5091 5085 5091 5086 5095 5089 5094 5095 5093 5092 5089 5091 5094 5089 5095 5086 5087 5092 5094 5095 5094 5092 5088 5091 5093 5086 5091 5090 5085 5093 5095 5088 5089 5093 5095 5087 5094 5086 5088 5091 5089 5092 5087 5087 5090 5091 5095 5089 5086 5094 5091 5086 5089 5093 5092 5093 5086 5087 5092 5094 5095 5090 5087 5089 5085 5095 5092 5087 5093 5092 5091 5088 5094 5090 5088 5087 5094 5092 5091 5095 5091 5086 5085 5092 5087 5090 5095 5094 5087 5092 5085 5091 5085 5086 5093 5092 5095 5089 5085 5086 5088 5087 5093 5091 5090 5089 5087 5093 5094 5094 5086 5085 5089 5087 5091 5093 5090 5088 5094 5095 5085 5095 5087 5088 5091 5092 5086 5085 5094 5092 5088 5089 5086 5090 5091 5089 5093 5087 5092 5089 5090 5094 5091 5085 5092 5093 5092 5085 5088 5089 5087 5094 5085 5095 5088 5090 5087 5095 5089 5086 5085 5090 5088 5094 5089 5091 5095 5090 5085 5094 5093 5089 5087 5085 5086 5093 5091 5088 5087 5090 5095 5087 5086 5093 5085 5090 5092 5092 5086 5093 5085 5088 5091 5095 5089 5085 5090 5092 5091 5091 5092 5095 5093 5094 5088 5085 5092 5095 5088 5086 5089 5094 5091 5090 5087 5093 5089 5093 5091 5090 5086 5095 5094 5087 5088 5091 5092 5089 5095 5086 5087 5090 5094 5091 5095 5088 5095 5087 5094 5089 5090 5093 5085 5090 5087 5092 5088 5087 5090 5094 5088 5089 5086 1 400000 600000 1 200000 1000000 800000 30 3654 3653 3658 3657 3655 3656 3655 3658 3654 3653 3656 3657 3655 3657 3656 3658 3654 3653 3658 3656 3654 3653 3657 3655 3657 3659 3655 3656 3658 3654 3655 3652 3653 3650 3654 3651 3660 3658 3659 3661 3662 3657 3656 3654 3658 3655 3653 3657 3653 3656 3654 3655 3658 3657 3659 3656 3658 3660 3657 3655 3659 3661 3656 3660 3657 3658 3653 3658 3655 3654 3657 3656 3656 3655 3657 3654 3653 3658 3649 3648 3651 3652 3653 3650 3653 3655 3658 3657 3656 3654 3660 3663 3659 3662 3664 3661 3663 3658 3661 3659 3660 3662 3656 3657 3653 3654 3652 3655 3655 3654 3658 3653 3657 3656 3656 3653 3654 3658 3655 3657 3657 3654 3653 3656 3658 3655 3655 3656 3654 3653 3657 3658 3655 3656 3653 3658 3657 3654 3656 3658 3653 3657 3654 3655 3658 3654 3656 3655 3657 3653 3651 3652 3654 3649 3653 3650 3655 3656 3652 3654 3653 3651 3664 3665 3660 3661 3663 3662 3647 3648 3649 3650 3646 3651 3648 3649 3650 3652 3651 3647 75 2271 2264 2262 2269 2263 2268 2269 2271 2262 2263 2268 2272 2265 2270 2266 2273 2274 2275 2265 2270 2273 2266 2275 2267 2263 2262 2268 2269 2264 2271 2263 2269 2272 2264 2271 2262 2270 2266 2273 2274 2265 2275 2263 2271 2268 2264 2269 2272 2271 2269 2268 2263 2264 2262 2263 2269 2262 2268 2272 2271 2263 2262 2272 2269 2268 2271 2269 2271 2268 2264 2272 2262 2269 2268 2262 2271 2263 2272 2266 2267 2270 2273 2265 2274 2274 2275 2265 2270 2267 2273 2268 2269 2272 2264 2263 2262 2269 2264 2262 2272 2268 2263 2262 2272 2271 2268 2263 2269 2263 2268 2264 2262 2269 2271 2265 2267 2273 2266 2275 2270 2264 2269 2262 2263 2271 2272 2274 2266 2270 2267 2273 2265 2269 2262 2263 2271 2264 2268 2270 2266 2274 2275 2273 2267 2274 2270 2265 2266 2273 2275 2268 2264 2271 2272 2269 2262 2264 2262 2269 2268 2263 2272 2274 2266 2273 2275 2265 2270 2263 2264 2262 2269 2272 2271 2274 2265 2275 2273 2267 2266 2269 2264 2268 2271 2263 2262 2272 2264 2263 2268 2269 2262 2265 2270 2275 2267 2274 2266 2264 2272 2269 2271 2268 2263 2267 2265 2273 2274 2275 2266 2269 2262 2271 2264 2272 2263 2272 2268 2269 2262 2264 2271 2265 2274 2275 2273 2270 2267 2273 2274 2275 2265 2266 2267 2264 2263 2262 2272 2268 2271 2272 2269 2271 2262 2264 2263 2263 2272 2271 2264 2262 2268 2265 2274 2270 2267 2275 2273 2264 2268 2272 2263 2269 2262 2273 2275 2267 2266 2270 2265 2263 2269 2262 2268 2264 2271 2263 2271 2268 2272 2264 2262 2270 2266 2274 2273 2275 2267 2262 2263 2268 2272 2264 2269 2268 2272 2269 2264 2271 2262 2274 2267 2265 2266 2270 2273 2268 2272 2269 2263 2264 2262 2262 2272 2268 2269 2271 2263 2263 2262 2271 2269 2268 2272 2264 2263 2262 2271 2272 2269 2268 2271 2272 2263 2262 2264 2274 2266 2273 2267 2265 2270 2262 2264 2272 2269 2271 2268 2268 2272 2264 2271 2263 2262 2269 2262 2268 2264 2272 2271 2271 2264 2269 2262 2272 2263 2269 2272 2263 2271 2264 2262 2265 2266 2270 2275 2267 2273 2275 2273 2274 2266 2267 2270 2273 2274 2266 2265 2275 2267 2264 2262 2263 2268 2272 2269 2266 2265 2270 2273 2267 2274 2264 2262 2268 2263 2269 2272 2264 2272 2269 2268 2263 2262 2262 2264 2272 2269 2263 2271 2262 2269 2263 2272 2271 2264 2263 2262 2269 2264 2268 2272 2271 2263 2264 2269 2272 2268 2268 2269 2271 2264 2262 2263 2266 2273 2267 2270 2274 2265 99 4664 4709 4798 4789 4671 4684 4773 4718 4802 4678 4719 4768 4669 4699 4766 4752 4748 4788 4724 4746 4738 4686 4677 4796 4761 4809 4783 4800 4706 4718 4807 4781 4698 4670 4722 4738 4776 4676 4684 4689 4666 4767 4690 4773 4697 4717 4794 4741 4685 4698 4701 4752 4747 4664 4703 4708 4733 4670 4745 4742 4751 4746 4688 4786 4743 4678 4745 4712 4774 4685 4728 4794 4672 4693 4777 4776 4699 4756 4799 4807 4675 4671 4765 4768 4801 4683 4740 4728 4665 4673 4731 4735 4667 4705 4676 4775 4686 4736 4718 4758 4674 4710 4693 4682 4671 4767 4695 4736 4721 4769 4667 4666 4681 4707 4732 4725 4689 4735 4766 4718 4726 4808 4682 4742 4783 4679 4721 4787 4808 4712 4783 4691 4743 4695 4731 4756 4781 4706 4684 4769 4763 4713 4797 4771 4731 4722 4734 4799 4733 4698 4704 4749 4773 4783 4682 4673 4696 4719 4780 4685 4737 4723 4717 4771 4760 4780 4772 4720 4750 4731 4794 4713 4684 4722 4739 4665 4719 4787 4671 4777 4698 4743 4695 4694 4737 4779 4713 4802 4724 4791 4786 4754 4665 4772 4698 4717 4671 4778 4752 4803 4726 4740 4704 4714 4746 4677 4697 4695 4688 4799 4671 4752 4778 4760 4767 4676 4776 4724 4676 4697 4707 4794 4682 4754 4711 4693 4687 4725 4686 4675 4667 4742 4762 4793 4714 4770 4796 4685 4801 4739 4790 4751 4742 4734 4732 4675 4788 4702 4809 4754 4698 4763 4804 4793 4789 4723 4710 4712 4744 4696 4688 4730 4689 4729 4744 4671 4729 4764 4775 4774 4731 4722 4761 4801 4707 4790 4785 4667 4807 4721 4735 4680 4670 4732 4694 4695 4797 4745 4738 4736 4790 4771 4757 4744 4749 4683 4780 4801 4762 4767 4722 4785 4675 4739 4799 4795 4689 4784 4729 4708 4710 4680 4728 4736 4699 4809 4802 4800 4718 4701 4801 4773 4685 4674 4805 4747 4791 4742 4765 4719 4761 4745 4728 4740 4725 4700 4711 4799 4775 4807 4712 4695 4720 4748 4718 4685 4676 4708 4770 4782 4727 4705 4687 4684 4754 4674 4806 4692 4714 4690 4756 4802 4688 4778 4777 4779 4745 4794 4748 4786 4783 4684 4697 4677 4729 4730 4798 4738 4695 4772 4780 4809 4793 4752 4731 4759 4725 4670 4694 4693 4810 4665 4664 4755 4723 4671 4670 4793 4688 4788 4773 4683 4674 4700 4758 4696 4665 4781 4705 4693 4751 4672 4754 4800 4767 4666 4714 4779 4763 4685 4670 4781 4756 4700 4675 4737 4767 4683 4768 4760 4730 4803 4668 4786 4744 4746 4664 4669 4761 4675 4717 4669 4785 4711 4754 4685 4810 4767 4678 4780 4736 4808 4797 4758 4757 4670 4771 4766 4750 4722 4707 4800 4735 4737 4795 4728 4802 4738 4789 4745 4801 4779 4791 4782 4789 4686 4711 4683 4739 4754 4664 4700 4727 4709 4766 4774 4743 4763 4778 4704 4806 4664 4718 4776 4708 4781 4759 4699 4720 4766 4798 4756 4807 4781 4667 4806 4795 4789 4730 4788 4806 4761 4769 4724 4671 4722 4706 4736 4784 4786 4712 4689 4725 4743 4809 4756 4760 4665 4766 4779 4688 4772 4676 4787 4758 4754 4804 4722 4731 4764 4677 4709 4673 4785 4806 4805 4707 4690 4694 4801 4775 4714 4673 4751 4678 4664 4781 4706 4783 4671 4772 4692 4776 4722 4705 4706 4766 4783 4756 4741 4740 4798 4768 4803 4750 4774 4736 4721 4740 4691 4732 4726 4679 4798 4688 4750 4804 4724 4767 4686 4748 4712 4703 4723 100 6082 6080 6079 6084 6076 6081 6083 6076 6084 6077 6079 6082 6076 6081 6082 6083 6077 6084 6082 6078 6077 6081 6080 6079 6082 6080 6084 6077 6076 6078 6083 6076 6081 6082 6077 6079 6079 6083 6078 6081 6082 6084 6076 6077 6080 6082 6078 6081 6079 6080 6084 6081 6078 6082 6084 6078 6077 6082 6080 6081 6082 6079 6080 6077 6078 6084 6084 6082 6080 6076 6081 6078 6081 6077 6082 6076 6083 6084 6079 6078 6076 6082 6083 6084 6078 6080 6084 6082 6079 6077 6084 6083 6080 6078 6076 6077 6080 6084 6081 6076 6082 6083 6084 6077 6079 6082 6078 6080 6077 6079 6084 6083 6081 6078 6077 6083 6081 6082 6080 6084 6083 6077 6082 6080 6084 6081 6077 6083 6080 6082 6081 6079 6084 6079 6076 6080 6082 6078 6084 6079 6077 6078 6081 6083 6076 6083 6082 6079 6084 6080 6081 6078 6083 6082 6076 6080 6084 6080 6078 6077 6081 6082 6076 6083 6078 6082 6079 6084 6077 6078 6084 6076 6082 6080 6082 6078 6083 6079 6076 6084 6076 6078 6077 6081 6084 6082 6083 6080 6077 6078 6081 6084 6077 6080 6081 6079 6084 6076 6076 6080 6078 6082 6079 6083 6081 6083 6084 6077 6082 6080 6076 6084 6077 6079 6081 6082 6083 6084 6079 6081 6077 6080 6077 6079 6084 6078 6076 6081 6084 6079 6076 6080 6083 6082 6083 6077 6082 6076 6084 6078 6083 6077 6084 6081 6076 6079 6081 6083 6080 6082 6076 6078 6077 6079 6078 6081 6082 6083 6081 6079 6078 6080 6077 6076 6080 6077 6084 6076 6083 6078 6078 6083 6079 6077 6076 6081 6077 6079 6076 6084 6082 6081 6081 6082 6076 6080 6077 6078 6081 6077 6079 6078 6082 6076 6082 6080 6081 6077 6079 6078 6081 6080 6076 6082 6077 6079 6082 6078 6080 6076 6084 6083 6078 6079 6077 6076 6084 6081 6078 6081 6084 6083 6079 6080 6076 6081 6083 6077 6080 6079 6076 6082 6080 6077 6078 6079 6080 6083 6079 6081 6078 6082 6078 6082 6076 6077 6083 6080 6079 6082 6081 6078 6076 6077 6084 6076 6081 6079 6082 6078 6081 6080 6077 6079 6082 6078 6080 6083 6079 6081 6076 6082 6083 6080 6076 6078 6077 6082 6081 6076 6079 6077 6083 6082 6079 6080 6082 6078 6076 6081 6083 6076 6081 6082 6084 6080 6083 6078 6080 6079 6082 6084 6076 6081 6084 6077 6079 6083 6078 6084 6083 6081 6080 6077 6079 6078 6080 6082 6083 6077 6079 6076 6083 6078 6080 6081 6079 6081 6082 6083 6077 6084 6076 6078 6083 6079 6082 6077 6081 6078 6079 6077 6080 6084 6079 6081 6084 6077 6082 6080 6076 6083 6081 6084 6077 6080 6083 6082 6077 6080 6076 6079 6076 6083 6084 6077 6080 6081 6083 6078 6079 6080 6081 6084 6084 6078 6079 6080 6082 6081 6077 6076 6081 6078 6084 6080 6079 6078 6082 6081 6077 6076 6083 6081 6078 6077 6084 6082 6084 6079 6078 6082 6076 6083 6082 6077 6079 6078 6081 6080 6084 6080 6079 6078 6077 6082 6079 6077 6076 6084 6078 6082 6078 6084 6080 6079 6082 6077 6083 6078 6084 6081 6079 6076 6084 6083 6078 6077 6080 6082 6081 6078 6079 6080 6076 6083 6076 6083 6081 6079 6084 6077 6079 6082 6077 6083 6084 6078 6077 6076 6078 6080 6081 6084 6076 6080 6084 6079 6081 6082 6076 6077 6084 6078 6080 6081 6076 6080 6079 6084 6082 6083 6080 6083 6082 6077 6078 6081 6079 6081 6083 6077 6080 6078 6084 6078 6080 6082 6079 6081 80 9445 9436 9441 9459 9453 9442 9436 9455 9441 9453 9454 9442 9458 9435 9452 9437 9457 9448 9458 9446 9449 9439 9448 9435 9436 9444 9459 9441 9456 9445 9446 9458 9448 9435 9450 9451 9439 9448 9451 9450 9435 9446 9454 9455 9459 9456 9442 9445 9457 9446 9450 9451 9447 9458 9455 9441 9454 9456 9453 9442 9459 9440 9436 9442 9441 9454 9438 9456 9455 9453 9454 9459 9456 9441 9455 9444 9459 9436 9455 9441 9454 9456 9440 9445 9452 9457 9448 9458 9443 9439 9444 9459 9438 9445 9440 9454 9456 9436 9444 9453 9454 9445 9440 9456 9454 9442 9455 9444 9437 9447 9435 9446 9439 9443 9437 9435 9443 9446 9447 9452 9451 9437 9448 9446 9452 9447 9443 9450 9451 9448 9435 9457 9444 9442 9445 9453 9454 9459 9445 9441 9455 9438 9454 9436 9443 9450 9458 9452 9449 9446 9459 9436 9444 9454 9456 9438 9457 9452 9449 9447 9451 9446 9450 9443 9451 9435 9446 9448 9438 9440 9453 9444 9456 9441 9456 9440 9453 9455 9438 9436 9438 9456 9436 9444 9441 9453 9450 9439 9447 9452 9451 9435 9443 9435 9458 9448 9447 9457 9448 9450 9443 9447 9446 9437 9456 9444 9440 9453 9445 9454 9436 9442 9459 9455 9440 9438 9456 9438 9453 9444 9442 9455 9451 9443 9457 9449 9447 9435 9449 9439 9450 9443 9435 9451 9451 9447 9446 9450 9452 9435 9449 9451 9437 9447 9457 9443 9443 9439 9446 9451 9447 9450 9439 9450 9446 9447 9451 9437 9452 9457 9458 9448 9437 9449 9452 9439 9443 9450 9458 9447 9459 9438 9442 9454 9441 9456 9439 9450 9448 9452 9458 9446 9435 9439 9457 9458 9437 9450 9457 9447 9437 9446 9439 9451 9444 9459 9445 9454 9438 9436 9438 9459 9455 9440 9441 9444 9445 9459 9456 9438 9440 9436 9448 9458 9439 9449 9447 9443 9452 9435 9439 9449 9451 9443 9444 9441 9438 9445 9454 9453 9458 9443 9450 9439 9449 9437 9452 9458 9457 9450 9435 9437 9436 9442 9456 9455 9445 9440 9457 9458 9443 9452 9451 9450 9437 9446 9452 9448 9439 9443 9444 9453 9454 9459 9455 9436 9456 9444 9453 9440 9441 9436 9440 9459 9445 9455 9453 9454 9457 9447 9450 9451 9435 9446 9447 9450 9443 9446 9435 9457 9445 9456 9455 9441 9436 9454 9446 9447 9451 9437 9443 9457 9438 9445 9454 9436 9440 9442 9436 9442 9441 9453 9445 9456 9450 9451 9437 9443 9435 9449 9445 9454 9442 9459 9440 9438 9452 9449 9457 9448 9450 9443 9455 9442 9440 9454 9444 9436 9459 9456 9454 9453 9438 9436 9451 9449 9447 9437 9450 9452 9455 9436 9454 9442 9440 9444 9442 9455 9438 9456 9440 9453 9442 9440 9445 9438 9436 9459 9455 9436 9442 9441 9445 9444 9449 9437 9446 9450 9439 9452 100 7406 7421 7429 7418 7417 7414 7412 7416 7424 7426 7407 7430 7421 7417 7406 7425 7422 7414 7409 7430 7426 7410 7419 7427 7427 7410 7413 7430 7426 7415 7406 7420 7421 7408 7418 7422 7420 7428 7418 7411 7422 7406 7422 7411 7421 7429 7428 7425 7412 7407 7413 7410 7424 7427 7411 7417 7421 7420 7414 7418 7408 7425 7411 7429 7418 7417 7420 7428 7411 7421 7414 7406 7429 7411 7421 7420 7408 7414 7422 7425 7429 7428 7417 7418 7406 7411 7422 7418 7420 7417 7421 7411 7414 7425 7429 7422 7423 7412 7415 7424 7430 7409 7419 7412 7424 7409 7410 7427 7406 7429 7422 7418 7417 7420 7424 7430 7419 7410 7412 7409 7423 7415 7410 7424 7413 7430 7424 7409 7415 7423 7410 7426 7409 7430 7426 7407 7410 7413 7421 7418 7411 7425 7422 7429 7426 7412 7423 7430 7415 7424 7413 7427 7415 7416 7430 7409 7419 7412 7413 7410 7407 7423 7408 7417 7406 7420 7422 7421 7406 7418 7408 7428 7414 7422 7430 7426 7423 7412 7409 7419 7410 7426 7419 7430 7424 7413 7413 7419 7426 7409 7415 7416 7416 7412 7419 7423 7413 7407 7428 7408 7418 7414 7406 7422 7411 7408 7420 7418 7428 7421 7418 7420 7406 7428 7414 7421 7419 7409 7426 7424 7413 7416 7408 7414 7425 7418 7422 7429 7417 7428 7411 7418 7408 7406 7430 7424 7416 7413 7419 7415 7415 7423 7427 7426 7412 7413 7425 7429 7408 7421 7411 7418 7428 7422 7429 7420 7425 7411 7427 7412 7415 7430 7413 7426 7427 7412 7430 7423 7415 7419 7406 7411 7420 7428 7408 7422 7417 7418 7425 7408 7429 7422 7408 7406 7420 7411 7421 7429 7420 7406 7421 7428 7418 7408 7430 7409 7416 7419 7424 7407 7410 7430 7424 7409 7413 7426 7429 7421 7428 7411 7422 7408 7430 7427 7412 7423 7415 7419 7407 7415 7424 7430 7410 7423 7429 7406 7428 7417 7408 7414 7424 7430 7423 7407 7426 7409 7411 7425 7422 7429 7408 7406 7426 7410 7427 7419 7412 7424 7417 7425 7418 7406 7422 7411 7412 7419 7427 7410 7424 7409 7406 7422 7421 7418 7428 7425 7409 7423 7412 7416 7427 7419 7429 7414 7406 7408 7418 7425 7417 7422 7408 7421 7418 7406 7407 7427 7412 7416 7415 7430 7427 7415 7424 7416 7426 7430 7414 7425 7422 7428 7421 7429 7410 7419 7415 7416 7409 7423 7407 7423 7416 7410 7409 7413 7429 7414 7422 7417 7406 7418 7414 7418 7417 7421 7429 7422 7422 7418 7408 7414 7429 7420 7423 7426 7415 7419 7416 7427 7416 7409 7426 7424 7430 7419 7414 7422 7421 7406 7429 7411 7409 7430 7410 7424 7413 7415 7406 7408 7420 7429 7421 7422 7410 7423 7430 7413 7415 7409 7420 7421 7417 7418 7408 7429 7420 7422 7418 7406 7429 7411 7414 7418 7408 7428 7406 7422 7430 7407 7419 7410 7409 7413 7409 7427 7407 7412 7416 7426 7414 7428 7429 7422 7417 7406 7423 7424 7419 7416 7426 7407 7406 7425 7429 7418 7421 7411 7424 7410 7423 7430 7419 7426 7419 7407 7416 7430 7410 7413 7422 7418 7406 7411 7421 7428 7412 7424 7415 7416 7407 7426 7424 7423 7412 7426 7427 7416 7411 7428 7422 7429 7406 7414 7407 7413 7424 7423 7412 7427 7423 7430 7427 7424 7416 7407 7423 7412 7416 7410 7407 7415 7421 7425 7418 7420 7406 7411 7411 7428 7406 7414 7425 7422 7417 7425 7414 7411 7421 7420 7410 7412 7426 7424 7423 7415 7407 7430 7412 7426 7413 7409 99 2667 2661 2578 2589 2609 2596 2566 2606 2579 2634 2612 2670 2634 2683 2612 2693 2585 2692 2632 2615 2558 2575 2705 2676 2690 2662 2587 2650 2608 2685 2685 2564 2656 2572 2594 2668 2617 2667 2601 2575 2676 2596 2696 2671 2704 2619 2593 2640 2616 2628 2589 2572 2701 2582 2646 2633 2558 2582 2700 2618 2622 2689 2644 2652 2668 2590 2685 2588 2644 2649 2600 2586 2628 2565 2596 2568 2705 2679 2652 2697 2573 2631 2583 2704 2565 2631 2585 2573 2627 2569 2683 2663 2610 2635 2589 2644 2658 2676 2600 2604 2611 2684 2689 2585 2688 2574 2560 2618 2573 2645 2683 2604 2611 2659 2694 2621 2563 2662 2584 2676 2689 2582 2567 2667 2575 2664 2698 2639 2678 2620 2613 2569 2672 2696 2617 2659 2704 2576 2617 2696 2681 2641 2636 2662 2607 2566 2609 2627 2648 2662 2562 2586 2609 2610 2683 2582 2598 2645 2590 2582 2615 2670 2678 2675 2664 2590 2596 2673 2637 2608 2700 2653 2677 2644 2638 2626 2657 2699 2577 2672 2704 2674 2681 2570 2694 2558 2647 2597 2696 2686 2560 2678 2592 2581 2647 2627 2612 2566 2638 2641 2651 2652 2672 2678 2669 2559 2674 2607 2611 2648 2669 2686 2665 2634 2682 2561 2577 2664 2562 2671 2656 2645 2616 2664 2577 2657 2623 2629 2678 2633 2697 2610 2676 2671 2584 2611 2656 2664 2623 2637 2663 2613 2574 2667 2682 2594 2600 2701 2589 2693 2689 2678 2558 2564 2635 2588 2589 2568 2684 2703 2604 2686 2650 2598 2626 2598 2562 2621 2578 2566 2613 2568 2603 2633 2689 2571 2590 2670 2623 2621 2649 2616 2698 2668 2680 2687 2601 2656 2696 2676 2645 2659 2697 2619 2673 2645 2608 2697 2689 2563 2635 2691 2692 2574 2653 2680 2691 2572 2563 2570 2647 2609 2647 2627 2645 2560 2674 2631 2644 2657 2640 2645 2678 2566 2612 2580 2702 2560 2602 2678 2605 2578 2650 2600 2631 2640 2653 2687 2670 2660 2629 2638 2560 2676 2643 2702 2694 2582 2598 2661 2568 2632 2659 2599 2637 2603 2690 2628 2581 2564 2652 2620 2581 2590 2572 2608 2615 2659 2589 2610 2655 2679 2561 2680 2694 2658 2663 2608 2571 2674 2680 2641 2630 2650 2609 2629 2690 2647 2662 2584 2693 2669 2678 2666 2660 2657 2576 2672 2678 2698 2584 2614 2606 2568 2590 2700 2680 2650 2607 2657 2689 2670 2613 2563 2682 2627 2619 2565 2604 2668 2687 2568 2650 2636 2587 2566 2644 2630 2683 2656 2573 2622 2591 2599 2570 2606 2674 2612 2627 2594 2626 2567 2647 2665 2662 2566 2615 2625 2626 2638 2608 2690 2579 2564 2575 2619 2622 2600 2615 2678 2591 2677 2647 2592 2687 2682 2617 2612 2656 2567 2592 2653 2582 2631 2647 2600 2608 2634 2561 2645 2592 2651 2659 2677 2660 2679 2628 2645 2602 2566 2697 2612 2582 2597 2646 2572 2691 2627 2678 2689 2648 2573 2624 2595 2630 2641 2598 2613 2565 2584 2637 2629 2667 2635 2560 2659 2600 2562 2649 2644 2588 2587 2648 2620 2573 2634 2699 2567 2642 2653 2659 2695 2657 2612 2669 2667 2677 2631 2611 2659 2702 2692 2615 2569 2636 2633 2677 2620 2561 2668 2666 2685 2674 2638 2576 2613 2580 2624 2647 2684 2601 2670 2593 2628 2578 2663 2680 2623 2565 2560 2574 2590 2604 2602 2664 2576 2624 2632 2697 2677 2678 2687 2686 2679 2622 2600 2596 2677 2673 2639 2704 2684 2670 2643 100 6755 6753 6759 6752 6756 6758 6758 6757 6760 6754 6753 6756 6753 6755 6759 6754 6757 6756 6772 6766 6768 6769 6765 6771 6758 6757 6753 6752 6760 6759 6756 6762 6759 6755 6757 6758 6759 6763 6761 6762 6765 6757 6754 6752 6753 6755 6756 6757 6789 6793 6795 6788 6794 6792 6754 6760 6753 6752 6758 6755 6753 6759 6760 6756 6755 6757 6783 6782 6784 6789 6785 6788 6756 6752 6754 6758 6755 6753 6755 6750 6754 6753 6749 6756 6753 6754 6756 6755 6759 6757 6792 6789 6787 6790 6785 6786 6777 6774 6773 6781 6780 6779 6757 6759 6754 6755 6760 6753 6753 6754 6758 6755 6752 6759 6759 6753 6756 6755 6757 6754 6761 6764 6763 6760 6765 6766 6754 6752 6758 6757 6755 6753 6782 6779 6781 6783 6784 6778 6791 6797 6799 6798 6793 6796 6757 6755 6756 6753 6759 6754 6758 6755 6753 6752 6759 6757 6755 6757 6759 6754 6756 6752 6755 6757 6752 6759 6756 6754 6773 6776 6779 6780 6777 6778 6757 6755 6752 6758 6753 6754 6760 6755 6753 6752 6758 6759 6754 6752 6758 6753 6756 6760 6778 6786 6783 6781 6780 6785 6760 6758 6752 6759 6756 6755 6757 6758 6755 6760 6759 6756 6757 6755 6758 6753 6760 6759 6746 6750 6753 6751 6749 6752 6754 6755 6750 6756 6757 6749 6752 6753 6756 6757 6758 6755 6756 6754 6758 6757 6753 6759 6758 6755 6753 6757 6756 6754 6760 6753 6752 6757 6755 6756 6753 6759 6757 6752 6758 6760 6778 6775 6777 6773 6770 6772 6774 6777 6775 6778 6780 6782 6753 6755 6757 6752 6754 6758 6763 6756 6758 6762 6761 6760 6743 6750 6745 6749 6751 6747 6754 6753 6760 6755 6757 6758 6768 6763 6764 6767 6765 6766 6773 6774 6771 6775 6777 6772 6767 6774 6768 6772 6771 6773 6760 6756 6755 6757 6752 6753 6792 6795 6797 6791 6790 6789 6790 6794 6787 6793 6791 6792 6757 6760 6753 6752 6755 6754 6748 6750 6753 6745 6749 6751 6744 6752 6745 6748 6746 6747 6756 6753 6760 6754 6757 6758 6765 6764 6767 6760 6761 6763 6797 6794 6791 6792 6795 6793 6754 6755 6757 6759 6751 6756 6756 6757 6755 6754 6759 6753 6751 6755 6753 6752 6749 6748 6753 6758 6760 6757 6755 6756 6754 6752 6758 6755 6756 6757 6793 6788 6790 6789 6786 6787 6758 6753 6760 6759 6756 6755 6755 6758 6761 6754 6760 6757 6754 6759 6757 6756 6755 6758 6760 6759 6757 6755 6754 6756 6776 6769 6770 6777 6772 6771 6782 6775 6783 6781 6779 6780 6760 6758 6753 6752 6759 6756 6749 6746 6743 6750 6742 6747 6765 6766 6762 6760 6761 6763 6775 6772 6768 6774 6769 6773 6759 6757 6753 6760 6756 6755 6756 6753 6755 6758 6759 6760 6769 6761 6762 6766 6767 6768 6756 6757 6754 6755 6760 6753 6777 6784 6782 6778 6780 6785 6781 6787 6780 6786 6779 6784 6754 6757 6753 6759 6760 6756 6788 6783 6782 6785 6780 6784 6772 6766 6774 6768 6771 6769 6789 6783 6788 6786 6790 6785 6771 6767 6766 6763 6769 6768 6754 6756 6755 6753 6752 6760 6787 6793 6791 6788 6790 6792 6754 6758 6752 6760 6757 6759 6760 6756 6752 6755 6759 6754 6764 6767 6770 6766 6771 6769 6758 6759 6757 6760 6752 6753 6754 6753 6760 6755 6752 6759 6790 6789 6786 6784 6787 6788 6754 6759 6753 6758 6756 6760 6763 6759 6757 6756 6761 6758 6756 6758 6757 6754 6760 6752 6760 6756 6752 6753 6755 6757 100 6999 6993 6994 6995 6997 6996 7008 7009 7011 7007 7012 7010 7007 7006 7003 7002 7005 7004 6989 6986 6984 6988 6987 6983 6996 7000 6999 7002 6997 7001 6991 6993 6995 6996 6990 6994 6987 6986 6988 6991 6990 6985 6989 6990 6995 6994 6993 6992 7001 7000 7002 6999 7005 7004 6923 6922 6927 6924 6926 6928 6928 6923 6925 6924 6927 6926 6949 6953 6951 6952 6954 6950 6976 6979 6981 6978 6977 6975 6989 6990 6987 6992 6988 6991 6990 6986 6987 6992 6988 6989 6949 6951 6947 6950 6953 6948 6964 6963 6962 6965 6967 6968 6935 6932 6936 6934 6931 6930 6956 6958 6959 6954 6957 6955 6954 6958 6957 6956 6955 6952 6971 6970 6973 6972 6976 6975 6974 6976 6978 6975 6979 6977 6972 6973 6969 6971 6967 6970 7004 7000 6998 6999 7003 7001 6982 6987 6983 6984 6985 6986 6941 6947 6946 6944 6942 6943 6966 6962 6964 6963 6961 6965 6936 6941 6937 6939 6938 6942 6924 6919 6918 6923 6921 6920 6928 6925 6929 6930 6931 6926 6964 6965 6968 6967 6966 6969 7011 7009 7007 7005 7006 7010 6935 6938 6937 6940 6939 6936 6946 6950 6949 6948 6945 6944 6938 6935 6940 6936 6939 6937 6956 6957 6959 6953 6954 6955 6918 6919 6920 6921 6922 6917 6932 6934 6937 6938 6933 6936 6955 6956 6950 6953 6954 6952 6952 6955 6950 6954 6949 6953 6913 6915 6914 6917 6912 6911 6999 6998 6995 6994 6997 7000 6972 6978 6976 6974 6977 6973 7009 7005 7006 7004 7010 7007 6930 6932 6928 6931 6934 6933 6972 6968 6970 6973 6974 6971 6965 6964 6967 6969 6966 6963 6918 6921 6919 6915 6917 6920 6948 6951 6946 6947 6949 6952 6920 6921 6922 6923 6925 6926 6958 6957 6959 6961 6963 6960 6970 6969 6971 6965 6967 6966 6923 6922 6920 6921 6919 6917 6963 6966 6961 6965 6960 6964 6919 6918 6917 6916 6915 6920 6984 6987 6988 6986 6990 6989 6977 6980 6975 6976 6979 6978 6992 6995 6997 6998 6993 6994 6938 6937 6942 6939 6941 6940 6936 6935 6939 6933 6934 6938 6949 6944 6947 6946 6943 6948 7000 7003 7001 7006 7002 7005 7007 7009 7006 7004 7003 7005 6940 6944 6946 6945 6942 6941 6994 6989 6988 6993 6991 6990 6930 6931 6933 6932 6929 6934 6915 6916 6914 6912 6913 6911 6972 6968 6966 6970 6971 6967 6974 6969 6971 6970 6975 6973 6927 6931 6928 6932 6929 6926 6964 6962 6959 6958 6961 6963 6994 6996 6993 6992 6995 6991 7009 7010 7007 7008 7011 7006 6978 6984 6979 6981 6980 6983 6972 6973 6976 6971 6977 6974 6927 6928 6930 6929 6924 6926 6944 6945 6943 6948 6947 6946 6912 6914 6913 6915 6909 6911 6941 6945 6942 6939 6944 6943 6923 6920 6922 6919 6925 6924 6912 6916 6913 6914 6918 6915 6947 6948 6951 6946 6949 6950 6917 6916 6914 6918 6913 6919 6977 6978 6980 6982 6979 6981 6984 6979 6985 6981 6983 6982 6984 6985 6987 6986 6982 6983 6979 6981 6977 6982 6983 6978 6953 6952 6951 6954 6955 6957 6929 6928 6930 6932 6933 6931 6961 6960 6962 6958 6957 6956 6995 7000 7001 6999 6996 6998 6960 6959 6962 6961 6965 6963 6956 6960 6957 6959 6961 6958 7005 7002 7006 7007 7004 7008 6940 6938 6944 6941 6942 6943 6933 6934 6937 6932 6935 6931 6999 7002 6997 7000 7003 6998 6985 6984 6986 6980 6981 6982 6927 6922 6921 6926 6923 6925 7010 7014 7012 7013 7009 7011 100 8043 8045 8044 8040 8041 8042 8032 8028 8027 8029 8031 8030 8028 8031 8030 8032 8027 8029 8031 8029 8027 8028 8030 8032 8021 8022 8024 8026 8025 8023 8042 8041 8040 8039 8043 8044 8030 8032 8028 8031 8029 8027 8055 8052 8057 8056 8053 8054 8027 8032 8029 8031 8028 8030 8072 8073 8068 8071 8070 8069 8021 8024 8023 8025 8022 8020 8043 8040 8041 8039 8038 8042 8049 8046 8050 8045 8048 8047 8030 8028 8029 8027 8031 8032 8027 8028 8030 8029 8031 8032 8031 8028 8030 8026 8027 8029 8030 8029 8032 8028 8027 8031 8032 8027 8030 8031 8028 8029 8024 8025 8027 8023 8022 8026 8028 8031 8027 8029 8032 8030 8051 8054 8052 8055 8050 8053 8048 8050 8051 8049 8047 8046 8027 8031 8030 8032 8029 8028 8027 8029 8030 8028 8032 8031 8059 8055 8057 8060 8056 8058 8027 8026 8025 8024 8023 8028 8029 8028 8030 8027 8032 8031 8030 8027 8031 8029 8032 8028 8027 8032 8030 8028 8031 8029 8032 8029 8028 8030 8027 8031 8066 8067 8071 8068 8070 8069 8027 8028 8031 8030 8029 8032 8029 8032 8028 8030 8027 8031 8032 8031 8030 8029 8027 8028 8028 8031 8030 8032 8027 8029 8031 8028 8032 8027 8030 8029 8056 8058 8057 8059 8055 8054 8060 8062 8058 8063 8059 8061 8031 8032 8028 8027 8029 8030 8068 8065 8067 8069 8070 8066 8058 8056 8057 8053 8054 8055 8073 8070 8072 8071 8069 8074 8029 8026 8028 8024 8027 8025 8037 8038 8040 8039 8035 8036 8043 8044 8046 8048 8047 8045 8061 8064 8065 8062 8060 8063 8063 8066 8067 8068 8064 8065 8031 8028 8027 8030 8032 8029 8033 8037 8036 8035 8034 8038 8061 8057 8058 8059 8060 8056 8030 8029 8034 8032 8031 8033 8029 8030 8028 8027 8032 8031 8033 8031 8029 8032 8030 8028 8052 8049 8054 8050 8051 8053 8031 8030 8028 8029 8027 8032 8029 8031 8028 8030 8027 8032 8035 8031 8033 8032 8034 8036 8058 8061 8057 8059 8060 8062 8027 8031 8032 8030 8028 8029 8031 8029 8030 8028 8032 8027 8031 8029 8032 8030 8028 8027 8026 8028 8027 8030 8025 8029 8028 8032 8031 8030 8027 8029 8029 8032 8031 8027 8030 8028 8037 8039 8040 8041 8036 8038 8027 8031 8029 8032 8028 8030 8030 8027 8032 8031 8028 8029 8037 8040 8039 8038 8042 8041 8027 8028 8031 8032 8029 8030 8027 8032 8030 8028 8031 8029 8038 8035 8039 8037 8034 8036 8066 8068 8067 8065 8069 8064 8031 8032 8029 8027 8028 8030 8065 8064 8061 8063 8066 8062 8049 8050 8052 8051 8048 8047 8046 8049 8048 8044 8047 8045 8032 8030 8031 8029 8028 8027 8030 8032 8027 8031 8028 8029 8042 8043 8046 8044 8045 8047 8029 8028 8031 8032 8027 8030 8035 8032 8030 8033 8031 8034 8032 8029 8031 8030 8027 8028 8029 8028 8031 8030 8027 8032 8027 8029 8032 8030 8031 8028 8045 8042 8041 8044 8046 8043 8032 8028 8030 8031 8029 8027 8032 8027 8029 8030 8031 8028 8029 8027 8031 8028 8032 8030 8067 8072 8071 8068 8069 8070 8029 8032 8028 8031 8030 8027 8027 8028 8029 8032 8030 8031 8029 8031 8030 8028 8032 8027 8048 8052 8051 8053 8050 8049 8053 8054 8056 8051 8052 8055 8064 8061 8063 8062 8060 8059 8030 8029 8028 8031 8032 8027 8063 8065 8064 8067 8062 8066 8032 8027 8030 8031 8029 8028 8028 8029 8031 8032 8030 8027 8032 8036 8033 8035 8034 8037 45 5278 5284 5286 5282 5277 5280 5281 5287 5282 5286 5290 5284 5277 5284 5280 5287 5290 5286 5282 5281 5277 5284 5286 5290 5294 5293 5279 5283 5288 5285 5281 5277 5280 5290 5284 5282 5293 5285 5294 5289 5279 5283 5290 5280 5277 5287 5282 5278 5287 5282 5277 5290 5278 5280 5285 5294 5279 5289 5291 5292 5277 5286 5280 5281 5287 5282 5278 5281 5284 5282 5286 5280 5283 5293 5292 5291 5285 5288 5284 5280 5287 5290 5282 5281 5283 5279 5292 5289 5294 5293 5286 5278 5290 5281 5284 5282 5285 5279 5293 5283 5289 5288 5280 5286 5281 5287 5290 5277 5294 5279 5285 5283 5293 5289 5278 5287 5282 5277 5281 5290 5277 5290 5284 5287 5281 5286 5287 5278 5284 5286 5282 5281 5280 5284 5282 5281 5287 5277 5286 5284 5282 5278 5281 5280 5286 5278 5282 5277 5284 5290 5280 5284 5286 5287 5282 5281 5281 5287 5284 5286 5282 5278 5286 5281 5290 5284 5280 5287 5280 5290 5277 5278 5286 5287 5288 5294 5289 5285 5283 5293 5277 5281 5287 5278 5290 5284 5294 5283 5288 5289 5291 5292 5282 5290 5281 5280 5287 5286 5290 5277 5282 5281 5278 5287 5294 5291 5279 5292 5289 5288 5289 5294 5283 5279 5292 5291 5288 5283 5292 5289 5293 5285 5293 5279 5291 5283 5289 5294 5278 5286 5281 5287 5280 5282 5283 5288 5292 5285 5294 5279 5290 5278 5286 5277 5282 5280 5288 5293 5291 5294 5285 5292 5290 5284 5287 5286 5282 5281 5280 5277 5281 5287 5284 5286 5290 5286 5287 5282 5277 5284 100 982 987 991 983 988 990 964 972 971 967 969 966 1025 1026 1019 1021 1020 1028 1005 1001 1003 997 996 1004 966 976 969 968 967 970 932 941 943 938 935 933 1009 1006 1008 1010 1003 1011 1012 1009 1011 1013 1017 1014 980 985 979 987 982 978 1007 1002 1004 1005 998 1003 967 963 964 965 966 959 968 973 970 974 969 975 968 978 977 976 975 969 947 946 953 950 951 956 989 982 979 983 990 986 1017 1009 1018 1016 1012 1013 971 963 964 968 962 965 953 956 951 957 960 959 923 931 924 933 934 927 955 962 954 958 964 963 970 964 963 961 969 967 952 951 959 949 957 960 953 957 948 952 954 958 966 967 965 963 962 957 985 991 994 988 989 992 978 973 981 976 982 972 1011 1006 1007 1005 1009 1014 980 977 978 976 974 983 949 950 947 946 939 943 929 920 919 923 928 922 963 965 960 961 955 962 990 988 992 994 987 991 992 995 994 998 988 996 955 959 962 966 963 961 996 989 992 991 994 993 938 944 942 943 939 937 995 990 999 994 992 991 949 946 944 948 945 942 944 942 948 949 938 943 992 998 997 994 991 993 1028 1018 1025 1022 1024 1019 936 932 930 934 935 929 1018 1016 1026 1022 1017 1021 995 993 999 991 1001 1002 953 959 961 957 958 963 1019 1010 1016 1020 1014 1018 1005 1015 1006 1008 1004 1013 996 1000 1003 994 997 999 968 965 972 973 966 969 924 921 922 926 923 929 944 947 945 951 953 955 967 965 957 962 961 963 981 978 975 980 983 976 1001 1005 1000 1006 1007 1004 941 938 933 935 942 931 987 988 981 980 985 982 997 1005 1006 996 999 998 1004 1003 1006 1007 1012 1002 1025 1027 1026 1019 1024 1017 949 951 943 944 954 946 990 982 986 992 985 987 968 967 978 970 969 973 1021 1023 1018 1014 1017 1022 977 981 979 973 976 978 939 948 947 942 945 938 986 981 988 987 977 980 994 993 992 986 987 989 1004 1014 1013 1005 1003 1006 933 936 940 934 937 930 927 921 931 926 923 922 957 955 956 952 950 954 975 976 973 979 981 974 967 975 974 976 969 970 1011 1006 1004 1002 1008 1003 978 985 982 984 983 975 996 1000 993 997 999 1001 945 944 946 951 950 949 949 956 950 951 948 953 995 1002 994 1003 1005 999 992 993 984 990 991 985 932 925 928 931 929 933 967 969 966 962 968 963 1014 1015 1012 1019 1011 1022 946 945 940 944 936 935 929 924 932 930 933 927 1003 1006 1007 998 1005 1008 944 942 936 941 939 933 1006 1016 1008 1013 1010 1017 1019 1013 1023 1016 1015 1022 938 929 932 935 930 936 933 932 934 927 930 929 946 938 941 947 944 940 1018 1013 1007 1015 1009 1012 980 981 983 979 987 986 949 957 951 948 958 956 1014 1018 1019 1020 1024 1017 977 980 976 978 973 974 929 933 937 927 938 930 930 933 940 929 936 931 953 942 950 948 945 951 60 1859 1857 1854 1856 1862 1866 1862 1858 1868 1856 1852 1859 1865 1863 1851 1853 1860 1867 1862 1852 1856 1857 1866 1854 1864 1855 1863 1853 1861 1860 1864 1853 1851 1867 1865 1855 1860 1867 1853 1855 1861 1863 1863 1855 1853 1867 1865 1864 1864 1863 1853 1867 1855 1860 1858 1856 1862 1854 1852 1859 1851 1863 1860 1861 1855 1853 1855 1853 1861 1864 1851 1863 1865 1864 1867 1861 1860 1851 1860 1865 1861 1853 1864 1855 1865 1860 1851 1855 1864 1853 1865 1861 1851 1853 1860 1855 1852 1866 1868 1862 1857 1856 1855 1863 1867 1851 1861 1865 1860 1865 1855 1851 1867 1853 1856 1862 1852 1859 1868 1857 1866 1854 1859 1857 1856 1862 1864 1861 1855 1863 1867 1853 1853 1855 1860 1865 1863 1861 1864 1865 1855 1860 1867 1851 1851 1853 1867 1863 1855 1861 1863 1851 1860 1853 1861 1864 1858 1856 1866 1862 1852 1854 1866 1862 1852 1868 1854 1857 1863 1853 1851 1861 1865 1864 1851 1863 1853 1860 1861 1867 1865 1851 1864 1861 1855 1860 1857 1852 1856 1854 1862 1859 1860 1853 1865 1864 1867 1863 1852 1862 1858 1856 1866 1857 1865 1860 1867 1861 1851 1855 1862 1856 1868 1866 1857 1859 1863 1853 1851 1861 1865 1855 1867 1855 1861 1864 1863 1853 1867 1855 1863 1853 1861 1865 1852 1854 1856 1857 1858 1866 1867 1860 1865 1855 1851 1864 1853 1867 1865 1855 1851 1861 1865 1860 1853 1861 1863 1855 1861 1855 1865 1860 1867 1864 1854 1859 1866 1858 1868 1857 1862 1856 1857 1868 1858 1852 1867 1853 1863 1864 1855 1851 1867 1855 1864 1861 1860 1851 1867 1864 1853 1855 1865 1861 1856 1868 1858 1862 1857 1852 1867 1861 1855 1853 1851 1863 1853 1855 1861 1860 1865 1867 1857 1856 1858 1854 1852 1862 1857 1852 1858 1868 1859 1856 1854 1859 1856 1858 1868 1857 1865 1855 1863 1864 1853 1861 1861 1865 1860 1853 1863 1864 1860 1867 1851 1853 1865 1863 1864 1865 1861 1853 1851 1863 1857 1859 1866 1858 1854 1868 99 2611 2730 2729 2636 2612 2721 2707 2691 2712 2594 2700 2699 2675 2719 2684 2734 2662 2668 2662 2729 2632 2721 2679 2701 2646 2673 2648 2595 2634 2715 2648 2683 2721 2604 2675 2735 2672 2713 2631 2617 2720 2625 2687 2660 2628 2638 2612 2624 2730 2618 2682 2696 2648 2651 2710 2722 2684 2643 2617 2704 2593 2626 2657 2635 2721 2713 2606 2692 2589 2666 2646 2675 2686 2714 2723 2697 2690 2687 2700 2651 2711 2597 2638 2614 2609 2636 2594 2694 2606 2654 2633 2729 2720 2659 2686 2733 2648 2624 2675 2681 2609 2619 2632 2702 2606 2701 2680 2636 2616 2623 2647 2683 2661 2721 2706 2696 2700 2728 2624 2606 2679 2728 2604 2677 2695 2698 2718 2672 2675 2658 2715 2631 2714 2705 2678 2692 2645 2624 2594 2634 2656 2687 2612 2616 2610 2667 2725 2727 2695 2707 2701 2650 2702 2643 2633 2625 2645 2617 2695 2724 2672 2614 2650 2618 2664 2635 2704 2605 2598 2648 2588 2639 2623 2663 2652 2713 2672 2660 2624 2733 2699 2638 2599 2665 2717 2627 2670 2671 2686 2665 2676 2625 2627 2638 2617 2664 2591 2628 2700 2624 2694 2617 2607 2653 2695 2623 2645 2703 2725 2625 2712 2594 2596 2695 2667 2714 2707 2618 2611 2703 2691 2686 2623 2696 2680 2654 2644 2618 2733 2615 2673 2664 2663 2616 2631 2708 2597 2713 2709 2734 2614 2657 2592 2698 2671 2635 2667 2653 2638 2686 2641 2608 2684 2707 2730 2690 2678 2727 2617 2703 2632 2634 2606 2723 2635 2637 2595 2696 2684 2616 2672 2652 2598 2614 2616 2688 2714 2699 2638 2727 2726 2694 2732 2627 2595 2628 2614 2714 2659 2730 2645 2596 2728 2613 2714 2677 2672 2704 2651 2615 2660 2691 2656 2676 2649 2622 2651 2703 2722 2635 2731 2631 2615 2626 2701 2613 2636 2723 2595 2690 2609 2679 2644 2729 2638 2643 2649 2711 2729 2709 2654 2645 2678 2688 2718 2594 2728 2632 2594 2712 2731 2668 2721 2679 2695 2708 2709 2599 2667 2671 2592 2632 2600 2589 2675 2591 2672 2633 2724 2721 2588 2603 2651 2698 2713 2728 2673 2721 2694 2691 2718 2664 2680 2646 2630 2607 2602 2722 2660 2713 2712 2603 2668 2627 2727 2704 2667 2670 2680 2620 2698 2705 2617 2724 2605 2652 2668 2600 2604 2678 2710 2677 2611 2699 2717 2702 2671 2628 2727 2694 2606 2732 2613 2648 2604 2670 2620 2588 2731 2637 2631 2687 2596 2625 2606 2711 2720 2694 2727 2615 2629 2612 2663 2686 2669 2605 2698 2730 2589 2692 2615 2657 2715 2676 2596 2675 2694 2734 2715 2608 2732 2617 2653 2660 2593 2626 2694 2696 2635 2709 2662 2698 2648 2591 2720 2655 2680 2601 2625 2605 2659 2645 2699 2588 2604 2634 2722 2682 2651 2647 2691 2708 2713 2665 2596 2614 2734 2648 2599 2607 2606 2669 2703 2594 2727 2649 2599 2626 2657 2712 2700 2711 2602 2638 2643 2730 2669 2728 2705 2636 2590 2628 2734 2619 2646 2729 2726 2654 2733 2672 2656 2673 2622 2642 2722 2607 2678 2660 2653 2633 2606 2733 2605 2710 2696 2726 2656 2641 2695 2703 2590 2717 2722 2656 2673 2626 2612 2605 2668 2729 2648 2641 2721 2589 2623 2659 2693 2671 2627 2683 2600 2712 2669 2686 2642 2590 2630 2658 2668 2601 2610 2649 2692 2617 2654 2702 2626 2734 2607 2622 2614 2671 2669 2693 2622 2711 2636 2650 2695 2592 2655 2653 2636 2595 100 7221 7230 7232 7231 7233 7228 7225 7224 7223 7229 7227 7222 7222 7224 7226 7225 7227 7229 7228 7231 7230 7221 7232 7233 7225 7226 7229 7227 7223 7224 7233 7230 7228 7221 7232 7231 7225 7229 7224 7222 7223 7226 7221 7232 7228 7231 7233 7230 7228 7233 7230 7232 7221 7231 7223 7226 7222 7227 7224 7225 7225 7224 7223 7222 7227 7226 7231 7230 7233 7221 7232 7228 7223 7227 7226 7229 7224 7225 7228 7232 7221 7230 7233 7231 7223 7229 7227 7225 7222 7226 7233 7228 7231 7230 7232 7221 7222 7227 7223 7229 7226 7225 7231 7232 7233 7228 7221 7230 7227 7223 7226 7224 7225 7222 7223 7226 7224 7222 7227 7225 7227 7224 7229 7223 7225 7226 7233 7228 7232 7230 7231 7221 7226 7229 7223 7224 7227 7225 7229 7222 7225 7223 7224 7227 7228 7221 7232 7230 7231 7233 7233 7228 7221 7232 7230 7231 7222 7227 7223 7225 7224 7229 7227 7222 7229 7225 7226 7224 7231 7233 7228 7221 7232 7230 7222 7225 7229 7224 7223 7226 7227 7222 7223 7229 7226 7225 7225 7226 7224 7223 7229 7227 7226 7227 7229 7225 7222 7223 7231 7230 7233 7221 7232 7228 7232 7228 7221 7231 7233 7230 7229 7227 7225 7223 7226 7222 7223 7226 7227 7222 7224 7229 7231 7230 7232 7228 7221 7233 7228 7221 7232 7233 7230 7231 7226 7222 7224 7227 7223 7229 7221 7230 7228 7233 7232 7231 7221 7232 7228 7231 7233 7230 7228 7232 7231 7233 7221 7230 7226 7225 7222 7223 7229 7224 7225 7227 7222 7229 7224 7223 7225 7222 7229 7224 7226 7223 7230 7232 7233 7231 7228 7221 7230 7233 7232 7228 7231 7221 7221 7230 7233 7231 7232 7228 7221 7228 7231 7233 7232 7230 7222 7224 7225 7227 7229 7226 7231 7232 7221 7230 7228 7233 7228 7221 7233 7230 7232 7231 7222 7225 7227 7224 7229 7226 7228 7231 7221 7232 7233 7230 7228 7221 7232 7233 7231 7230 7232 7233 7231 7221 7230 7228 7224 7226 7222 7229 7225 7227 7231 7221 7232 7230 7228 7233 7222 7229 7227 7226 7225 7223 7231 7221 7233 7232 7228 7230 7233 7232 7230 7221 7231 7228 7232 7228 7230 7233 7221 7231 7229 7227 7226 7224 7225 7223 7233 7232 7228 7221 7230 7231 7225 7226 7222 7229 7224 7223 7222 7225 7223 7226 7229 7224 7233 7228 7230 7232 7221 7231 7230 7231 7233 7232 7228 7221 7222 7223 7226 7227 7229 7224 7232 7233 7231 7230 7221 7228 7231 7233 7230 7221 7228 7232 7227 7222 7229 7223 7224 7225 7229 7227 7225 7224 7223 7222 7226 7227 7222 7229 7223 7225 7230 7221 7228 7231 7232 7233 7229 7226 7223 7224 7222 7227 7227 7223 7222 7226 7229 7225 7231 7228 7233 7221 7230 7232 7223 7225 7226 7227 7229 7222 7231 7232 7228 7221 7230 7233 7227 7223 7229 7226 7222 7225 7224 7229 7223 7226 7222 7225 7222 7224 7227 7229 7223 7225 7232 7231 7221 7228 7230 7233 7224 7225 7223 7222 7226 7227 7233 7221 7232 7228 7230 7231 7224 7229 7227 7223 7226 7222 7229 7225 7224 7227 7226 7223 7229 7225 7226 7224 7227 7223 7231 7228 7230 7233 7221 7232 7232 7230 7231 7221 7233 7228 7221 7230 7233 7228 7232 7231 7230 7233 7228 7221 7231 7232 7224 7222 7226 7223 7229 7227 7221 7230 7228 7233 7231 7232 7226 7225 7224 7222 7223 7227 7221 7232 7231 7233 7230 7228 7222 7226 7229 7225 7227 7223 7228 7221 7231 7232 7230 7233 30 8156 8153 8154 8159 8160 8150 8146 8156 8155 8154 8147 8152 8135 8142 8137 8140 8146 8139 8158 8154 8150 8155 8159 8148 8140 8147 8137 8142 8143 8144 8143 8138 8140 8141 8144 8135 8157 8159 8164 8155 8162 8158 8164 8162 8169 8159 8161 8160 8159 8155 8152 8160 8161 8162 8166 8162 8161 8164 8157 8158 8143 8152 8147 8151 8145 8141 8153 8156 8159 8152 8162 8157 8149 8153 8145 8151 8142 8144 8145 8148 8146 8147 8143 8150 8140 8142 8136 8133 8139 8134 8142 8138 8147 8143 8141 8137 8137 8135 8141 8136 8138 8143 8152 8150 8151 8156 8148 8149 8169 8170 8161 8163 8164 8166 8157 8152 8150 8155 8148 8153 8142 8144 8148 8143 8146 8147 8147 8148 8145 8146 8150 8151 8158 8155 8159 8153 8152 8151 8149 8140 8142 8146 8138 8143 8157 8158 8160 8167 8165 8163 8164 8160 8165 8166 8158 8163 8138 8131 8130 8133 8132 8134 8135 8133 8136 8138 8137 8141 8148 8146 8150 8147 8142 8140 8160 8165 8159 8156 8163 8164 45 2810 2805 2813 2807 2823 2809 2818 2804 2805 2810 2809 2807 2823 2812 2805 2825 2804 2824 2826 2808 2811 2816 2815 2806 2823 2807 2810 2812 2813 2805 2820 2821 2815 2814 2808 2826 2806 2827 2817 2808 2819 2815 2806 2827 2826 2819 2815 2816 2822 2813 2825 2818 2805 2807 2809 2810 2822 2805 2825 2804 2826 2821 2816 2817 2806 2811 2820 2827 2821 2817 2808 2811 2824 2810 2823 2825 2818 2812 2811 2820 2808 2806 2827 2819 2816 2806 2820 2826 2821 2815 2807 2804 2822 2810 2812 2824 2808 2820 2811 2821 2827 2815 2824 2823 2813 2818 2804 2812 2821 2814 2808 2811 2820 2806 2811 2826 2816 2814 2817 2806 2809 2813 2807 2812 2810 2818 2813 2804 2823 2822 2812 2825 2805 2825 2804 2823 2812 2809 2814 2815 2821 2808 2820 2827 2810 2818 2822 2809 2807 2823 2823 2818 2824 2807 2825 2822 2825 2822 2818 2805 2807 2824 2813 2825 2818 2807 2804 2812 2811 2821 2814 2826 2819 2808 2825 2812 2810 2805 2818 2804 2813 2807 2825 2812 2810 2824 2804 2807 2805 2812 2810 2822 2812 2813 2825 2818 2810 2823 2805 2810 2813 2812 2822 2818 2823 2804 2810 2822 2805 2825 2810 2818 2805 2809 2813 2804 2826 2817 2815 2814 2819 2808 2813 2809 2823 2805 2804 2807 2820 2821 2808 2816 2826 2806 2823 2824 2804 2818 2825 2810 2822 2824 2812 2818 2804 2825 2824 2825 2812 2822 2810 2813 2805 2824 2813 2809 2823 2822 2824 2823 2810 2807 2822 2813 2818 2807 2810 2812 2825 2823 100 5077 5075 5070 5072 5076 5069 5090 5085 5092 5093 5088 5094 5085 5081 5080 5087 5078 5086 5085 5077 5086 5078 5087 5083 5099 5098 5103 5102 5101 5105 5087 5086 5085 5084 5089 5083 5086 5085 5084 5083 5081 5087 5087 5082 5085 5081 5080 5078 5077 5080 5087 5078 5083 5086 5085 5087 5084 5086 5080 5081 5084 5088 5087 5092 5093 5094 5078 5082 5079 5083 5085 5077 5082 5077 5079 5080 5085 5086 5091 5095 5099 5093 5092 5094 5102 5101 5097 5095 5096 5098 5082 5084 5081 5083 5080 5077 5084 5088 5092 5085 5087 5093 5086 5090 5091 5083 5082 5085 5087 5085 5089 5090 5088 5092 5094 5087 5093 5091 5092 5088 5086 5080 5087 5084 5077 5079 5089 5093 5097 5094 5098 5096 5119 5111 5118 5116 5117 5112 5077 5078 5081 5085 5086 5082 5070 5074 5080 5075 5078 5073 5079 5078 5081 5073 5080 5074 5079 5074 5081 5077 5072 5080 5082 5077 5079 5080 5081 5078 5077 5087 5081 5078 5084 5086 5111 5103 5105 5109 5113 5110 5068 5069 5065 5074 5066 5070 5087 5077 5079 5080 5081 5084 5084 5082 5086 5079 5083 5080 5083 5081 5077 5078 5084 5080 5081 5085 5079 5080 5086 5076 5079 5083 5082 5077 5087 5081 5081 5079 5085 5078 5084 5083 5110 5114 5106 5113 5112 5108 5085 5080 5087 5077 5082 5084 5077 5086 5079 5082 5081 5078 5076 5078 5074 5075 5077 5080 5078 5082 5079 5085 5084 5083 5087 5077 5084 5079 5078 5083 5075 5078 5083 5079 5074 5080 5070 5069 5071 5078 5073 5072 5100 5091 5096 5097 5101 5098 5078 5082 5077 5081 5079 5075 5106 5104 5103 5108 5107 5111 5084 5081 5079 5080 5085 5086 5081 5078 5077 5087 5083 5085 5090 5091 5088 5093 5086 5096 5082 5081 5084 5080 5083 5078 5075 5068 5071 5070 5066 5073 5081 5080 5085 5083 5077 5084 5083 5084 5077 5079 5085 5080 5083 5077 5082 5079 5084 5081 5119 5117 5114 5116 5121 5113 5114 5108 5111 5112 5110 5113 5082 5081 5084 5085 5078 5086 5106 5104 5103 5101 5097 5105 5085 5081 5078 5079 5077 5087 5077 5081 5080 5079 5086 5078 5084 5082 5085 5083 5081 5078 5082 5080 5087 5081 5079 5083 5108 5110 5101 5103 5109 5106 5083 5086 5081 5087 5077 5082 5078 5086 5081 5085 5084 5079 5081 5087 5080 5085 5086 5083 5106 5101 5102 5100 5099 5108 5116 5113 5106 5115 5112 5107 5116 5117 5122 5124 5119 5114 5080 5082 5077 5084 5085 5078 5077 5068 5076 5069 5072 5073 5111 5108 5112 5117 5116 5110 5093 5101 5103 5098 5094 5095 5082 5083 5086 5084 5087 5077 5104 5108 5110 5109 5112 5102 5087 5077 5078 5086 5083 5080 5082 5084 5087 5078 5083 5079 5086 5085 5084 5081 5082 5087 5104 5097 5100 5096 5105 5101 5079 5078 5087 5085 5086 5080 5112 5111 5116 5114 5110 5113 5087 5078 5080 5086 5079 5084 5083 5086 5080 5085 5079 5078 5088 5095 5089 5091 5098 5094 5081 5086 5084 5087 5083 5080 5078 5085 5080 5083 5084 5086 5116 5117 5109 5118 5110 5111 5079 5084 5087 5078 5086 5077 5119 5113 5121 5118 5112 5117 5086 5082 5078 5079 5077 5083 5097 5100 5094 5098 5102 5104 5077 5083 5079 5084 5086 5078 5106 5096 5101 5102 5105 5100 5082 5083 5081 5084 5077 5085 5078 5080 5079 5086 5081 5084 5115 5112 5113 5108 5111 5116 5083 5087 5079 5082 5084 5078 5084 5077 5085 5081 5083 5080 100 7044 7042 7043 7041 7046 7045 7041 7043 7046 7042 7045 7044 7046 7045 7043 7044 7041 7042 7046 7043 7045 7044 7042 7041 7045 7043 7042 7041 7044 7046 7046 7041 7044 7043 7045 7042 7041 7043 7046 7045 7044 7042 7044 7045 7046 7043 7042 7041 7041 7043 7046 7042 7045 7044 7043 7044 7045 7042 7046 7041 7045 7043 7044 7041 7046 7042 7042 7041 7044 7046 7043 7045 7042 7041 7044 7045 7043 7046 7042 7046 7043 7044 7041 7045 7045 7044 7041 7043 7046 7042 7043 7046 7042 7041 7045 7044 7044 7043 7046 7041 7045 7042 7041 7045 7043 7046 7044 7042 7045 7042 7046 7041 7043 7044 7045 7042 7043 7041 7046 7044 7041 7044 7045 7046 7042 7043 7042 7046 7045 7044 7041 7043 7043 7042 7044 7041 7045 7046 7043 7041 7045 7042 7046 7044 7045 7041 7044 7043 7042 7046 7041 7046 7043 7045 7042 7044 7042 7043 7041 7046 7044 7045 7044 7042 7041 7046 7045 7043 7044 7045 7043 7046 7042 7041 7046 7041 7042 7043 7045 7044 7041 7043 7042 7046 7045 7044 7043 7042 7044 7041 7046 7045 7043 7045 7044 7042 7046 7041 7041 7045 7043 7044 7042 7046 7042 7043 7044 7045 7046 7041 7041 7042 7043 7045 7044 7046 7042 7044 7041 7046 7045 7043 7045 7043 7044 7041 7042 7046 7043 7041 7046 7044 7045 7042 7044 7043 7041 7045 7046 7042 7042 7044 7046 7043 7045 7041 7042 7043 7041 7045 7044 7046 7043 7042 7046 7045 7044 7041 7045 7041 7042 7044 7046 7043 7042 7044 7046 7043 7045 7041 7041 7046 7044 7045 7043 7042 7043 7044 7046 7045 7041 7042 7041 7045 7044 7043 7046 7042 7041 7044 7043 7045 7046 7042 7043 7045 7046 7044 7042 7041 7041 7044 7043 7042 7045 7046 7046 7045 7041 7042 7044 7043 7041 7045 7044 7046 7042 7043 7041 7046 7042 7044 7043 7045 7046 7045 7041 7042 7043 7044 7046 7044 7042 7041 7043 7045 7043 7041 7042 7045 7046 7044 7044 7042 7046 7045 7041 7043 7043 7046 7042 7044 7045 7041 7041 7042 7044 7045 7046 7043 7043 7044 7042 7041 7045 7046 7046 7045 7043 7041 7044 7042 7046 7042 7043 7044 7041 7045 7046 7043 7044 7042 7041 7045 7043 7045 7041 7044 7046 7042 7044 7043 7042 7046 7045 7041 7045 7041 7044 7042 7043 7046 7042 7045 7046 7044 7043 7041 7042 7046 7043 7041 7045 7044 7042 7045 7044 7041 7043 7046 7045 7046 7042 7041 7043 7044 7046 7045 7043 7042 7041 7044 7045 7044 7042 7046 7041 7043 7042 7045 7041 7043 7046 7044 7045 7043 7041 7046 7042 7044 7041 7046 7042 7044 7043 7045 7046 7045 7041 7042 7043 7044 7041 7045 7043 7044 7042 7046 7043 7044 7042 7046 7045 7041 7043 7044 7042 7045 7046 7041 7044 7045 7043 7042 7041 7046 7044 7045 7043 7041 7042 7046 7044 7041 7046 7045 7042 7043 7045 7046 7041 7044 7043 7042 7043 7042 7044 7046 7045 7041 7043 7041 7042 7044 7045 7046 7043 7044 7046 7042 7041 7045 7044 7041 7042 7043 7045 7046 7041 7042 7046 7043 7045 7044 7043 7042 7045 7041 7044 7046 7043 7045 7042 7044 7046 7041 7045 7041 7044 7046 7043 7042 7041 7043 7042 7044 7045 7046 7042 7044 7045 7043 7046 7041 7042 7046 7043 7041 7045 7044 7044 7042 7041 7045 7043 7046 7042 7046 7041 7045 7044 7043 7041 7044 7042 7043 7045 7046 7041 7045 7043 7046 7044 7042 7045 7043 7041 7044 7042 7046 60 2474 2469 2471 2476 2459 2475 2469 2474 2476 2461 2466 2475 2474 2466 2465 2461 2470 2459 2478 2479 2467 2480 2473 2472 2465 2459 2466 2460 2461 2470 2469 2460 2471 2459 2475 2466 2462 2463 2472 2468 2478 2473 2460 2469 2466 2474 2475 2461 2476 2460 2474 2469 2466 2471 2462 2478 2473 2464 2467 2479 2461 2466 2475 2469 2476 2470 2479 2472 2473 2464 2478 2462 2470 2461 2471 2466 2476 2465 2470 2474 2461 2459 2469 2475 2466 2461 2475 2476 2460 2470 2474 2471 2460 2465 2466 2459 2471 2466 2465 2476 2469 2475 2459 2474 2469 2461 2475 2465 2471 2476 2475 2474 2461 2466 2472 2462 2479 2464 2463 2478 2465 2469 2461 2475 2460 2476 2472 2467 2478 2462 2479 2468 2465 2474 2470 2461 2460 2459 2464 2463 2477 2478 2467 2473 2475 2476 2466 2461 2465 2460 2462 2477 2468 2479 2472 2467 2470 2471 2465 2466 2461 2474 2474 2459 2466 2470 2475 2465 2464 2480 2463 2478 2479 2468 2461 2466 2476 2459 2475 2474 2479 2478 2467 2477 2472 2462 2465 2471 2476 2461 2469 2460 2466 2460 2470 2461 2476 2465 2474 2469 2471 2475 2470 2460 2468 2477 2464 2472 2480 2478 2461 2465 2469 2471 2470 2474 2459 2474 2461 2476 2460 2471 2476 2470 2469 2471 2474 2461 2465 2471 2461 2460 2474 2466 2476 2461 2471 2459 2470 2465 2471 2461 2459 2469 2470 2476 2472 2478 2480 2468 2473 2467 2476 2469 2461 2470 2460 2466 2479 2468 2463 2464 2467 2478 2474 2461 2465 2460 2466 2476 2463 2478 2468 2479 2464 2462 2465 2469 2459 2475 2461 2466 2476 2469 2474 2459 2470 2475 2459 2475 2476 2466 2471 2461 2460 2475 2474 2466 2465 2470 2473 2468 2467 2464 2472 2462 2472 2462 2477 2473 2478 2480 2477 2467 2479 2480 2462 2464 2459 2474 2466 2475 2461 2470 2468 2477 2479 2463 2467 2478 2462 2478 2477 2480 2464 2472 2473 2463 2478 2479 2472 2468 2474 2459 2465 2475 2466 2461 2476 2470 2475 2459 2474 2469 2470 2471 2461 2469 2474 2476 45 4988 4977 4983 4979 4984 4980 4981 4983 4977 4984 4980 4988 4979 4984 4981 4980 4988 4977 4978 4975 4982 4985 4986 4987 4984 4983 4981 4979 4977 4988 4980 4988 4983 4981 4979 4984 4987 4976 4975 4982 4985 4986 4982 4975 4976 4987 4978 4985 4985 4978 4986 4982 4976 4987 4984 4980 4979 4988 4983 4977 4988 4981 4984 4983 4980 4979 4977 4984 4980 4981 4983 4979 4987 4975 4986 4982 4978 4976 4980 4979 4988 4981 4983 4977 4980 4981 4983 4979 4984 4977 4985 4982 4975 4987 4986 4978 4978 4985 4982 4976 4987 4975 4984 4983 4981 4980 4988 4979 4980 4977 4984 4979 4988 4983 4977 4979 4981 4980 4984 4988 4983 4980 4984 4977 4979 4981 4987 4985 4976 4986 4982 4978 4975 4976 4987 4985 4986 4982 4984 4983 4977 4988 4980 4981 4979 4981 4988 4980 4977 4983 4981 4979 4983 4984 4977 4980 4983 4981 4980 4984 4977 4979 4975 4986 4987 4982 4976 4978 4979 4981 4983 4988 4984 4977 4983 4984 4979 4981 4988 4980 4983 4981 4979 4984 4980 4977 4979 4977 4984 4988 4980 4983 4979 4977 4988 4983 4980 4984 4983 4981 4979 4980 4977 4988 4988 4979 4983 4981 4980 4984 4987 4978 4986 4982 4976 4985 4988 4977 4979 4983 4980 4981 4982 4978 4975 4986 4985 4976 4978 4985 4986 4976 4975 4987 4981 4988 4977 4983 4984 4980 4977 4980 4983 4979 4988 4981 4988 4984 4979 4980 4977 4983 4987 4975 4978 4982 4976 4986 4977 4988 4980 4983 4981 4979 4987 4985 4986 4978 4975 4982 99 1793 1896 1807 1842 1810 1828 1822 1800 1757 1860 1768 1848 1823 1861 1856 1846 1813 1827 1810 1773 1893 1799 1770 1792 1859 1761 1780 1823 1866 1873 1815 1866 1838 1890 1823 1814 1846 1772 1843 1806 1848 1862 1880 1885 1776 1824 1840 1781 1806 1893 1802 1885 1852 1842 1807 1833 1900 1796 1830 1875 1767 1823 1824 1781 1840 1792 1880 1797 1798 1768 1869 1765 1833 1809 1857 1837 1892 1891 1892 1879 1768 1807 1845 1897 1901 1792 1867 1766 1866 1856 1819 1872 1789 1799 1757 1766 1882 1770 1802 1847 1799 1860 1780 1853 1784 1904 1869 1864 1884 1798 1835 1853 1759 1845 1784 1813 1765 1849 1877 1760 1780 1804 1772 1879 1822 1790 1821 1870 1762 1829 1884 1793 1900 1806 1809 1797 1888 1877 1811 1857 1822 1780 1806 1889 1866 1788 1885 1853 1881 1850 1845 1902 1766 1802 1833 1826 1845 1828 1826 1881 1806 1801 1862 1831 1900 1880 1877 1873 1760 1764 1811 1878 1805 1886 1888 1842 1894 1859 1884 1793 1794 1766 1888 1904 1760 1791 1762 1774 1812 1875 1903 1899 1834 1791 1799 1874 1851 1877 1892 1779 1836 1782 1897 1804 1799 1896 1889 1807 1843 1852 1867 1885 1789 1882 1833 1832 1887 1841 1851 1838 1785 1847 1874 1852 1876 1843 1880 1882 1787 1810 1893 1868 1805 1769 1768 1785 1773 1885 1860 1797 1826 1809 1786 1827 1892 1903 1814 1902 1806 1793 1837 1824 1811 1901 1762 1825 1775 1873 1873 1769 1761 1879 1865 1819 1825 1761 1789 1778 1837 1884 1870 1817 1849 1800 1903 1796 1897 1834 1798 1758 1837 1877 1780 1771 1870 1827 1869 1800 1892 1868 1871 1827 1835 1859 1794 1836 1864 1796 1873 1843 1875 1807 1864 1798 1865 1823 1858 1898 1833 1854 1820 1866 1902 1834 1790 1763 1796 1879 1819 1885 1903 1859 1894 1874 1832 1892 1857 1871 1837 1794 1896 1834 1890 1784 1887 1878 1771 1824 1892 1845 1885 1835 1839 1806 1886 1822 1766 1787 1780 1799 1787 1852 1771 1815 1759 1833 1888 1789 1896 1828 1781 1803 1863 1767 1871 1872 1776 1855 1826 1829 1834 1838 1879 1898 1860 1864 1901 1841 1794 1776 1896 1875 1782 1890 1803 1887 1819 1866 1867 1839 1869 1834 1844 1846 1850 1817 1860 1769 1846 1850 1889 1801 1839 1781 1799 1895 1761 1896 1773 1892 1799 1857 1820 1862 1791 1843 1807 1890 1811 1823 1785 1889 1794 1822 1814 1864 1758 1780 1841 1768 1861 1890 1856 1798 1794 1849 1824 1789 1886 1798 1768 1774 1879 1857 1796 1822 1883 1847 1785 1805 1766 1809 1885 1775 1763 1888 1889 1855 1789 1851 1832 1860 1900 1855 1835 1891 1834 1808 1845 1785 1789 1807 1776 1757 1795 1813 1862 1819 1846 1812 1807 1810 1760 1761 1882 1817 1837 1784 1770 1794 1904 1903 1827 1849 1784 1773 1837 1797 1824 1812 1878 1825 1820 1897 1765 1807 1827 1803 1874 1883 1847 1769 1830 1849 1831 1876 1888 1818 1884 1760 1770 1838 1778 1767 1821 1904 1895 1802 1800 1768 1783 1883 1851 1844 1862 1793 1871 1767 1892 1883 1800 1768 1884 1872 1772 1791 1830 1789 1881 1886 1786 1770 1816 1820 1765 1813 1895 1760 1774 1861 1769 1835 1764 1867 1762 1784 1780 1767 1823 1802 1830 1818 1828 1770 1780 1815 1881 1766 1874 1817 1784 1886 1784 1809 1796 1758 1838 1860 1833 1811 1889 1844 1843 1784 80 2737 2730 2731 2728 2734 2738 2727 2726 2736 2735 2732 2729 2733 2727 2729 2736 2735 2726 2728 2730 2734 2738 2731 2737 2731 2734 2730 2728 2738 2737 2727 2726 2733 2735 2732 2736 2734 2731 2728 2730 2737 2738 2732 2729 2727 2736 2735 2726 2731 2728 2734 2730 2738 2737 2730 2728 2734 2737 2738 2731 2730 2728 2734 2738 2731 2737 2730 2734 2738 2737 2728 2731 2728 2738 2737 2730 2731 2734 2733 2726 2736 2735 2729 2727 2738 2734 2731 2737 2730 2728 2735 2732 2733 2729 2726 2727 2731 2734 2730 2728 2738 2737 2737 2731 2728 2738 2730 2734 2730 2738 2728 2737 2731 2734 2735 2736 2733 2732 2727 2729 2733 2727 2736 2726 2735 2729 2730 2734 2731 2738 2728 2737 2732 2736 2735 2726 2729 2727 2735 2733 2726 2729 2732 2727 2727 2726 2733 2732 2736 2729 2730 2731 2728 2737 2734 2738 2734 2737 2738 2730 2728 2731 2733 2726 2727 2729 2736 2732 2730 2738 2734 2731 2728 2737 2731 2738 2728 2730 2734 2737 2727 2735 2732 2726 2729 2733 2736 2732 2733 2729 2726 2727 2728 2731 2738 2737 2734 2730 2735 2733 2732 2729 2726 2736 2738 2731 2730 2737 2728 2734 2733 2726 2736 2732 2727 2729 2730 2734 2738 2728 2731 2737 2735 2736 2726 2732 2729 2727 2737 2731 2734 2730 2728 2738 2733 2735 2727 2726 2732 2736 2727 2735 2733 2726 2732 2736 2733 2735 2732 2727 2736 2726 2728 2738 2737 2730 2734 2731 2728 2734 2730 2738 2731 2737 2736 2735 2726 2727 2729 2732 2738 2737 2734 2731 2728 2730 2737 2728 2731 2734 2738 2730 2731 2734 2737 2738 2728 2730 2732 2733 2736 2727 2735 2726 2734 2738 2731 2728 2737 2730 2735 2736 2733 2732 2727 2729 2734 2728 2730 2738 2731 2737 2730 2734 2731 2737 2738 2728 2734 2730 2738 2731 2728 2737 2731 2734 2728 2737 2738 2730 2735 2733 2732 2736 2726 2727 2727 2732 2729 2735 2726 2733 2734 2738 2728 2730 2731 2737 2726 2733 2735 2727 2729 2736 2728 2731 2730 2738 2734 2737 2732 2733 2727 2729 2736 2726 2735 2736 2727 2733 2729 2732 2736 2727 2729 2732 2726 2733 2733 2729 2735 2726 2736 2732 2736 2735 2726 2727 2729 2732 2737 2728 2730 2738 2731 2734 2738 2728 2737 2730 2734 2731 2732 2729 2726 2736 2733 2735 2730 2734 2737 2728 2738 2731 2729 2726 2733 2727 2736 2732 2726 2732 2735 2727 2729 2736 2729 2726 2732 2736 2733 2735 2735 2736 2726 2733 2727 2729 2737 2731 2728 2730 2734 2738 2726 2733 2727 2736 2735 2729 2731 2737 2730 2738 2728 2734 2727 2733 2735 2729 2726 2736 2730 2738 2728 2737 2731 2734 2733 2729 2726 2727 2736 2735 2733 2735 2726 2736 2732 2727 10 4483 4484 4486 4480 4485 4476 4480 4477 4476 4479 4482 4474 4480 4479 4481 4477 4486 4482 4474 4477 4482 4484 4481 4475 4488 4491 4486 4490 4487 4493 4483 4480 4475 4479 4481 4485 4495 4490 4489 4493 4487 4485 4490 4486 4494 4489 4488 4491 4488 4489 4495 4485 4492 4494 4490 4487 4488 4492 4485 4486 100 5764 5673 5739 5699 5668 5692 5663 5782 5766 5693 5683 5768 5730 5727 5796 5800 5670 5792 5666 5709 5800 5718 5773 5795 5685 5674 5666 5779 5698 5713 5713 5776 5719 5682 5669 5722 5738 5760 5713 5754 5787 5799 5680 5691 5772 5807 5778 5755 5682 5701 5727 5768 5681 5705 5724 5727 5798 5717 5764 5700 5693 5774 5736 5682 5759 5672 5717 5762 5763 5764 5801 5706 5698 5665 5706 5736 5724 5732 5769 5715 5767 5680 5756 5759 5792 5776 5716 5660 5724 5711 5730 5779 5677 5729 5778 5661 5802 5729 5775 5772 5780 5779 5773 5700 5805 5794 5695 5796 5786 5682 5738 5668 5687 5727 5720 5783 5805 5683 5718 5804 5800 5730 5759 5709 5660 5678 5779 5684 5774 5746 5711 5704 5742 5752 5685 5658 5682 5788 5701 5771 5689 5767 5762 5722 5702 5762 5687 5775 5771 5665 5674 5675 5756 5720 5740 5760 5714 5742 5802 5791 5775 5761 5660 5777 5717 5682 5720 5784 5791 5761 5722 5763 5772 5730 5680 5775 5705 5684 5679 5665 5745 5734 5717 5768 5780 5692 5766 5799 5705 5747 5738 5719 5702 5667 5800 5708 5743 5773 5659 5687 5672 5722 5752 5698 5687 5770 5734 5782 5658 5807 5725 5768 5757 5781 5747 5750 5673 5787 5743 5727 5718 5762 5673 5718 5788 5763 5760 5672 5673 5747 5665 5764 5685 5751 5756 5723 5802 5799 5778 5801 5806 5804 5781 5692 5777 5780 5699 5715 5708 5691 5799 5798 5689 5761 5702 5664 5718 5753 5778 5709 5807 5755 5667 5700 5661 5686 5770 5682 5659 5670 5696 5702 5764 5720 5697 5800 5673 5790 5719 5713 5806 5753 5690 5758 5747 5712 5692 5715 5683 5769 5687 5686 5744 5675 5689 5698 5704 5752 5757 5767 5706 5787 5744 5798 5704 5790 5795 5664 5668 5660 5800 5709 5697 5789 5699 5799 5695 5783 5783 5732 5738 5666 5779 5798 5804 5766 5777 5692 5699 5666 5761 5709 5786 5766 5739 5779 5784 5766 5735 5745 5737 5685 5728 5702 5707 5661 5678 5801 5806 5762 5749 5794 5754 5695 5751 5668 5712 5703 5760 5663 5751 5754 5752 5805 5779 5677 5736 5732 5661 5679 5678 5699 5758 5752 5730 5794 5723 5659 5731 5710 5726 5668 5658 5684 5800 5739 5666 5754 5685 5702 5712 5719 5682 5676 5692 5746 5695 5685 5688 5804 5701 5715 5712 5770 5756 5726 5772 5741 5695 5794 5680 5761 5697 5664 5750 5737 5699 5767 5806 5801 5803 5746 5677 5764 5789 5700 5771 5710 5700 5718 5684 5664 5743 5693 5746 5707 5780 5673 5729 5775 5707 5739 5660 5709 5769 5725 5715 5789 5799 5691 5738 5753 5715 5774 5758 5746 5782 5708 5716 5788 5709 5740 5698 5757 5684 5771 5769 5667 5672 5767 5779 5660 5683 5731 5744 5718 5734 5800 5766 5801 5708 5704 5711 5668 5745 5802 5705 5716 5798 5718 5763 5722 5719 5769 5694 5766 5787 5716 5709 5787 5670 5773 5669 5722 5754 5768 5714 5783 5712 5667 5760 5805 5786 5684 5780 5797 5803 5685 5748 5687 5765 5723 5705 5679 5779 5741 5805 5785 5751 5754 5790 5721 5722 5753 5766 5767 5713 5680 5755 5762 5661 5806 5666 5679 5747 5782 5684 5668 5757 5771 5720 5760 5775 5680 5729 5795 5665 5705 5699 5678 5740 5797 5724 5707 5707 5743 5766 5668 5750 5769 5765 5751 5779 5798 5665 5671 5709 5805 5774 5733 5782 5741 5736 5730 5773 5667 5693 5756 5800 5763 5699 5745 5714 5802 5796 5718 5747 5771 5685 5683 10 1180 1177 1175 1174 1178 1176 1177 1181 1173 1176 1179 1175 1176 1175 1173 1177 1174 1179 1179 1175 1174 1176 1180 1181 1176 1178 1174 1179 1175 1181 1176 1174 1181 1173 1177 1180 1177 1176 1178 1181 1180 1179 1180 1177 1173 1178 1181 1176 1176 1178 1181 1179 1177 1174 1174 1179 1177 1178 1176 1175 100 8213 8217 8211 8212 8218 8219 8217 8224 8223 8226 8220 8225 8185 8194 8190 8193 8192 8196 8204 8212 8210 8207 8202 8213 8194 8190 8196 8188 8185 8186 8197 8202 8195 8199 8204 8201 8194 8192 8187 8190 8196 8191 8189 8186 8185 8195 8190 8196 8189 8195 8191 8185 8196 8190 8216 8217 8218 8219 8214 8215 8191 8190 8192 8193 8197 8189 8184 8192 8194 8191 8193 8185 8193 8186 8196 8187 8189 8191 8195 8197 8191 8193 8192 8200 8196 8187 8190 8193 8191 8192 8178 8183 8172 8175 8180 8176 8193 8188 8192 8191 8190 8195 8196 8185 8187 8195 8186 8192 8196 8204 8195 8199 8193 8200 8201 8198 8205 8207 8203 8204 8191 8193 8187 8185 8188 8192 8214 8221 8217 8210 8218 8215 8223 8218 8225 8227 8224 8219 8195 8193 8196 8187 8194 8186 8213 8211 8206 8208 8212 8214 8214 8217 8216 8213 8208 8219 8187 8185 8193 8191 8186 8189 8183 8188 8182 8185 8178 8187 8195 8192 8194 8189 8196 8191 8195 8193 8185 8186 8194 8191 8188 8192 8193 8187 8186 8191 8225 8228 8219 8229 8224 8223 8173 8177 8174 8176 8175 8178 8195 8188 8189 8186 8193 8185 8194 8195 8191 8189 8192 8187 8192 8193 8196 8187 8190 8186 8193 8192 8191 8188 8186 8194 8220 8218 8221 8217 8224 8222 8185 8195 8187 8192 8193 8191 8187 8180 8190 8188 8184 8189 8195 8185 8190 8194 8187 8193 8193 8191 8196 8198 8197 8199 8193 8185 8189 8187 8188 8196 8187 8186 8189 8195 8190 8185 8181 8182 8186 8185 8191 8190 8189 8192 8195 8185 8187 8190 8191 8185 8196 8194 8188 8192 8189 8187 8196 8188 8193 8190 8225 8221 8219 8222 8214 8216 8196 8198 8199 8204 8194 8201 8182 8179 8183 8180 8177 8184 8195 8186 8196 8191 8194 8190 8177 8180 8175 8181 8183 8176 8207 8204 8208 8205 8206 8198 8196 8191 8188 8192 8186 8187 8192 8191 8187 8184 8186 8183 8186 8189 8187 8192 8195 8196 8193 8187 8195 8190 8188 8185 8185 8193 8188 8191 8189 8196 8193 8192 8196 8186 8189 8194 8201 8207 8210 8204 8212 8208 8191 8192 8185 8188 8194 8190 8196 8185 8195 8194 8191 8188 8189 8195 8187 8186 8185 8191 8193 8195 8187 8186 8190 8188 8185 8186 8193 8188 8187 8195 8198 8201 8197 8195 8192 8196 8192 8185 8187 8194 8188 8196 8186 8182 8177 8178 8179 8176 8196 8194 8193 8195 8198 8197 8191 8196 8195 8190 8188 8194 8186 8191 8188 8192 8187 8196 8222 8231 8228 8229 8230 8221 8208 8215 8204 8212 8210 8213 8187 8192 8195 8190 8186 8196 8217 8208 8209 8215 8214 8207 8196 8192 8191 8190 8186 8185 8226 8221 8231 8224 8225 8228 8191 8188 8186 8194 8192 8187 8195 8192 8186 8190 8191 8185 8187 8192 8188 8186 8190 8195 8192 8193 8196 8186 8188 8195 8190 8196 8186 8192 8194 8187 8192 8193 8195 8190 8185 8186 8188 8178 8185 8179 8187 8189 8190 8195 8196 8186 8185 8193 8216 8205 8215 8212 8214 8210 8195 8186 8193 8185 8189 8194 8183 8193 8191 8182 8190 8188 8190 8196 8197 8194 8188 8198 8185 8188 8189 8196 8186 8187 8214 8223 8221 8222 8219 8213 8203 8208 8211 8209 8204 8200 8223 8219 8224 8221 8226 8222 8217 8213 8220 8211 8215 8216 8194 8185 8192 8193 8187 8190 8205 8210 8200 8206 8202 8203 8188 8191 8190 8189 8192 8195 8206 8196 8201 8199 8204 8200 8204 8207 8211 8212 8206 8208 80 5565 5572 5571 5567 5568 5561 5564 5574 5569 5562 5573 5570 5571 5565 5561 5568 5572 5566 5561 5571 5572 5567 5565 5568 5569 5574 5562 5573 5560 5564 5572 5561 5571 5567 5565 5566 5567 5566 5572 5565 5571 5568 5567 5566 5571 5572 5565 5568 5574 5564 5560 5573 5563 5570 5563 5560 5564 5570 5574 5573 5571 5572 5567 5566 5561 5568 5571 5566 5567 5561 5565 5568 5567 5571 5566 5568 5561 5565 5565 5567 5566 5572 5571 5561 5566 5561 5565 5572 5567 5568 5570 5562 5574 5560 5569 5563 5565 5571 5566 5567 5561 5572 5560 5569 5573 5564 5563 5574 5562 5573 5570 5560 5564 5563 5565 5561 5568 5571 5566 5567 5567 5572 5568 5561 5571 5565 5571 5565 5568 5572 5566 5567 5570 5574 5569 5562 5573 5563 5567 5561 5568 5565 5566 5572 5566 5565 5571 5561 5572 5567 5574 5573 5562 5563 5570 5569 5563 5574 5570 5562 5573 5569 5570 5563 5569 5560 5574 5573 5566 5561 5568 5571 5572 5567 5573 5564 5560 5562 5574 5563 5562 5560 5564 5569 5563 5574 5562 5569 5564 5560 5574 5570 5570 5573 5564 5574 5562 5560 5572 5566 5571 5567 5565 5568 5569 5573 5560 5563 5574 5570 5562 5570 5563 5569 5573 5574 5560 5564 5569 5562 5570 5574 5565 5567 5568 5566 5572 5571 5570 5562 5560 5573 5564 5569 5569 5563 5573 5562 5564 5574 5561 5565 5568 5566 5571 5567 5560 5574 5564 5573 5570 5563 5562 5573 5569 5570 5560 5563 5560 5573 5570 5574 5564 5562 5566 5568 5567 5565 5571 5572 5561 5572 5565 5567 5568 5566 5565 5571 5572 5567 5566 5568 5562 5564 5563 5574 5560 5569 5560 5569 5573 5564 5574 5570 5573 5563 5564 5569 5562 5570 5568 5567 5561 5565 5566 5571 5573 5560 5574 5569 5563 5570 5567 5561 5572 5571 5565 5566 5561 5571 5567 5565 5572 5568 5560 5570 5569 5563 5564 5574 5568 5567 5566 5565 5572 5571 5569 5574 5563 5560 5562 5564 5571 5567 5572 5566 5565 5568 5574 5560 5573 5563 5562 5570 5572 5571 5566 5567 5561 5568 5561 5567 5572 5565 5566 5568 5561 5571 5567 5565 5568 5572 5570 5563 5574 5569 5562 5560 5568 5567 5565 5571 5572 5561 5560 5573 5563 5570 5574 5569 5569 5564 5560 5573 5562 5570 5570 5564 5574 5562 5573 5563 5566 5571 5567 5565 5561 5568 5568 5572 5567 5571 5566 5565 5566 5572 5571 5565 5561 5568 5563 5573 5570 5560 5564 5569 5572 5571 5568 5567 5566 5565 5568 5566 5561 5565 5567 5572 5570 5574 5562 5569 5563 5573 5566 5561 5571 5568 5565 5572 5574 5569 5562 5563 5573 5564 5569 5574 5570 5562 5563 5564 5562 5574 5563 5564 5573 5560 5563 5564 5569 5574 5573 5570 5568 5566 5565 5571 5567 5572 100 4737 4733 4735 4743 4741 4738 4733 4738 4735 4743 4736 4742 4743 4738 4735 4737 4734 4744 4733 4741 4742 4743 4737 4744 4735 4739 4733 4738 4734 4736 4733 4744 4740 4741 4738 4739 4735 4737 4744 4739 4743 4733 4737 4738 4742 4743 4740 4739 4738 4744 4734 4735 4733 4737 4742 4738 4739 4740 4744 4743 4737 4741 4735 4734 4733 4742 4738 4733 4736 4742 4741 4737 4739 4744 4736 4735 4743 4737 4738 4736 4735 4744 4733 4734 4739 4737 4742 4741 4733 4735 4734 4737 4739 4744 4741 4733 4737 4744 4742 4743 4739 4733 4736 4744 4734 4737 4743 4733 4743 4741 4733 4744 4734 4742 4740 4744 4739 4742 4736 4737 4733 4735 4739 4738 4734 4741 4738 4737 4733 4735 4744 4740 4733 4740 4743 4734 4737 4738 4738 4734 4740 4741 4735 4742 4737 4739 4733 4734 4740 4741 4739 4737 4742 4735 4734 4733 4743 4740 4733 4741 4744 4736 4741 4740 4733 4735 4743 4736 4736 4743 4734 4742 4733 4738 4734 4739 4736 4735 4741 4738 4738 4736 4743 4737 4741 4742 4739 4743 4735 4736 4741 4742 4744 4740 4736 4743 4741 4734 4736 4739 4742 4733 4744 4738 4736 4741 4735 4738 4743 4734 4740 4738 4733 4741 4736 4734 4742 4739 4740 4738 4744 4735 4735 4733 4742 4734 4743 4736 4733 4742 4736 4737 4744 4739 4735 4742 4744 4740 4736 4737 4733 4736 4744 4742 4738 4735 4736 4743 4738 4739 4737 4735 4735 4739 4744 4742 4740 4736 4737 4741 4744 4733 4736 4740 4741 4735 4743 4740 4737 4736 4733 4744 4740 4737 4735 4736 4740 4738 4739 4737 4743 4733 4744 4739 4736 4733 4741 4735 4736 4744 4735 4741 4738 4737 4744 4736 4743 4733 4734 4742 4740 4744 4736 4735 4743 4739 4734 4744 4743 4739 4742 4736 4737 4741 4744 4738 4734 4740 4736 4735 4740 4741 4743 4739 4740 4738 4741 4734 4739 4737 4739 4736 4737 4744 4743 4740 4734 4739 4744 4737 4743 4740 4744 4735 4737 4743 4739 4736 4740 4738 4743 4733 4734 4742 4739 4736 4740 4738 4742 4733 4740 4738 4737 4736 4739 4741 4742 4744 4735 4743 4741 4736 4737 4740 4739 4735 4738 4736 4738 4743 4741 4739 4744 4737 4736 4742 4739 4733 4737 4738 4741 4736 4733 4738 4739 4735 4740 4742 4735 4734 4736 4744 4735 4742 4744 4734 4741 4743 4739 4734 4743 4738 4742 4740 4744 4737 4741 4736 4740 4738 4740 4738 4743 4735 4742 4736 4733 4740 4737 4736 4743 4744 4742 4738 4733 4739 4743 4740 4742 4735 4737 4733 4741 4738 4734 4736 4740 4741 4737 4744 4735 4736 4738 4733 4740 4742 4744 4741 4737 4738 4739 4733 4738 4742 4736 4739 4743 4734 4741 4744 4735 4737 4736 4734 4735 4739 4740 4738 4743 4742 4736 4737 4739 4733 4738 4734 4742 4744 4743 4735 4738 4734 4740 4742 4737 4743 4733 4739 4741 4738 4736 4743 4742 4734 4743 4733 4744 4735 4738 4742 4738 4744 4743 4734 4742 4737 4740 4738 4739 4733 4744 4737 4733 4737 4736 4735 4739 4740 4737 4739 4742 4734 4744 4733 4736 4734 4738 4744 4739 4741 4738 4741 4743 4737 4744 4736 4742 4741 4738 4734 4737 4743 4735 4743 4744 4739 4733 4741 4741 4742 4734 4744 4740 4733 4736 4743 4737 4738 4735 4741 4735 4734 4736 4741 4733 4738 4742 4740 4741 4737 4738 4744 4733 4738 4742 4735 4743 4734 4740 4743 4733 4736 4735 4737 4741 4735 4734 4737 4736 4739 30 1085 1092 1088 1084 1093 1087 1095 1092 1089 1096 1088 1086 1083 1086 1085 1079 1087 1078 1091 1086 1085 1094 1088 1093 1094 1088 1091 1084 1090 1087 1087 1086 1092 1088 1093 1094 1080 1082 1079 1085 1087 1086 1075 1084 1082 1079 1076 1083 1085 1087 1088 1091 1086 1092 1083 1086 1088 1089 1080 1085 1093 1084 1085 1090 1088 1086 1078 1083 1084 1075 1076 1080 1076 1080 1072 1081 1075 1079 1089 1086 1088 1093 1090 1092 1084 1087 1090 1086 1088 1092 1087 1086 1091 1083 1090 1088 1073 1082 1078 1076 1080 1079 1093 1089 1092 1090 1091 1085 1086 1084 1092 1089 1087 1090 1092 1084 1093 1085 1090 1091 1091 1084 1083 1085 1092 1093 1084 1088 1087 1090 1089 1092 1089 1094 1093 1084 1091 1087 1083 1082 1091 1081 1089 1086 1084 1088 1093 1092 1087 1085 1088 1087 1085 1092 1089 1090 1086 1080 1082 1081 1084 1088 1089 1091 1086 1087 1095 1085 1086 1085 1081 1078 1080 1083 1091 1088 1085 1093 1094 1086 80 7455 7454 7451 7436 7437 7441 7437 7442 7454 7452 7448 7453 7448 7452 7436 7455 7440 7454 7440 7452 7454 7437 7451 7442 7447 7450 7457 7446 7449 7443 7438 7447 7439 7443 7446 7444 7444 7438 7446 7443 7447 7456 7457 7443 7444 7450 7439 7438 7446 7438 7450 7449 7457 7444 7456 7445 7449 7439 7435 7447 7445 7439 7435 7443 7447 7456 7443 7445 7447 7444 7446 7439 7437 7440 7453 7454 7455 7436 7442 7448 7440 7451 7452 7437 7454 7442 7437 7448 7440 7453 7449 7456 7435 7443 7445 7446 7437 7455 7440 7451 7441 7448 7435 7444 7457 7447 7446 7443 7440 7442 7448 7455 7441 7452 7436 7455 7441 7453 7454 7448 7454 7436 7442 7437 7453 7448 7438 7435 7444 7443 7449 7445 7441 7442 7440 7455 7448 7437 7446 7444 7439 7438 7449 7447 7452 7454 7437 7436 7451 7448 7450 7443 7449 7447 7445 7456 7451 7440 7453 7442 7436 7448 7438 7456 7450 7435 7443 7445 7447 7438 7444 7435 7456 7450 7441 7440 7437 7452 7453 7442 7437 7448 7451 7453 7440 7455 7443 7446 7439 7457 7447 7438 7450 7445 7444 7449 7457 7435 7450 7457 7446 7443 7439 7438 7440 7441 7453 7436 7451 7442 7444 7443 7456 7435 7450 7447 7449 7456 7443 7438 7446 7439 7446 7457 7447 7449 7456 7439 7453 7437 7455 7452 7451 7454 7451 7448 7453 7437 7440 7436 7443 7450 7447 7438 7446 7457 7440 7442 7441 7452 7436 7437 7439 7443 7445 7449 7456 7446 7454 7442 7441 7453 7448 7455 7439 7447 7449 7444 7456 7445 7449 7445 7446 7444 7438 7457 7457 7450 7447 7435 7446 7444 7454 7452 7437 7451 7453 7436 7451 7454 7436 7452 7440 7448 7453 7437 7442 7451 7455 7441 7448 7452 7442 7455 7454 7440 7444 7457 7456 7445 7447 7443 7438 7450 7457 7435 7439 7446 7455 7441 7452 7454 7448 7451 7450 7438 7445 7439 7444 7446 7454 7448 7453 7437 7436 7451 7453 7455 7452 7437 7454 7436 7443 7446 7435 7439 7457 7456 7438 7435 7446 7456 7444 7449 7455 7454 7436 7441 7448 7452 7456 7450 7435 7439 7445 7447 7454 7441 7448 7436 7452 7442 7455 7448 7436 7437 7441 7452 7438 7444 7445 7439 7446 7447 7441 7452 7453 7442 7437 7448 7442 7453 7454 7448 7441 7451 7445 7446 7447 7449 7435 7443 7454 7436 7455 7453 7440 7437 7441 7440 7437 7442 7452 7453 7445 7435 7457 7444 7446 7443 7454 7453 7455 7437 7451 7442 7447 7435 7456 7450 7439 7457 7457 7439 7446 7443 7444 7449 7450 7447 7438 7456 7435 7439 7441 7452 7453 7436 7440 7455 7450 7439 7457 7435 7443 7447 7448 7453 7440 7455 7441 7437 7452 7442 7437 7441 7451 7440 7440 7454 7453 7437 7442 7451 7447 7445 7457 7449 7456 7446 10 3282 3281 3279 3287 3277 3278 3286 3279 3280 3288 3285 3281 3280 3282 3278 3283 3288 3281 3281 3285 3288 3286 3282 3283 3279 3285 3278 3286 3281 3288 3284 3278 3280 3285 3279 3288 3281 3282 3284 3285 3287 3277 3285 3283 3284 3278 3287 3288 3287 3288 3277 3285 3283 3278 3281 3283 3278 3286 3285 3279 60 7803 7802 7808 7794 7807 7805 7807 7795 7809 7794 7806 7805 7799 7800 7813 7814 7792 7796 7804 7810 7799 7814 7811 7813 7807 7803 7809 7806 7812 7802 7813 7804 7810 7811 7798 7800 7811 7800 7798 7796 7792 7801 7805 7807 7809 7806 7794 7802 7795 7806 7794 7808 7802 7809 7813 7798 7799 7800 7801 7814 7794 7806 7795 7809 7793 7805 7800 7801 7804 7810 7797 7811 7812 7806 7794 7805 7793 7807 7795 7802 7809 7803 7793 7806 7796 7811 7813 7804 7810 7800 7793 7809 7795 7812 7802 7805 7806 7808 7812 7802 7805 7793 7814 7798 7813 7799 7804 7797 7794 7807 7802 7795 7808 7793 7798 7799 7804 7810 7797 7792 7799 7811 7800 7814 7796 7804 7806 7803 7807 7793 7802 7812 7809 7803 7805 7793 7795 7802 7812 7795 7807 7794 7803 7808 7792 7800 7799 7796 7813 7804 7797 7798 7796 7800 7792 7810 7808 7794 7805 7795 7803 7807 7808 7802 7794 7809 7793 7795 7795 7802 7812 7807 7809 7806 7801 7813 7811 7792 7810 7804 7810 7792 7814 7801 7811 7799 7809 7807 7803 7806 7793 7794 7800 7804 7796 7811 7801 7797 7812 7795 7809 7793 7806 7794 7798 7792 7799 7814 7813 7811 7804 7813 7792 7797 7801 7796 7804 7792 7798 7800 7811 7801 7793 7809 7805 7812 7806 7803 7808 7805 7794 7795 7803 7806 7802 7807 7805 7793 7806 7803 7797 7792 7814 7813 7798 7810 7805 7806 7807 7793 7803 7812 7807 7805 7802 7809 7806 7793 7812 7807 7809 7805 7793 7806 7811 7799 7801 7800 7797 7814 7813 7798 7796 7800 7792 7797 7796 7799 7811 7797 7798 7810 7811 7796 7797 7799 7801 7804 7806 7812 7802 7795 7803 7794 7814 7796 7813 7811 7800 7804 7792 7801 7797 7800 7813 7804 7795 7793 7808 7807 7805 7812 7806 7803 7794 7809 7805 7808 7814 7801 7792 7813 7800 7796 7814 7797 7799 7810 7798 7796 7813 7811 7814 7797 7792 7800 7792 7813 7798 7800 7814 7799 7814 7792 7811 7799 7800 7796 7808 7795 7794 7812 7793 7809 7793 7795 7803 7794 7806 7808 100 5295 5294 5303 5293 5306 5297 5305 5304 5307 5300 5302 5296 5299 5302 5300 5307 5296 5304 5303 5306 5297 5294 5293 5295 5293 5303 5294 5301 5306 5295 5301 5303 5297 5295 5306 5293 5295 5306 5301 5294 5297 5303 5295 5293 5294 5306 5297 5303 5306 5293 5303 5301 5294 5295 5294 5301 5297 5306 5295 5303 5302 5299 5298 5296 5307 5304 5301 5306 5295 5293 5303 5297 5295 5294 5303 5293 5306 5297 5303 5294 5301 5297 5293 5306 5296 5307 5302 5300 5299 5304 5300 5304 5298 5302 5305 5296 5300 5299 5307 5304 5305 5302 5299 5307 5305 5296 5300 5304 5295 5293 5297 5303 5301 5306 5303 5301 5306 5295 5297 5294 5293 5294 5295 5301 5306 5297 5299 5307 5304 5296 5300 5298 5305 5298 5307 5300 5299 5296 5307 5305 5298 5304 5302 5296 5303 5294 5306 5301 5295 5293 5297 5293 5294 5303 5306 5301 5301 5306 5295 5293 5294 5297 5296 5300 5299 5305 5302 5298 5293 5295 5297 5301 5294 5306 5304 5302 5307 5305 5298 5299 5295 5297 5294 5306 5293 5303 5299 5307 5305 5304 5302 5296 5304 5300 5299 5298 5296 5305 5295 5294 5293 5297 5303 5301 5295 5293 5301 5297 5294 5303 5303 5293 5306 5297 5294 5301 5293 5303 5295 5297 5301 5306 5296 5307 5304 5305 5298 5299 5296 5298 5305 5300 5307 5302 5306 5294 5301 5295 5293 5297 5300 5305 5299 5298 5296 5302 5306 5301 5303 5297 5293 5294 5305 5307 5300 5304 5299 5296 5293 5301 5303 5295 5306 5294 5296 5305 5302 5307 5300 5298 5300 5304 5305 5298 5296 5299 5304 5305 5300 5299 5302 5298 5307 5302 5305 5296 5299 5298 5304 5296 5300 5298 5305 5307 5302 5307 5304 5299 5300 5296 5294 5301 5293 5303 5297 5306 5301 5297 5293 5295 5303 5294 5296 5300 5298 5302 5307 5305 5300 5298 5296 5305 5307 5304 5304 5302 5305 5299 5307 5298 5302 5298 5304 5296 5307 5300 5302 5300 5296 5298 5307 5305 5294 5297 5295 5301 5303 5293 5301 5295 5293 5303 5306 5294 5304 5302 5307 5296 5300 5299 5293 5301 5294 5297 5295 5303 5299 5304 5302 5307 5300 5298 5305 5304 5307 5299 5302 5298 5297 5306 5301 5293 5294 5303 5307 5304 5300 5305 5302 5296 5304 5302 5305 5300 5307 5299 5294 5295 5297 5306 5293 5301 5296 5304 5302 5299 5305 5298 5296 5299 5298 5300 5305 5304 5303 5293 5301 5297 5294 5306 5307 5305 5298 5304 5299 5296 5303 5306 5295 5294 5293 5297 5297 5293 5303 5301 5294 5295 5307 5298 5296 5302 5304 5299 5307 5299 5302 5305 5304 5296 5299 5307 5304 5305 5302 5298 5306 5295 5297 5294 5303 5301 5303 5306 5297 5301 5293 5295 5302 5304 5299 5307 5296 5305 5294 5295 5303 5306 5297 5301 5306 5294 5301 5303 5293 5297 5302 5304 5307 5296 5300 5299 5302 5296 5300 5298 5307 5299 5303 5297 5306 5294 5301 5295 5306 5293 5301 5303 5297 5294 5299 5300 5302 5304 5298 5296 5305 5307 5304 5296 5298 5300 5295 5303 5301 5294 5306 5293 5303 5295 5293 5294 5297 5301 5300 5299 5305 5296 5307 5302 5305 5302 5307 5299 5300 5296 5301 5295 5306 5297 5303 5294 5307 5305 5302 5299 5298 5296 5293 5294 5306 5297 5295 5303 5304 5299 5302 5305 5307 5300 5295 5294 5306 5303 5301 5293 5307 5296 5300 5304 5298 5305 5294 5297 5306 5293 5295 5301 5301 5297 5306 5293 5294 5303 5303 5301 5293 5294 5295 5297 60 7192 7179 7172 7184 7180 7183 7173 7180 7183 7182 7171 7184 7192 7173 7184 7193 7171 7183 7179 7183 7180 7172 7192 7193 7175 7174 7170 7188 7176 7191 7191 7190 7175 7176 7186 7170 7182 7179 7171 7183 7189 7173 7174 7176 7177 7170 7190 7191 7171 7192 7183 7189 7187 7184 7173 7189 7184 7180 7172 7187 7185 7190 7170 7178 7175 7176 7187 7184 7173 7193 7182 7189 7170 7188 7175 7181 7174 7190 7176 7188 7175 7174 7170 7177 7182 7184 7180 7183 7187 7171 7181 7186 7191 7177 7178 7170 7187 7184 7193 7192 7183 7179 7176 7181 7178 7177 7185 7188 7170 7186 7185 7181 7177 7190 7180 7187 7183 7179 7192 7189 7193 7180 7192 7182 7184 7183 7173 7192 7179 7193 7184 7171 7180 7193 7183 7192 7173 7172 7171 7173 7180 7192 7193 7183 7189 7183 7180 7184 7173 7179 7174 7181 7177 7188 7176 7185 7193 7171 7182 7189 7180 7192 7179 7171 7182 7193 7189 7172 7182 7173 7193 7187 7189 7180 7183 7180 7189 7171 7184 7172 7192 7180 7179 7172 7171 7183 7189 7184 7179 7171 7173 7180 7193 7182 7171 7179 7184 7183 7179 7189 7184 7182 7180 7173 7175 7190 7178 7181 7186 7176 7176 7178 7188 7186 7175 7185 7189 7179 7180 7193 7187 7182 7170 7185 7176 7181 7191 7177 7173 7189 7179 7182 7192 7171 7182 7187 7173 7192 7172 7193 7180 7193 7183 7182 7189 7179 7188 7175 7185 7174 7170 7186 7189 7187 7172 7183 7173 7182 7192 7171 7187 7184 7183 7173 7189 7173 7187 7179 7180 7192 7183 7180 7179 7171 7182 7187 7188 7191 7181 7190 7174 7176 7179 7192 7187 7173 7193 7171 7172 7171 7184 7179 7193 7182 7182 7193 7179 7172 7189 7187 7188 7175 7176 7186 7178 7191 7182 7173 7184 7192 7180 7183 7170 7185 7178 7186 7175 7174 7184 7182 7187 7171 7189 7179 7193 7180 7187 7183 7182 7173 7185 7176 7186 7181 7170 7174 7180 7187 7173 7189 7183 7184 7185 7181 7188 7178 7174 7190 7176 7188 7174 7181 7190 7178 7184 7183 7171 7172 7179 7187 2 6265 6268 6270 6266 6267 6269 6265 6270 6267 6266 6269 6268 60 7022 7028 7020 7016 7026 7027 7023 7024 7025 7017 7019 7021 7025 7018 7017 7024 7021 7019 7023 7021 7017 7018 7024 7019 7026 7028 7022 7027 7016 7020 7020 7027 7016 7028 7026 7022 7022 7028 7020 7016 7027 7026 7026 7022 7016 7028 7027 7020 7020 7016 7026 7028 7022 7027 7024 7019 7025 7017 7021 7018 7016 7020 7026 7027 7028 7022 7025 7024 7018 7021 7019 7023 7027 7028 7026 7020 7016 7022 7028 7027 7022 7020 7016 7026 7021 7017 7025 7018 7019 7024 7026 7020 7027 7028 7022 7016 7028 7027 7022 7026 7016 7020 7020 7016 7028 7026 7022 7027 7020 7022 7016 7028 7026 7027 7020 7028 7022 7027 7026 7016 7024 7023 7019 7025 7018 7017 7027 7026 7020 7028 7022 7016 7026 7028 7027 7020 7016 7022 7021 7018 7017 7024 7023 7025 7028 7026 7016 7020 7027 7022 7016 7026 7022 7027 7028 7020 7024 7018 7021 7017 7019 7023 7025 7019 7024 7017 7021 7018 7019 7017 7018 7024 7025 7023 7025 7023 7018 7019 7017 7024 7023 7021 7025 7024 7018 7017 7017 7019 7018 7023 7025 7024 7016 7022 7020 7027 7028 7026 7022 7028 7016 7020 7027 7026 7027 7026 7022 7020 7028 7016 7026 7022 7020 7028 7027 7016 7024 7017 7018 7021 7019 7023 7026 7020 7016 7022 7028 7027 7024 7017 7021 7019 7018 7023 7024 7018 7025 7023 7021 7017 7023 7021 7018 7019 7017 7025 7025 7023 7021 7017 7018 7019 7026 7020 7027 7028 7022 7016 7021 7024 7017 7019 7023 7018 7023 7018 7025 7017 7021 7019 7020 7028 7026 7016 7027 7022 7028 7020 7026 7027 7022 7016 7028 7020 7016 7026 7027 7022 7023 7019 7025 7017 7021 7018 7021 7018 7023 7017 7024 7019 7019 7023 7024 7018 7021 7025 7027 7028 7022 7020 7026 7016 7022 7026 7016 7027 7028 7020 7016 7028 7022 7020 7026 7027 7018 7017 7019 7021 7023 7024 7023 7018 7025 7024 7019 7021 7021 7018 7025 7024 7017 7023 7018 7023 7025 7024 7019 7021 7025 7018 7024 7019 7017 7021 7021 7017 7024 7018 7023 7019 100 5275 5233 5251 5298 5240 5217 5284 5172 5174 5272 5204 5276 5245 5177 5275 5248 5174 5290 5237 5269 5170 5261 5229 5172 5260 5236 5204 5244 5238 5264 5207 5299 5300 5311 5281 5309 5295 5254 5256 5199 5210 5241 5306 5197 5283 5302 5219 5225 5187 5256 5315 5180 5194 5305 5309 5287 5220 5288 5232 5308 5300 5271 5189 5284 5180 5225 5256 5234 5181 5309 5306 5209 5304 5208 5293 5195 5188 5300 5211 5207 5181 5306 5272 5201 5314 5190 5197 5182 5298 5181 5228 5313 5199 5274 5288 5230 5170 5224 5283 5273 5296 5213 5313 5219 5249 5265 5278 5204 5280 5252 5223 5295 5225 5191 5257 5242 5179 5175 5262 5202 5275 5170 5282 5284 5292 5283 5299 5255 5304 5249 5290 5307 5242 5223 5289 5311 5221 5263 5279 5308 5194 5301 5222 5179 5298 5248 5307 5209 5249 5285 5212 5206 5226 5241 5221 5308 5253 5270 5233 5170 5245 5189 5278 5267 5217 5191 5306 5209 5173 5242 5257 5277 5311 5310 5218 5246 5217 5240 5305 5198 5299 5209 5243 5272 5276 5194 5208 5291 5220 5295 5194 5185 5174 5237 5178 5186 5235 5315 5225 5218 5229 5314 5299 5183 5202 5269 5234 5281 5168 5193 5251 5215 5229 5172 5176 5190 5256 5220 5176 5217 5200 5277 5292 5191 5286 5174 5302 5217 5260 5171 5175 5169 5168 5262 5293 5303 5228 5249 5193 5179 5276 5190 5219 5316 5295 5207 5172 5212 5211 5219 5246 5177 5286 5259 5191 5246 5293 5283 5285 5186 5216 5180 5235 5197 5178 5290 5170 5300 5194 5280 5200 5248 5238 5172 5228 5253 5183 5260 5202 5199 5255 5225 5184 5226 5294 5307 5190 5297 5257 5304 5236 5200 5289 5180 5241 5249 5216 5289 5279 5256 5215 5186 5232 5251 5283 5175 5191 5216 5209 5206 5284 5309 5265 5299 5276 5244 5171 5258 5270 5315 5313 5238 5265 5295 5262 5316 5268 5207 5218 5294 5215 5239 5266 5250 5272 5222 5204 5196 5285 5271 5197 5280 5269 5236 5313 5287 5246 5275 5307 5226 5291 5249 5199 5250 5206 5265 5211 5227 5184 5174 5301 5214 5168 5265 5184 5302 5214 5167 5241 5246 5303 5313 5314 5204 5264 5221 5203 5180 5294 5256 5310 5293 5301 5278 5225 5173 5223 5274 5175 5174 5241 5274 5222 5272 5286 5171 5256 5222 5171 5268 5301 5266 5273 5301 5264 5316 5213 5205 5266 5288 5291 5296 5220 5316 5310 5294 5228 5235 5168 5272 5200 5224 5279 5300 5302 5305 5295 5263 5253 5242 5278 5288 5233 5184 5310 5226 5224 5270 5238 5235 5237 5213 5185 5214 5294 5290 5174 5312 5314 5187 5244 5178 5226 5284 5315 5221 5203 5305 5226 5285 5262 5284 5204 5243 5260 5290 5221 5217 5211 5271 5216 5196 5236 5201 5173 5266 5272 5246 5299 5234 5312 5224 5309 5172 5223 5175 5232 5315 5307 5290 5206 5279 5297 5172 5205 5311 5239 5250 5279 5193 5276 5207 5222 5238 5215 5236 5196 5197 5291 5191 5167 5207 5196 5256 5217 5248 5245 5239 5232 5263 5266 5305 5287 5244 5285 5229 5295 5245 5211 5233 5314 5213 5305 5254 5258 5313 5219 5231 5205 5225 5255 5278 5312 5207 5249 5280 5260 5201 5202 5306 5209 5182 5214 5204 5195 5225 5289 5267 5174 5306 5193 5252 5229 5182 5241 5304 5278 5198 5205 5231 5167 5256 5240 5284 5311 5223 5300 5172 5216 5298 5176 5199 5296 5285 5249 5232 5284 5259 5241 5259 5273 5301 5186 5193 5314 5183 5214 5280 5294 5254 60 5101 5094 5090 5091 5097 5096 5097 5091 5101 5096 5090 5094 5098 5093 5099 5095 5100 5092 5095 5100 5092 5093 5098 5099 5096 5094 5090 5101 5097 5091 5091 5101 5096 5097 5094 5090 5090 5101 5096 5097 5094 5091 5101 5096 5094 5091 5090 5097 5095 5092 5099 5098 5093 5100 5094 5090 5096 5097 5101 5091 5100 5095 5098 5093 5099 5092 5098 5099 5093 5092 5095 5100 5096 5094 5101 5090 5091 5097 5095 5098 5099 5092 5100 5093 5096 5094 5091 5101 5097 5090 5099 5092 5098 5095 5093 5100 5096 5097 5101 5091 5094 5090 5101 5090 5094 5096 5097 5091 5101 5090 5096 5091 5094 5097 5097 5101 5096 5094 5090 5091 5097 5090 5091 5096 5094 5101 5093 5095 5100 5098 5099 5092 5096 5101 5091 5090 5097 5094 5092 5098 5095 5100 5093 5099 5090 5096 5094 5091 5101 5097 5091 5090 5097 5096 5101 5094 5096 5094 5097 5091 5101 5090 5094 5096 5090 5097 5091 5101 5094 5096 5091 5097 5101 5090 5099 5100 5092 5098 5095 5093 5095 5093 5092 5098 5099 5100 5090 5091 5101 5096 5094 5097 5101 5096 5097 5090 5091 5094 5094 5097 5090 5101 5091 5096 5097 5090 5091 5094 5096 5101 5090 5101 5097 5094 5096 5091 5097 5096 5090 5094 5101 5091 5095 5098 5099 5093 5092 5100 5099 5092 5093 5095 5098 5100 5093 5099 5100 5098 5095 5092 5090 5091 5097 5094 5096 5101 5095 5092 5098 5100 5093 5099 5091 5097 5094 5090 5096 5101 5093 5099 5095 5100 5092 5098 5090 5096 5094 5097 5091 5101 5090 5091 5094 5101 5097 5096 5101 5094 5097 5096 5091 5090 5101 5094 5096 5090 5091 5097 5092 5098 5093 5100 5095 5099 5096 5094 5097 5101 5090 5091 5090 5097 5096 5101 5094 5091 5093 5100 5092 5099 5095 5098 5090 5091 5094 5096 5101 5097 5094 5096 5101 5091 5090 5097 5091 5101 5094 5090 5096 5097 5094 5101 5090 5091 5096 5097 5098 5093 5099 5100 5092 5095 5091 5097 5090 5096 5094 5101 5097 5091 5101 5096 5090 5094 5092 5095 5093 5098 5100 5099 10 9945 9946 9947 9944 9949 9948 9945 9948 9947 9949 9946 9944 9947 9948 9949 9946 9945 9944 9944 9948 9949 9946 9947 9945 9944 9945 9948 9949 9946 9947 9948 9947 9944 9945 9946 9949 9948 9949 9946 9947 9944 9945 9947 9949 9944 9948 9945 9946 9945 9944 9946 9947 9948 9949 9949 9944 9946 9948 9945 9947 10 5406 5411 5409 5404 5407 5412 5404 5408 5398 5406 5399 5403 5408 5403 5410 5405 5402 5412 5409 5404 5410 5402 5403 5405 5409 5399 5405 5407 5408 5402 5408 5413 5414 5411 5416 5417 5411 5414 5409 5413 5406 5412 5408 5410 5407 5409 5414 5411 5404 5412 5414 5405 5409 5413 5400 5403 5401 5405 5409 5406 75 8665 8671 8662 8658 8669 8663 8661 8670 8668 8660 8655 8656 8657 8656 8670 8668 8659 8655 8666 8665 8664 8663 8667 8669 8665 8658 8666 8663 8671 8662 8658 8665 8662 8667 8664 8671 8660 8668 8657 8661 8654 8659 8668 8670 8656 8657 8654 8661 8664 8663 8666 8662 8671 8667 8655 8656 8660 8654 8657 8670 8659 8660 8656 8654 8655 8657 8654 8660 8670 8655 8668 8661 8654 8670 8660 8655 8656 8661 8669 8662 8664 8663 8671 8658 8668 8659 8670 8661 8654 8660 8654 8661 8668 8660 8659 8670 8671 8669 8658 8665 8666 8662 8655 8668 8656 8660 8670 8657 8659 8668 8661 8655 8660 8657 8666 8658 8662 8667 8663 8665 8668 8659 8660 8656 8661 8670 8665 8669 8664 8667 8663 8662 8669 8663 8667 8658 8665 8664 8657 8659 8661 8654 8656 8655 8665 8671 8662 8658 8669 8666 8658 8667 8664 8663 8666 8669 8670 8661 8659 8660 8656 8668 8657 8655 8670 8654 8659 8668 8669 8662 8665 8671 8667 8666 8654 8659 8661 8660 8657 8668 8656 8660 8670 8655 8657 8661 8661 8659 8668 8670 8656 8654 8659 8656 8668 8654 8660 8661 8668 8657 8660 8654 8656 8670 8661 8659 8670 8660 8654 8657 8670 8668 8654 8655 8660 8661 8656 8668 8654 8661 8660 8657 8660 8657 8659 8668 8655 8670 8657 8670 8660 8655 8661 8656 8669 8662 8664 8666 8667 8658 8661 8655 8660 8659 8656 8657 8657 8654 8660 8655 8661 8670 8664 8663 8669 8671 8665 8667 8667 8666 8662 8671 8669 8663 8669 8671 8662 8663 8666 8665 8662 8664 8658 8666 8669 8663 8656 8657 8670 8668 8660 8655 8660 8657 8670 8655 8661 8654 8663 8671 8662 8664 8658 8669 8655 8661 8659 8668 8660 8656 8661 8659 8656 8657 8660 8655 8660 8661 8657 8659 8668 8654 8665 8664 8662 8671 8669 8666 8655 8656 8659 8654 8660 8661 8663 8662 8666 8669 8664 8671 8668 8670 8657 8654 8659 8660 8655 8656 8654 8657 8659 8660 8660 8668 8661 8670 8655 8659 8654 8655 8670 8660 8661 8656 8657 8661 8654 8670 8668 8655 8670 8661 8668 8654 8657 8656 8663 8671 8669 8664 8667 8665 8667 8665 8664 8669 8658 8666 8654 8660 8661 8655 8668 8657 8670 8660 8656 8654 8655 8657 8670 8660 8655 8657 8656 8668 8657 8656 8668 8655 8654 8661 8660 8661 8659 8656 8654 8655 8659 8656 8655 8670 8661 8668 8664 8658 8667 8666 8665 8669 8662 8671 8664 8663 8666 8667 8656 8668 8659 8654 8657 8655 8661 8660 8655 8657 8656 8670 8670 8668 8656 8655 8660 8654 8654 8659 8670 8668 8656 8660 10 8386 8388 8385 8389 8387 8390 8385 8384 8387 8383 8386 8388 8392 8395 8393 8394 8391 8397 8388 8390 8389 8384 8385 8386 8389 8387 8388 8392 8391 8386 8392 8393 8396 8395 8394 8391 8394 8395 8393 8396 8397 8392 8396 8394 8397 8393 8391 8395 8391 8390 8387 8392 8388 8389 8394 8395 8397 8393 8392 8396 75 8892 8889 8897 8888 8893 8899 8892 8888 8893 8899 8889 8897 8892 8893 8888 8889 8899 8897 8895 8898 8896 8891 8890 8894 8894 8890 8895 8891 8898 8896 8894 8890 8895 8896 8898 8891 8893 8899 8889 8897 8892 8888 8891 8894 8898 8896 8890 8895 8892 8899 8888 8889 8897 8893 8899 8897 8893 8892 8888 8889 8893 8897 8892 8889 8888 8899 8891 8898 8890 8896 8895 8894 8896 8890 8898 8894 8895 8891 8896 8891 8894 8895 8890 8898 8890 8895 8896 8894 8898 8891 8893 8899 8889 8897 8888 8892 8894 8898 8895 8890 8891 8896 8896 8894 8898 8890 8891 8895 8895 8896 8894 8898 8890 8891 8899 8889 8897 8888 8892 8893 8898 8894 8890 8891 8896 8895 8888 8892 8889 8893 8899 8897 8893 8889 8892 8897 8899 8888 8891 8894 8896 8895 8898 8890 8893 8899 8889 8888 8892 8897 8892 8893 8897 8899 8888 8889 8895 8896 8891 8894 8898 8890 8890 8895 8894 8898 8891 8896 8893 8888 8897 8892 8889 8899 8896 8895 8891 8898 8890 8894 8893 8889 8892 8888 8897 8899 8897 8893 8892 8899 8888 8889 8889 8899 8897 8888 8893 8892 8894 8895 8898 8890 8891 8896 8896 8890 8894 8898 8891 8895 8899 8892 8897 8889 8893 8888 8893 8889 8899 8897 8892 8888 8899 8897 8893 8889 8888 8892 8899 8888 8897 8892 8889 8893 8894 8896 8890 8898 8891 8895 8890 8898 8895 8896 8894 8891 8894 8891 8890 8898 8896 8895 8893 8888 8892 8897 8889 8899 8888 8892 8889 8897 8899 8893 8889 8892 8897 8893 8899 8888 8892 8897 8889 8893 8888 8899 8892 8899 8893 8888 8897 8889 8899 8888 8893 8889 8897 8892 8889 8892 8888 8893 8899 8897 8890 8898 8896 8891 8895 8894 8897 8889 8893 8892 8899 8888 8888 8893 8899 8889 8892 8897 8897 8899 8888 8893 8889 8892 8891 8894 8896 8898 8890 8895 8897 8892 8889 8893 8899 8888 8897 8899 8893 8892 8889 8888 8897 8899 8893 8889 8892 8888 8888 8899 8893 8897 8889 8892 8889 8892 8897 8899 8888 8893 8890 8896 8891 8894 8895 8898 8888 8892 8893 8889 8897 8899 8897 8888 8893 8892 8889 8899 8899 8897 8888 8892 8889 8893 8899 8893 8888 8897 8889 8892 8897 8888 8889 8893 8899 8892 8893 8889 8892 8888 8899 8897 8892 8889 8899 8897 8893 8888 8891 8894 8890 8896 8895 8898 8893 8892 8897 8899 8888 8889 8899 8889 8893 8888 8892 8897 8889 8899 8888 8897 8893 8892 8889 8892 8899 8893 8888 8897 8889 8897 8892 8893 8899 8888 8897 8892 8889 8888 8899 8893 8888 8889 8892 8893 8899 8897 60 4172 4168 4150 4161 4157 4159 4150 4153 4167 4148 4157 4161 4148 4172 4159 4157 4153 4167 4163 4161 4172 4150 4167 4153 4149 4154 4165 4162 4158 4152 4166 4170 4152 4154 4169 4158 4167 4150 4153 4168 4157 4172 4149 4164 4165 4169 4160 4162 4167 4156 4150 4157 4161 4159 4164 4166 4149 4160 4155 4158 4157 4171 4151 4167 4148 4161 4161 4168 4148 4171 4163 4157 4170 4164 4162 4169 4166 4158 4149 4154 4164 4152 4166 4160 4151 4172 4156 4161 4167 4157 4168 4171 4153 4159 4148 4156 4155 4166 4160 4149 4165 4162 4148 4171 4172 4156 4167 4151 4151 4171 4156 4159 4172 4157 4163 4159 4161 4153 4167 4156 4160 4162 4155 4154 4158 4152 4167 4151 4168 4157 4172 4153 4153 4172 4148 4168 4161 4151 4164 4170 4160 4154 4155 4162 4156 4159 4163 4148 4151 4168 4164 4162 4152 4149 4154 4158 4155 4169 4166 4164 4149 4160 4171 4148 4172 4159 4156 4167 4159 4156 4157 4161 4153 4151 4172 4148 4161 4171 4163 4156 4160 4155 4154 4152 4158 4164 4163 4171 4159 4156 4148 4153 4158 4169 4155 4166 4152 4170 4170 4162 4158 4165 4169 4152 4167 4148 4150 4172 4157 4156 4162 4158 4165 4160 4170 4155 4151 4157 4150 4163 4148 4172 4162 4170 4165 4149 4169 4155 4153 4168 4148 4171 4157 4159 4149 4169 4164 4155 4154 4170 4164 4162 4166 4165 4158 4154 4166 4155 4162 4160 4170 4158 4161 4153 4168 4148 4151 4163 4170 4162 4154 4160 4158 4166 4150 4157 4153 4161 4156 4168 4169 4152 4158 4164 4170 4165 4155 4152 4170 4154 4149 4160 4156 4168 4157 4161 4151 4172 4165 4158 4164 4170 4155 4166 4162 4170 4158 4165 4160 4149 4155 4160 4165 4154 4152 4162 4170 4162 4165 4166 4149 4160 4159 4168 4161 4151 4150 4153 4168 4172 4151 4163 4159 4167 4163 4161 4172 4150 4156 4168 4165 4154 4160 4164 4152 4169 4166 4158 4165 4170 4152 4169 4155 4160 4149 4162 4152 4158 4170 4166 4160 4155 4162 4154 4156 4171 4153 4172 4159 4168 10 7302 7303 7305 7307 7306 7304 7307 7306 7302 7303 7304 7305 7303 7305 7302 7306 7307 7304 7296 7299 7300 7301 7298 7297 7304 7302 7306 7303 7305 7307 7296 7300 7297 7295 7299 7298 7299 7301 7300 7304 7302 7303 7301 7300 7303 7298 7302 7299 7305 7306 7303 7307 7302 7304 7299 7298 7297 7301 7300 7302 30 1475 1473 1476 1481 1477 1478 1476 1478 1474 1472 1469 1471 1486 1481 1482 1483 1479 1488 1476 1478 1479 1475 1472 1480 1465 1466 1461 1467 1469 1459 1466 1471 1465 1469 1472 1464 1467 1463 1469 1466 1461 1460 1466 1470 1467 1474 1476 1468 1487 1486 1483 1484 1489 1491 1485 1488 1481 1486 1484 1491 1475 1470 1466 1473 1474 1471 1486 1488 1479 1480 1485 1484 1463 1460 1459 1462 1458 1467 1484 1486 1494 1490 1492 1489 1487 1490 1493 1489 1495 1496 1472 1475 1468 1467 1477 1470 1470 1473 1474 1468 1471 1477 1469 1463 1464 1471 1466 1468 1485 1478 1481 1483 1479 1484 1483 1477 1482 1485 1480 1478 1490 1488 1487 1486 1485 1480 1461 1469 1470 1462 1468 1471 1480 1474 1484 1481 1477 1479 1485 1486 1488 1489 1492 1491 1481 1477 1471 1476 1480 1474 1486 1481 1487 1479 1477 1478 1491 1489 1494 1490 1496 1488 1479 1478 1473 1483 1481 1482 1466 1468 1473 1465 1464 1474 1485 1489 1488 1486 1492 1495 10 9544 9550 9545 9548 9546 9547 9546 9543 9544 9540 9545 9541 9540 9542 9539 9541 9543 9544 9548 9543 9542 9546 9545 9544 9551 9550 9554 9553 9552 9549 9547 9551 9546 9549 9552 9548 9552 9549 9548 9547 9553 9551 9542 9544 9541 9546 9545 9547 9548 9544 9549 9546 9543 9545 9550 9548 9547 9546 9549 9545 98 5488 5381 5377 5434 5394 5393 5397 5388 5429 5437 5452 5445 5412 5357 5347 5386 5375 5432 5478 5366 5377 5435 5431 5440 5408 5444 5362 5382 5458 5436 5483 5440 5471 5371 5414 5482 5367 5484 5388 5454 5478 5379 5365 5418 5480 5367 5393 5460 5424 5367 5428 5379 5361 5457 5490 5397 5481 5432 5398 5480 5405 5345 5419 5352 5362 5400 5484 5442 5413 5470 5458 5434 5422 5399 5488 5437 5430 5436 5361 5390 5404 5450 5372 5363 5476 5413 5386 5400 5458 5408 5485 5442 5359 5366 5367 5463 5361 5430 5380 5458 5369 5411 5411 5432 5346 5459 5426 5473 5359 5365 5484 5472 5393 5419 5480 5418 5377 5483 5390 5414 5413 5449 5381 5427 5425 5451 5390 5379 5405 5476 5432 5438 5450 5466 5397 5379 5459 5416 5347 5411 5369 5376 5454 5365 5415 5413 5464 5350 5392 5391 5466 5389 5352 5465 5485 5471 5419 5370 5426 5403 5425 5430 5472 5484 5469 5364 5446 5456 5403 5438 5404 5366 5472 5412 5412 5434 5356 5487 5453 5361 5447 5467 5491 5359 5361 5457 5388 5467 5468 5353 5491 5465 5469 5437 5373 5375 5487 5414 5379 5357 5388 5370 5360 5374 5361 5422 5402 5439 5368 5366 5408 5407 5462 5349 5484 5391 5443 5453 5406 5350 5459 5470 5435 5385 5482 5426 5488 5377 5346 5486 5447 5470 5380 5379 5476 5393 5445 5433 5423 5452 5470 5407 5391 5371 5384 5418 5381 5357 5413 5376 5400 5347 5418 5403 5407 5454 5357 5376 5384 5436 5386 5346 5397 5358 5431 5395 5455 5432 5443 5352 5380 5412 5484 5419 5430 5447 5396 5454 5457 5356 5461 5423 5368 5383 5462 5484 5456 5466 5393 5450 5350 5434 5418 5365 5356 5391 5479 5469 5369 5374 5421 5369 5404 5435 5401 5447 5395 5468 5382 5363 5394 5432 5395 5449 5446 5415 5416 5460 5385 5363 5364 5476 5412 5490 5475 5439 5483 5401 5399 5352 5359 5471 5428 5451 5446 5489 5442 5347 5455 5384 5349 5428 5354 5406 5357 5458 5462 5474 5414 5360 5438 5390 5346 5358 5412 5369 5362 5455 5349 5465 5458 5453 5385 5372 5431 5486 5389 5424 5425 5431 5461 5436 5476 5380 5352 5464 5481 5447 5462 5484 5422 5470 5364 5465 5382 5440 5418 5488 5403 5442 5377 5467 5352 5364 5461 5362 5388 5462 5484 5427 5428 5432 5462 5463 5460 5372 5417 5360 5454 5369 5357 5403 5345 5430 5473 5458 5446 5373 5474 5389 5407 5421 5449 5482 5470 5417 5377 5483 5347 5487 5408 5383 5467 5351 5389 5353 5415 5350 5404 5420 5471 5416 5465 5430 5369 5346 5425 5364 5362 5376 5426 5346 5457 5348 5445 5414 5423 5460 5491 5442 5414 5380 5425 5387 5459 5435 5360 5457 5464 5385 5469 5369 5439 5357 5403 5436 5415 5448 5425 5391 5471 5483 5408 5421 5411 5400 5478 5404 5460 5475 5455 5379 5366 5478 5375 5484 5364 5405 5461 5449 5374 5486 5401 5399 5461 5363 5458 5362 5482 5448 5414 5462 5380 5473 5357 5399 5367 5485 5437 5351 5414 5390 5386 5375 5411 5425 5443 5470 5432 5476 5370 5400 5448 5358 5396 5447 5451 5480 5405 5403 5371 5409 5362 5413 5468 5364 5455 5408 5483 5399 5398 5404 5489 5470 5379 5389 5460 5385 5382 5384 5390 5407 5410 5464 5424 5362 5385 5446 5470 5368 5352 5425 5470 5468 5346 5463 5483 5372 5403 5396 5401 5374 5448 5434 5432 5393 5411 5479 80 9363 9349 9366 9353 9354 9359 9363 9360 9351 9366 9354 9357 9358 9362 9350 9355 9367 9365 9363 9354 9366 9357 9360 9359 9364 9352 9365 9362 9361 9358 9354 9360 9363 9359 9357 9366 9357 9349 9363 9353 9359 9360 9361 9358 9350 9365 9355 9364 9360 9363 9357 9353 9359 9354 9350 9358 9361 9355 9362 9352 9356 9367 9362 9365 9355 9364 9358 9355 9365 9350 9361 9364 9352 9356 9355 9367 9364 9361 9359 9351 9353 9366 9357 9363 9360 9349 9363 9353 9351 9354 9349 9357 9353 9366 9354 9351 9351 9357 9349 9354 9359 9363 9353 9357 9360 9363 9354 9351 9362 9352 9365 9356 9367 9364 9354 9357 9363 9349 9359 9366 9364 9362 9367 9361 9350 9365 9355 9367 9356 9352 9361 9364 9360 9351 9354 9353 9349 9366 9349 9357 9354 9360 9351 9359 9354 9353 9349 9366 9359 9363 9366 9359 9363 9360 9357 9353 9354 9349 9366 9357 9351 9363 9354 9363 9366 9353 9360 9349 9362 9350 9365 9364 9355 9358 9354 9360 9357 9349 9351 9353 9353 9351 9359 9354 9360 9357 9353 9359 9366 9351 9360 9363 9362 9364 9365 9352 9355 9367 9360 9349 9357 9366 9354 9359 9358 9367 9365 9362 9352 9356 9355 9362 9352 9356 9367 9350 9367 9362 9358 9350 9352 9365 9357 9366 9353 9363 9359 9349 9363 9359 9351 9349 9353 9357 9358 9362 9356 9355 9365 9367 9352 9365 9350 9361 9367 9362 9367 9362 9364 9355 9365 9350 9354 9357 9360 9353 9351 9359 9365 9356 9362 9358 9367 9352 9358 9352 9365 9356 9364 9350 9354 9360 9349 9357 9366 9363 9365 9350 9355 9352 9356 9367 9356 9352 9350 9367 9361 9358 9358 9356 9352 9361 9355 9362 9352 9358 9362 9356 9350 9361 9349 9360 9363 9357 9366 9354 9349 9360 9363 9357 9359 9354 9349 9360 9366 9351 9354 9357 9365 9362 9364 9350 9358 9367 9349 9354 9363 9359 9366 9353 9352 9362 9350 9364 9361 9365 9366 9359 9353 9363 9354 9351 9354 9363 9353 9359 9351 9366 9362 9352 9350 9364 9355 9356 9359 9357 9349 9363 9360 9351 9352 9361 9356 9367 9362 9365 9358 9355 9356 9362 9365 9364 9359 9357 9353 9363 9351 9354 9359 9353 9363 9366 9354 9360 9361 9364 9350 9367 9352 9362 9366 9351 9363 9354 9359 9349 9359 9351 9360 9363 9353 9366 9350 9364 9352 9362 9361 9358 9352 9355 9362 9367 9358 9350 9355 9361 9352 9358 9356 9364 9352 9367 9365 9350 9362 9361 9359 9349 9354 9363 9366 9360 9367 9352 9364 9361 9350 9355 9360 9363 9357 9349 9351 9353 9361 9364 9367 9362 9356 9355 9358 9364 9365 9356 9361 9367 9366 9354 9349 9359 9357 9363 9356 9361 9362 9365 9352 9358 9350 9365 9361 9355 9364 9358 9355 9362 9356 9361 9352 9350 30 2579 2575 2570 2577 2578 2573 2572 2578 2573 2574 2579 2576 2571 2570 2577 2581 2576 2579 2579 2572 2570 2578 2574 2580 2577 2578 2571 2572 2574 2570 2570 2571 2579 2573 2572 2577 2573 2581 2571 2578 2572 2579 2576 2575 2574 2570 2579 2578 2576 2579 2571 2578 2581 2570 2575 2570 2577 2574 2580 2573 2577 2572 2575 2580 2573 2570 2573 2570 2579 2572 2577 2574 2573 2571 2577 2570 2581 2580 2574 2578 2581 2570 2577 2572 2580 2570 2579 2581 2572 2575 2579 2570 2571 2581 2575 2573 2576 2579 2575 2574 2570 2581 2580 2576 2579 2571 2578 2577 2573 2578 2576 2572 2571 2580 2571 2579 2577 2572 2574 2570 2573 2580 2578 2576 2570 2571 2573 2581 2577 2579 2580 2574 2581 2577 2575 2576 2571 2574 2573 2578 2580 2572 2574 2577 2574 2580 2570 2571 2573 2581 2571 2578 2580 2577 2570 2576 2571 2572 2580 2581 2579 2577 2577 2575 2573 2578 2571 2574 2575 2574 2577 2572 2571 2570 2577 2581 2576 2573 2580 2579 100 5656 5654 5659 5653 5652 5655 5663 5662 5660 5655 5656 5661 5742 5738 5736 5741 5743 5737 5658 5663 5664 5662 5659 5665 5730 5729 5731 5726 5724 5728 5688 5683 5686 5685 5681 5680 5742 5744 5739 5746 5743 5745 5680 5674 5675 5681 5677 5679 5740 5744 5741 5737 5745 5738 5748 5740 5742 5744 5745 5747 5658 5652 5659 5653 5656 5651 5706 5704 5698 5705 5700 5703 5704 5706 5707 5708 5701 5705 5712 5711 5716 5717 5709 5710 5688 5687 5692 5689 5686 5685 5667 5666 5660 5665 5659 5662 5732 5731 5729 5736 5737 5735 5668 5670 5671 5669 5674 5675 5719 5721 5718 5714 5717 5716 5663 5667 5669 5665 5664 5666 5654 5650 5653 5651 5646 5652 5730 5728 5724 5726 5729 5727 5710 5703 5705 5711 5706 5704 5727 5731 5734 5726 5728 5729 5726 5723 5719 5720 5727 5721 5740 5744 5738 5741 5746 5745 5680 5672 5673 5674 5679 5676 5663 5662 5666 5660 5667 5664 5675 5670 5673 5674 5672 5671 5655 5650 5648 5654 5652 5651 5725 5727 5722 5728 5726 5723 5711 5715 5714 5713 5710 5716 5719 5717 5713 5715 5716 5721 5705 5704 5703 5700 5698 5697 5712 5714 5718 5710 5716 5717 5704 5702 5707 5705 5701 5703 5655 5662 5657 5659 5658 5654 5693 5690 5688 5691 5687 5689 5686 5688 5683 5685 5687 5682 5746 5751 5745 5747 5752 5749 5748 5741 5749 5746 5747 5743 5746 5745 5753 5752 5747 5751 5688 5685 5686 5683 5687 5684 5720 5727 5722 5723 5726 5728 5687 5693 5688 5689 5686 5691 5668 5670 5665 5672 5666 5671 5677 5684 5678 5682 5681 5685 5704 5710 5712 5706 5705 5711 5669 5673 5670 5674 5671 5676 5736 5734 5739 5735 5741 5740 5736 5732 5738 5735 5734 5731 5676 5679 5674 5678 5673 5671 5680 5682 5681 5676 5679 5678 5738 5734 5736 5732 5737 5731 5711 5719 5712 5713 5714 5715 5693 5689 5688 5696 5690 5694 5749 5750 5748 5742 5746 5743 5655 5653 5656 5650 5654 5657 5696 5701 5697 5698 5702 5700 5694 5697 5695 5700 5693 5698 5684 5685 5683 5691 5689 5686 5664 5661 5657 5662 5658 5659 5723 5725 5724 5726 5730 5722 5672 5675 5673 5678 5677 5674 5709 5710 5708 5707 5702 5706 5736 5735 5738 5734 5740 5733 5682 5683 5686 5684 5687 5681 5748 5747 5743 5746 5751 5750 5649 5653 5655 5647 5650 5648 5654 5649 5656 5651 5650 5657 5720 5722 5716 5723 5719 5721 5673 5670 5669 5671 5667 5672 5671 5669 5670 5673 5672 5674 5743 5736 5740 5741 5738 5744 5678 5682 5677 5681 5683 5679 5691 5693 5698 5695 5697 5692 5691 5690 5697 5693 5698 5696 5697 5702 5695 5703 5699 5698 5724 5725 5722 5726 5721 5718 5700 5697 5701 5693 5699 5694 5678 5685 5686 5680 5681 5679 5689 5692 5695 5687 5691 5694 5667 5670 5662 5665 5666 5664 5726 5731 5732 5729 5727 5730 5716 5718 5721 5720 5722 5715 5713 5707 5710 5711 5706 5708 5664 5661 5659 5660 5658 5657 5712 5711 5707 5709 5713 5714 5694 5697 5689 5691 5692 5690 5728 5735 5729 5731 5733 5732 5699 5706 5705 5701 5702 5700 5659 5661 5657 5653 5658 5655 5735 5734 5736 5741 5742 5737 5730 5736 5729 5733 5731 5732 5713 5710 5707 5711 5706 5708 5720 5725 5718 5724 5717 5723 5674 5680 5677 5679 5675 5681 5662 5667 5663 5664 5665 5666 5694 5701 5698 5697 5696 5695 5717 5712 5718 5716 5719 5720 10 9640 9643 9638 9641 9642 9639 9645 9642 9640 9641 9643 9644 9641 9639 9643 9642 9644 9640 9639 9638 9642 9641 9637 9640 9643 9645 9646 9642 9644 9647 9644 9649 9645 9648 9646 9647 9645 9641 9644 9642 9646 9643 9643 9648 9647 9645 9646 9644 9635 9636 9639 9638 9640 9637 9636 9640 9641 9638 9639 9637 45 7104 7101 7096 7097 7102 7103 7104 7097 7101 7103 7102 7096 7098 7100 7105 7099 7095 7094 7094 7095 7105 7100 7099 7098 7098 7105 7094 7099 7100 7095 7094 7105 7095 7098 7100 7099 7096 7097 7104 7101 7102 7103 7102 7097 7104 7103 7101 7096 7100 7105 7094 7098 7099 7095 7098 7100 7095 7105 7094 7099 7095 7098 7094 7099 7100 7105 7099 7094 7105 7100 7095 7098 7105 7098 7094 7100 7095 7099 7095 7098 7100 7105 7094 7099 7097 7096 7104 7103 7102 7101 7097 7101 7104 7102 7103 7096 7105 7099 7095 7100 7094 7098 7099 7095 7094 7098 7105 7100 7099 7095 7100 7094 7105 7098 7101 7097 7102 7096 7104 7103 7100 7098 7105 7095 7099 7094 7102 7096 7104 7097 7101 7103 7094 7105 7098 7100 7095 7099 7099 7098 7094 7100 7105 7095 7094 7099 7098 7105 7100 7095 7097 7101 7102 7104 7096 7103 7099 7098 7100 7105 7094 7095 7100 7098 7094 7095 7105 7099 7099 7094 7105 7098 7095 7100 7105 7099 7098 7094 7100 7095 7100 7099 7094 7105 7095 7098 7094 7095 7100 7105 7098 7099 7100 7094 7095 7099 7105 7098 7097 7101 7096 7103 7104 7102 7100 7094 7098 7105 7095 7099 7099 7095 7100 7098 7105 7094 7097 7096 7101 7104 7102 7103 7104 7097 7102 7096 7103 7101 7098 7095 7105 7099 7100 7094 7104 7097 7096 7101 7103 7102 7104 7097 7096 7103 7101 7102 7099 7094 7100 7098 7095 7105 7104 7097 7103 7096 7102 7101 7099 7105 7095 7094 7100 7098 7105 7098 7095 7100 7099 7094 99 7711 7702 7719 7729 7690 7738 7637 7646 7733 7657 7760 7722 7705 7747 7748 7634 7757 7771 7663 7770 7656 7727 7659 7725 7694 7680 7755 7677 7750 7675 7765 7656 7774 7777 7762 7639 7729 7723 7678 7717 7754 7763 7722 7733 7754 7757 7708 7730 7739 7767 7653 7768 7654 7747 7638 7710 7762 7683 7759 7753 7669 7779 7771 7740 7757 7717 7660 7716 7668 7703 7638 7667 7659 7707 7768 7666 7677 7756 7712 7769 7738 7720 7739 7774 7651 7659 7778 7641 7698 7674 7773 7715 7653 7770 7642 7684 7694 7699 7766 7777 7764 7647 7666 7737 7635 7702 7691 7667 7704 7679 7775 7719 7668 7746 7761 7662 7682 7735 7715 7712 7670 7692 7654 7696 7767 7664 7718 7749 7685 7670 7656 7763 7711 7727 7777 7694 7640 7723 7660 7690 7755 7750 7742 7645 7642 7675 7683 7710 7677 7752 7713 7734 7747 7714 7729 7751 7693 7739 7690 7712 7720 7673 7653 7709 7648 7675 7747 7724 7691 7677 7646 7650 7700 7694 7771 7740 7653 7721 7769 7778 7731 7768 7747 7662 7637 7777 7722 7767 7766 7651 7754 7712 7701 7729 7763 7722 7732 7775 7657 7779 7718 7712 7664 7661 7688 7711 7655 7713 7690 7729 7644 7648 7753 7675 7693 7666 7699 7779 7754 7726 7714 7641 7711 7773 7737 7747 7730 7708 7730 7650 7733 7670 7774 7674 7770 7718 7713 7771 7753 7702 7673 7721 7638 7718 7686 7749 7700 7725 7649 7714 7644 7645 7709 7714 7693 7671 7780 7697 7684 7681 7656 7704 7771 7777 7769 7672 7645 7734 7692 7633 7696 7678 7766 7727 7684 7741 7738 7634 7677 7694 7680 7712 7672 7747 7735 7710 7637 7660 7689 7641 7706 7714 7746 7708 7769 7695 7649 7638 7707 7633 7645 7739 7727 7753 7778 7773 7717 7667 7769 7751 7746 7747 7653 7756 7728 7685 7721 7646 7769 7711 7775 7696 7738 7741 7749 7774 7752 7695 7761 7680 7677 7667 7713 7731 7644 7724 7733 7754 7711 7779 7717 7650 7633 7743 7757 7712 7651 7710 7766 7701 7651 7697 7764 7708 7739 7731 7780 7759 7729 7700 7722 7773 7734 7680 7705 7776 7655 7709 7677 7727 7749 7637 7720 7634 7748 7738 7734 7642 7649 7749 7697 7659 7636 7704 7638 7650 7696 7717 7666 7718 7744 7650 7642 7671 7745 7729 7744 7649 7652 7761 7764 7698 7753 7658 7639 7732 7642 7739 7769 7637 7713 7723 7644 7649 7690 7705 7654 7774 7735 7650 7736 7648 7655 7775 7694 7669 7703 7720 7668 7689 7755 7768 7683 7739 7743 7742 7764 7699 7684 7666 7766 7634 7749 7711 7740 7647 7741 7643 7773 7657 7755 7692 7658 7711 7642 7636 7773 7653 7640 7691 7745 7706 7757 7718 7680 7702 7653 7643 7774 7643 7748 7758 7686 7746 7693 7734 7727 7778 7706 7703 7720 7707 7688 7648 7725 7718 7754 7675 7718 7753 7742 7721 7662 7699 7658 7647 7714 7751 7766 7714 7742 7673 7740 7753 7741 7652 7766 7699 7774 7758 7695 7650 7725 7711 7707 7682 7658 7766 7764 7703 7661 7646 7681 7637 7778 7752 7747 7671 7661 7716 7642 7692 7696 7657 7674 7662 7742 7699 7656 7718 7734 7758 7656 7674 7718 7763 7734 7652 7671 7764 7669 7700 7637 7651 7728 7665 7653 7642 7764 7660 7748 7746 7682 7643 7654 7636 7774 7768 7753 7713 7744 7745 7715 7707 7679 7716 7716 7763 7705 7731 7770 7766 7776 7661 7665 7744 7678 7638 7749 7660 7635 7648 7679 7729 pathfinding-4.14.0/tests/A-small-practice.out000064400000000000000000000024001046102023000171520ustar 00000000000000Case #1: 4 Case #2: 1 Case #3: 3 Case #4: 6 Case #5: 30 Case #6: 10 Case #7: 9 Case #8: 83 Case #9: 94 Case #10: 22 Case #11: 55 Case #12: 20 Case #13: 98 Case #14: 6 Case #15: 1 Case #16: 19 Case #17: 14 Case #18: 10 Case #19: 10 Case #20: 19 Case #21: 10 Case #22: 11 Case #23: 100 Case #24: 10 Case #25: 20 Case #26: 100 Case #27: 7 Case #28: 7 Case #29: 15 Case #30: 24 Case #31: 24 Case #32: 37 Case #33: 63 Case #34: 97 Case #35: 30 Case #36: 22 Case #37: 98 Case #38: 2 Case #39: 50 Case #40: 2 Case #41: 23 Case #42: 30 Case #43: 7 Case #44: 11 Case #45: 1 Case #46: 20 Case #47: 14 Case #48: 51 Case #49: 9 Case #50: 25 Case #51: 25 Case #52: 96 Case #53: 55 Case #54: 100 Case #55: 55 Case #56: 18 Case #57: 100 Case #58: 18 Case #59: 33 Case #60: 13 Case #61: 30 Case #62: 24 Case #63: 52 Case #64: 6 Case #65: 22 Case #66: 14 Case #67: 80 Case #68: 13 Case #69: 10 Case #70: 100 Case #71: 9 Case #72: 56 Case #73: 15 Case #74: 12 Case #75: 19 Case #76: 23 Case #77: 10 Case #78: 23 Case #79: 15 Case #80: 24 Case #81: 2 Case #82: 13 Case #83: 69 Case #84: 12 Case #85: 6 Case #86: 10 Case #87: 18 Case #88: 10 Case #89: 12 Case #90: 25 Case #91: 10 Case #92: 30 Case #93: 10 Case #94: 62 Case #95: 19 Case #96: 12 Case #97: 100 Case #98: 10 Case #99: 12 Case #100: 84 pathfinding-4.14.0/tests/aoc-2017-12-12.rs000064400000000000000000000024741046102023000155150ustar 00000000000000// Test from https://adventofcode.com/, 2017-12-12 use lazy_static::lazy_static; use pathfinding::prelude::*; use std::collections::{HashMap, HashSet}; lazy_static! { static ref PIPES: Vec> = include_str!("aoc-2017-12-12.txt") .lines() .map(|line| line .replace(" <->", ",") .split(", ") .map(|w| w.parse::().unwrap()) .collect::>()) .collect::>(); } #[test] fn method1() { let pipes = PIPES .iter() .map(|l| (l[0], l[1..].to_vec())) .collect::>(); let all_nodes = pipes.keys().copied().collect::>(); let components = connected_components(&all_nodes, |&n| pipes.get(&n).cloned().unwrap_or_default()); assert_eq!(152, components[component_index(&components)[&0]].len()); assert_eq!(186, components.len()); } #[test] fn method2() { let (indices, groups) = separate_components(&PIPES); let zero = indices[&0]; assert_eq!(152, indices.values().filter(|&g| *g == zero).count()); assert_eq!(186, groups.into_iter().collect::>().len()); } #[test] fn method3() { let groups = components(&PIPES); let zero = groups.iter().find(|g| g.contains(&0)).unwrap(); assert_eq!(152, zero.len()); assert_eq!(186, groups.len()); } pathfinding-4.14.0/tests/aoc-2017-12-12.txt000064400000000000000000001054751046102023000157150ustar 000000000000000 <-> 46, 1376 1 <-> 1465, 1889 2 <-> 609, 1578 3 <-> 3, 1003, 1133, 1887 4 <-> 467, 1282 5 <-> 5, 460, 1059, 1812 6 <-> 235, 1318, 1556 7 <-> 885, 1143, 1400 8 <-> 8, 1102 9 <-> 1349 10 <-> 1711 11 <-> 1717 12 <-> 663, 1968 13 <-> 1374 14 <-> 55, 732, 926 15 <-> 255, 1133 16 <-> 645 17 <-> 180, 1507 18 <-> 401 19 <-> 531 20 <-> 20 21 <-> 467 22 <-> 1376, 1825 23 <-> 1163 24 <-> 93, 365, 383 25 <-> 46 26 <-> 1280 27 <-> 27 28 <-> 1001 29 <-> 1506, 1659 30 <-> 680, 1569 31 <-> 121, 172, 684 32 <-> 1331 33 <-> 527, 668, 1471 34 <-> 473 35 <-> 790, 1789 36 <-> 797 37 <-> 1832 38 <-> 1151, 1703 39 <-> 382 40 <-> 183, 333, 1032, 1405, 1587, 1649 41 <-> 589, 965 42 <-> 515, 1466 43 <-> 599 44 <-> 220, 1533 45 <-> 656 46 <-> 0, 25, 918, 1267 47 <-> 262, 1084, 1590 48 <-> 856 49 <-> 49 50 <-> 1604, 1650 51 <-> 233 52 <-> 1975 53 <-> 141, 296 54 <-> 54 55 <-> 14, 1483 56 <-> 738, 1632 57 <-> 698, 1089 58 <-> 133, 144, 1577 59 <-> 917 60 <-> 60, 694, 846 61 <-> 1386 62 <-> 264 63 <-> 1875 64 <-> 1028 65 <-> 83, 86, 1767, 1876 66 <-> 120 67 <-> 363 68 <-> 565 69 <-> 69 70 <-> 1414, 1542 71 <-> 782, 1149, 1918, 1944, 1951, 1974 72 <-> 72 73 <-> 73 74 <-> 77 75 <-> 81 76 <-> 519, 1266 77 <-> 74, 77 78 <-> 833, 1408, 1690 79 <-> 492 80 <-> 614, 1505 81 <-> 75, 81, 105, 595, 1035 82 <-> 440 83 <-> 65 84 <-> 106, 1907 85 <-> 508, 1397, 1811 86 <-> 65, 86, 112 87 <-> 682, 1872 88 <-> 1201 89 <-> 1297 90 <-> 592, 1873 91 <-> 1288, 1447 92 <-> 788, 1269, 1987 93 <-> 24, 97, 608 94 <-> 1138 95 <-> 1668 96 <-> 1608 97 <-> 93, 1446 98 <-> 580 99 <-> 220 100 <-> 1165, 1623 101 <-> 1588 102 <-> 1706, 1820 103 <-> 1187 104 <-> 561 105 <-> 81, 1419 106 <-> 84, 1055 107 <-> 140, 222 108 <-> 438, 1194 109 <-> 109, 1739 110 <-> 1217, 1968 111 <-> 650, 1213 112 <-> 86 113 <-> 250, 1380 114 <-> 248, 1172, 1254 115 <-> 115 116 <-> 713 117 <-> 319, 389 118 <-> 1892, 1914 119 <-> 227 120 <-> 66, 314, 350, 580 121 <-> 31, 1369, 1375 122 <-> 952, 1657 123 <-> 143, 1153 124 <-> 1124, 1173 125 <-> 125 126 <-> 1178 127 <-> 1406, 1966 128 <-> 620, 1493 129 <-> 541, 1095 130 <-> 1813 131 <-> 616 132 <-> 132, 1142 133 <-> 58, 163, 375 134 <-> 1288, 1503 135 <-> 534, 763 136 <-> 552 137 <-> 137, 762, 900 138 <-> 1791 139 <-> 502, 1768 140 <-> 107, 1150, 1346 141 <-> 53, 1415 142 <-> 1361 143 <-> 123, 729, 966, 1087, 1091 144 <-> 58, 1007, 1379 145 <-> 1183 146 <-> 543, 1569 147 <-> 600 148 <-> 735 149 <-> 828, 1558 150 <-> 442, 1096 151 <-> 228, 748 152 <-> 1076, 1951 153 <-> 1577 154 <-> 1829 155 <-> 376, 469, 789, 940, 1294 156 <-> 365, 1287 157 <-> 157 158 <-> 1372 159 <-> 504 160 <-> 1542 161 <-> 190 162 <-> 978 163 <-> 133, 671, 1173 164 <-> 776 165 <-> 437 166 <-> 231, 573, 1924 167 <-> 1661 168 <-> 1189 169 <-> 169, 907 170 <-> 230, 553 171 <-> 909 172 <-> 31, 234, 883 173 <-> 1062 174 <-> 174, 1688 175 <-> 597, 751, 1515, 1599 176 <-> 1302, 1435 177 <-> 177 178 <-> 427, 1148 179 <-> 1196, 1390 180 <-> 17, 847 181 <-> 528, 1956 182 <-> 482 183 <-> 40 184 <-> 184 185 <-> 307, 1339, 1555 186 <-> 703, 1198 187 <-> 1656 188 <-> 1342 189 <-> 1742 190 <-> 161, 237, 416, 590 191 <-> 907 192 <-> 482, 798, 1709 193 <-> 805, 1320 194 <-> 308, 989 195 <-> 316, 518, 728 196 <-> 848, 1239, 1335 197 <-> 681, 683, 1965, 1977 198 <-> 1028 199 <-> 1126, 1808, 1953 200 <-> 655, 921 201 <-> 733 202 <-> 1002, 1137, 1422 203 <-> 529, 1127 204 <-> 697, 1656 205 <-> 1249 206 <-> 608 207 <-> 669 208 <-> 241 209 <-> 1190 210 <-> 503 211 <-> 1017 212 <-> 567, 932, 1673 213 <-> 432 214 <-> 1097, 1180 215 <-> 715 216 <-> 426, 610, 1517 217 <-> 1638 218 <-> 1453 219 <-> 219, 1033 220 <-> 44, 99, 1874 221 <-> 221, 1466 222 <-> 107, 1014 223 <-> 495 224 <-> 503, 992 225 <-> 800 226 <-> 697, 1294 227 <-> 119, 733, 1186 228 <-> 151, 948, 984, 1359 229 <-> 1039 230 <-> 170, 1825, 1954 231 <-> 166, 894 232 <-> 580 233 <-> 51, 835, 1247 234 <-> 172, 588, 739 235 <-> 6, 812 236 <-> 1150 237 <-> 190, 1065, 1157 238 <-> 1930 239 <-> 345, 584, 1731 240 <-> 1514 241 <-> 208, 556, 784, 1992 242 <-> 242 243 <-> 1666, 1760 244 <-> 437, 1394 245 <-> 306, 1175 246 <-> 1032 247 <-> 522, 709, 1565, 1611 248 <-> 114, 248, 862, 1863 249 <-> 887, 1066 250 <-> 113 251 <-> 251 252 <-> 427, 1583 253 <-> 328 254 <-> 618, 680, 1370, 1442 255 <-> 15, 1516, 1637 256 <-> 470, 1532, 1678, 1809 257 <-> 448, 1263, 1434, 1587 258 <-> 519 259 <-> 296, 1877 260 <-> 311 261 <-> 1841 262 <-> 47, 1111 263 <-> 969 264 <-> 62, 264, 1347 265 <-> 1657 266 <-> 1360 267 <-> 494 268 <-> 1498 269 <-> 956, 1258 270 <-> 270, 532 271 <-> 400, 813, 1500 272 <-> 1777 273 <-> 1768 274 <-> 835, 1432 275 <-> 750 276 <-> 298, 1749 277 <-> 1256, 1285 278 <-> 1720 279 <-> 903 280 <-> 941 281 <-> 315, 1356 282 <-> 1293 283 <-> 667, 802 284 <-> 663, 1223 285 <-> 1732 286 <-> 493 287 <-> 584, 1823 288 <-> 365, 906 289 <-> 618, 1777 290 <-> 479, 988 291 <-> 794 292 <-> 304, 769, 944, 1448, 1735 293 <-> 516, 1295 294 <-> 406 295 <-> 1279 296 <-> 53, 259, 585, 1128 297 <-> 1047, 1899 298 <-> 276, 543 299 <-> 1268, 1528 300 <-> 993, 1384 301 <-> 1323, 1984 302 <-> 919, 923, 1611, 1962 303 <-> 1172 304 <-> 292 305 <-> 1857 306 <-> 245, 1044, 1699 307 <-> 185, 1138 308 <-> 194 309 <-> 1054 310 <-> 310, 1428, 1438 311 <-> 260, 1291 312 <-> 1316 313 <-> 441 314 <-> 120, 1865, 1967 315 <-> 281, 673, 711 316 <-> 195, 1083, 1969 317 <-> 317, 508 318 <-> 688 319 <-> 117 320 <-> 1174 321 <-> 822, 978, 1042, 1373, 1980 322 <-> 368, 1932 323 <-> 1192 324 <-> 1239 325 <-> 607, 704, 1871 326 <-> 634, 1916 327 <-> 940, 1605 328 <-> 253, 328, 636 329 <-> 722, 1528 330 <-> 1448 331 <-> 771, 820 332 <-> 1580 333 <-> 40, 1785 334 <-> 1992 335 <-> 1064, 1713 336 <-> 560, 1746, 1979 337 <-> 988 338 <-> 974, 1689, 1694 339 <-> 1468 340 <-> 555 341 <-> 426, 1068, 1976 342 <-> 1662 343 <-> 799, 860 344 <-> 743, 1109, 1547 345 <-> 239, 781, 1734, 1963 346 <-> 445, 1218, 1736 347 <-> 502, 1560 348 <-> 739, 1700 349 <-> 417 350 <-> 120, 887 351 <-> 533, 537 352 <-> 1075 353 <-> 506, 1098, 1248 354 <-> 354, 666 355 <-> 1320 356 <-> 464, 487, 1954 357 <-> 603, 1444, 1552 358 <-> 1273, 1623 359 <-> 1308, 1659 360 <-> 1648 361 <-> 361, 1822 362 <-> 362, 692 363 <-> 67, 606, 1127 364 <-> 364 365 <-> 24, 156, 288, 424, 1017 366 <-> 1006, 1434 367 <-> 372, 1413 368 <-> 322 369 <-> 1194 370 <-> 1272 371 <-> 1551 372 <-> 367 373 <-> 1077 374 <-> 1869 375 <-> 133 376 <-> 155 377 <-> 1373 378 <-> 982, 1730 379 <-> 556, 1999 380 <-> 1208, 1405 381 <-> 976, 1506, 1855 382 <-> 39, 1639 383 <-> 24, 894, 1215 384 <-> 1124, 1350 385 <-> 385, 417, 697, 845 386 <-> 491, 712, 817, 1550 387 <-> 1347 388 <-> 404 389 <-> 117, 1156, 1190 390 <-> 1344 391 <-> 679, 931, 989 392 <-> 396, 690, 1694 393 <-> 618, 1497, 1803 394 <-> 398, 1462 395 <-> 1230, 1417 396 <-> 392, 1412 397 <-> 818, 1176, 1951 398 <-> 394, 1651, 1945 399 <-> 1496 400 <-> 271, 1372, 1779, 1893 401 <-> 18, 1382 402 <-> 1726, 1864 403 <-> 1917 404 <-> 388, 1071 405 <-> 1026 406 <-> 294, 1354 407 <-> 1721, 1934 408 <-> 1523, 1600 409 <-> 923 410 <-> 410 411 <-> 856, 1190, 1568 412 <-> 714, 1423 413 <-> 736 414 <-> 953, 1631 415 <-> 1282 416 <-> 190, 659 417 <-> 349, 385 418 <-> 556, 912 419 <-> 1304 420 <-> 656 421 <-> 1230 422 <-> 422, 542 423 <-> 779, 1260 424 <-> 365, 1595 425 <-> 958, 1134, 1495 426 <-> 216, 341, 887 427 <-> 178, 252, 1609 428 <-> 428, 1257 429 <-> 1020 430 <-> 602 431 <-> 539 432 <-> 213, 938, 1633 433 <-> 629, 1705 434 <-> 640 435 <-> 447, 1694 436 <-> 1487 437 <-> 165, 244, 1661 438 <-> 108, 565, 966 439 <-> 663 440 <-> 82, 492 441 <-> 313, 441 442 <-> 150, 442, 1970 443 <-> 868, 1665 444 <-> 662, 823 445 <-> 346, 1043, 1660 446 <-> 691, 708 447 <-> 435, 1182 448 <-> 257, 1608 449 <-> 1771, 1959 450 <-> 893, 1299 451 <-> 1578 452 <-> 1607, 1725 453 <-> 533, 651, 1271 454 <-> 1366 455 <-> 1677 456 <-> 870, 1935 457 <-> 750 458 <-> 465, 1859 459 <-> 728 460 <-> 5 461 <-> 1070, 1937 462 <-> 1201, 1277 463 <-> 568 464 <-> 356, 1412 465 <-> 458, 1368, 1613, 1980 466 <-> 1385, 1993 467 <-> 4, 21, 1345 468 <-> 468, 707, 1721 469 <-> 155, 676, 1008 470 <-> 256, 667 471 <-> 1552 472 <-> 503, 1468 473 <-> 34, 473, 1638 474 <-> 531 475 <-> 1163, 1379 476 <-> 797 477 <-> 995 478 <-> 1258, 1441 479 <-> 290, 1257 480 <-> 1903 481 <-> 703, 1339 482 <-> 182, 192 483 <-> 500, 759, 1077 484 <-> 833 485 <-> 672, 828 486 <-> 661, 1784 487 <-> 356 488 <-> 688, 930 489 <-> 489, 579 490 <-> 490 491 <-> 386, 1580, 1715 492 <-> 79, 440, 767, 1872 493 <-> 286, 1538 494 <-> 267, 1674, 1902 495 <-> 223, 1655 496 <-> 572 497 <-> 532, 1038, 1401 498 <-> 498, 1241 499 <-> 614 500 <-> 483, 654, 1862, 1952 501 <-> 933, 1957 502 <-> 139, 347, 1629 503 <-> 210, 224, 472, 720, 1948 504 <-> 159, 1113 505 <-> 832, 913, 1707 506 <-> 353, 559, 1320 507 <-> 1870 508 <-> 85, 317, 722 509 <-> 1301, 1348, 1873 510 <-> 640, 1882 511 <-> 511 512 <-> 1300 513 <-> 1679, 1731 514 <-> 896, 1009 515 <-> 42, 1056 516 <-> 293 517 <-> 517, 1112, 1704 518 <-> 195 519 <-> 76, 258, 1247, 1782 520 <-> 661, 731, 1949 521 <-> 1179, 1762 522 <-> 247 523 <-> 668, 916, 1197 524 <-> 714, 1228, 1304 525 <-> 1479 526 <-> 1895 527 <-> 33 528 <-> 181, 528 529 <-> 203, 763, 1184, 1227, 1615 530 <-> 1169 531 <-> 19, 474, 1297, 1411, 1883 532 <-> 270, 497, 1630, 1821, 1868 533 <-> 351, 453 534 <-> 135, 1272 535 <-> 997, 1049 536 <-> 718, 1242 537 <-> 351, 1762 538 <-> 1165 539 <-> 431, 953, 1273 540 <-> 1062, 1362, 1554 541 <-> 129 542 <-> 422, 1713 543 <-> 146, 298 544 <-> 544 545 <-> 942, 1030, 1904 546 <-> 1553, 1598 547 <-> 974 548 <-> 845, 1479 549 <-> 1333 550 <-> 598 551 <-> 740, 1861 552 <-> 136, 1347, 1523 553 <-> 170, 915, 1603 554 <-> 1421 555 <-> 340, 760, 1836 556 <-> 241, 379, 418, 590 557 <-> 648 558 <-> 904, 1670 559 <-> 506, 1576, 1920 560 <-> 336, 1057, 1652 561 <-> 104, 1329, 1590 562 <-> 1297, 1322, 1702 563 <-> 1319 564 <-> 1331 565 <-> 68, 438, 1990 566 <-> 1031, 1240 567 <-> 212, 1146, 1436 568 <-> 463, 1093 569 <-> 1311, 1520 570 <-> 1065, 1893 571 <-> 1421 572 <-> 496, 587, 1082, 1537 573 <-> 166, 1556 574 <-> 1240 575 <-> 575 576 <-> 1157 577 <-> 1592 578 <-> 826 579 <-> 489, 986, 1458 580 <-> 98, 120, 232 581 <-> 1296, 1597 582 <-> 1439 583 <-> 1125, 1536 584 <-> 239, 287, 1152, 1743, 1834 585 <-> 296, 1189 586 <-> 952 587 <-> 572, 780, 1829 588 <-> 234, 1071, 1470 589 <-> 41, 1752 590 <-> 190, 556 591 <-> 1023 592 <-> 90, 1225, 1408 593 <-> 852, 1831 594 <-> 1760 595 <-> 81 596 <-> 1566 597 <-> 175 598 <-> 550, 765, 946, 1543 599 <-> 43, 1292, 1386, 1554 600 <-> 147, 1592 601 <-> 1025, 1586 602 <-> 430, 1028, 1522, 1812 603 <-> 357, 873 604 <-> 940 605 <-> 739, 1361 606 <-> 363, 630, 1828 607 <-> 325 608 <-> 93, 206 609 <-> 2 610 <-> 216 611 <-> 961, 1002 612 <-> 1193 613 <-> 892, 1090 614 <-> 80, 499, 1436 615 <-> 615, 1284 616 <-> 131, 1680, 1765 617 <-> 1017 618 <-> 254, 289, 393, 1308 619 <-> 1514 620 <-> 128, 1698 621 <-> 691 622 <-> 1844 623 <-> 811, 1323 624 <-> 745, 1429 625 <-> 959 626 <-> 1830 627 <-> 933 628 <-> 860, 1261, 1378, 1890 629 <-> 433, 1232 630 <-> 606, 1764 631 <-> 1836, 1986 632 <-> 806, 1297 633 <-> 717, 1539 634 <-> 326, 1646 635 <-> 1203, 1985 636 <-> 328 637 <-> 1894 638 <-> 1984 639 <-> 1669 640 <-> 434, 510, 996, 1683 641 <-> 844, 1166 642 <-> 816, 1865, 1953 643 <-> 1511 644 <-> 863, 1652 645 <-> 16, 1097, 1316, 1794 646 <-> 786 647 <-> 647 648 <-> 557, 1236 649 <-> 649 650 <-> 111 651 <-> 453, 888, 1207 652 <-> 795, 936, 1747 653 <-> 669 654 <-> 500, 1620 655 <-> 200, 1799 656 <-> 45, 420, 893, 1682 657 <-> 744 658 <-> 1106, 1293, 1493 659 <-> 416 660 <-> 1700 661 <-> 486, 520, 1067 662 <-> 444 663 <-> 12, 284, 439, 1627, 1922 664 <-> 726, 920, 1174 665 <-> 679 666 <-> 354 667 <-> 283, 470 668 <-> 33, 523 669 <-> 207, 653, 1740, 1806 670 <-> 1565, 1684 671 <-> 163 672 <-> 485 673 <-> 315 674 <-> 1161, 1617, 1714 675 <-> 1954 676 <-> 469, 1160, 1325, 1389 677 <-> 1664 678 <-> 1827 679 <-> 391, 665 680 <-> 30, 254, 750 681 <-> 197 682 <-> 87, 1751 683 <-> 197, 1724 684 <-> 31, 866 685 <-> 713 686 <-> 1911 687 <-> 1226 688 <-> 318, 488, 688, 1705 689 <-> 1127, 1343, 1769 690 <-> 392 691 <-> 446, 621, 1241 692 <-> 362, 1073 693 <-> 758, 1524, 1971 694 <-> 60, 1095 695 <-> 695 696 <-> 696, 1341 697 <-> 204, 226, 385, 824 698 <-> 57, 698 699 <-> 1219, 1429, 1566 700 <-> 935, 1487 701 <-> 826, 1197 702 <-> 1710 703 <-> 186, 481 704 <-> 325, 704 705 <-> 1607 706 <-> 1353, 1818 707 <-> 468 708 <-> 446, 945 709 <-> 247 710 <-> 1750 711 <-> 315 712 <-> 386 713 <-> 116, 685, 1250, 1662 714 <-> 412, 524 715 <-> 215, 833 716 <-> 1195 717 <-> 633, 737 718 <-> 536, 1633 719 <-> 1286, 1538 720 <-> 503, 1492, 1917 721 <-> 786, 1602 722 <-> 329, 508, 1251 723 <-> 1074, 1166 724 <-> 1715 725 <-> 1455 726 <-> 664, 927, 1121 727 <-> 1279 728 <-> 195, 459 729 <-> 143, 1929 730 <-> 785, 1269, 1826 731 <-> 520, 1907 732 <-> 14, 860 733 <-> 201, 227, 733 734 <-> 734 735 <-> 148, 1455, 1771 736 <-> 413, 1377, 1455 737 <-> 717, 1262, 1777 738 <-> 56 739 <-> 234, 348, 605 740 <-> 551, 790 741 <-> 1995 742 <-> 1435, 1768, 1814 743 <-> 344 744 <-> 657, 1857 745 <-> 624, 1283, 1745 746 <-> 1220 747 <-> 1253 748 <-> 151 749 <-> 1571 750 <-> 275, 457, 680 751 <-> 175, 1379, 1849 752 <-> 1577 753 <-> 842, 919 754 <-> 754 755 <-> 1609, 1941 756 <-> 756, 1451 757 <-> 1192, 1412 758 <-> 693, 1667 759 <-> 483 760 <-> 555 761 <-> 1389, 1641 762 <-> 137, 1280 763 <-> 135, 529, 1558 764 <-> 1239 765 <-> 598, 1420 766 <-> 1726 767 <-> 492 768 <-> 1697 769 <-> 292 770 <-> 882 771 <-> 331, 971, 1794 772 <-> 772, 809, 1365 773 <-> 1127 774 <-> 956, 981 775 <-> 1756 776 <-> 164, 1843 777 <-> 1224, 1252 778 <-> 778 779 <-> 423 780 <-> 587, 1295 781 <-> 345 782 <-> 71 783 <-> 1424, 1962 784 <-> 241 785 <-> 730, 1307, 1706 786 <-> 646, 721 787 <-> 1445 788 <-> 92, 1336 789 <-> 155, 1203 790 <-> 35, 740 791 <-> 1155 792 <-> 1818 793 <-> 1541 794 <-> 291, 794, 840, 1460 795 <-> 652, 1911 796 <-> 796 797 <-> 36, 476, 910, 1075 798 <-> 192, 1898 799 <-> 343, 905 800 <-> 225, 1334, 1488 801 <-> 1768 802 <-> 283, 1104, 1870 803 <-> 1484 804 <-> 804 805 <-> 193, 1331 806 <-> 632 807 <-> 830 808 <-> 1059 809 <-> 772, 1226 810 <-> 810 811 <-> 623 812 <-> 235, 1145, 1416 813 <-> 271, 1572 814 <-> 1257, 1886 815 <-> 1695 816 <-> 642 817 <-> 386 818 <-> 397, 1692 819 <-> 1551 820 <-> 331, 1177 821 <-> 1496 822 <-> 321 823 <-> 444, 1120, 1625 824 <-> 697 825 <-> 970 826 <-> 578, 701 827 <-> 1720 828 <-> 149, 485 829 <-> 1775 830 <-> 807, 1592, 1740 831 <-> 1578 832 <-> 505, 899, 1664 833 <-> 78, 484, 715, 916, 1054, 1403 834 <-> 1435 835 <-> 233, 274 836 <-> 1355, 1364 837 <-> 1032 838 <-> 1675, 1680 839 <-> 881, 1730 840 <-> 794 841 <-> 1250 842 <-> 753 843 <-> 1241, 1330, 1628 844 <-> 641 845 <-> 385, 548 846 <-> 60 847 <-> 180 848 <-> 196, 848 849 <-> 849 850 <-> 850 851 <-> 1392, 1439 852 <-> 593, 1151, 1421 853 <-> 1212, 1574 854 <-> 1051, 1065 855 <-> 866, 1390 856 <-> 48, 411 857 <-> 1018, 1526 858 <-> 1273 859 <-> 1541 860 <-> 343, 628, 732, 1385 861 <-> 1916 862 <-> 248, 1924 863 <-> 644, 1467 864 <-> 911 865 <-> 1115, 1667 866 <-> 684, 855 867 <-> 885, 1594 868 <-> 443 869 <-> 959, 1449 870 <-> 456, 1601, 1916 871 <-> 886 872 <-> 872, 1695 873 <-> 603 874 <-> 1396 875 <-> 1897 876 <-> 1315 877 <-> 1602 878 <-> 1578, 1969 879 <-> 1977 880 <-> 1158 881 <-> 839 882 <-> 770, 1136, 1390, 1544 883 <-> 172 884 <-> 1789 885 <-> 7, 867 886 <-> 871, 886 887 <-> 249, 350, 426 888 <-> 651 889 <-> 1768 890 <-> 1066, 1998 891 <-> 891 892 <-> 613, 942 893 <-> 450, 656 894 <-> 231, 383, 1485 895 <-> 1689 896 <-> 514 897 <-> 1395, 1873 898 <-> 1957 899 <-> 832 900 <-> 137, 1238, 1634, 1640 901 <-> 1563, 1633 902 <-> 911, 1312 903 <-> 279, 1066, 1337 904 <-> 558 905 <-> 799 906 <-> 288 907 <-> 169, 191 908 <-> 908 909 <-> 171, 983, 1309 910 <-> 797, 1540 911 <-> 864, 902, 1303 912 <-> 418 913 <-> 505, 940, 1835 914 <-> 914 915 <-> 553 916 <-> 523, 833 917 <-> 59, 1532 918 <-> 46, 1176, 1864 919 <-> 302, 753 920 <-> 664 921 <-> 200, 922, 1088, 1622 922 <-> 921 923 <-> 302, 409 924 <-> 924 925 <-> 925, 1103 926 <-> 14, 1013 927 <-> 726, 1725 928 <-> 1722 929 <-> 1088, 1932 930 <-> 488, 1719 931 <-> 391, 1750 932 <-> 212, 1258 933 <-> 501, 627 934 <-> 1146, 1693 935 <-> 700, 1713 936 <-> 652, 1530 937 <-> 1012 938 <-> 432 939 <-> 959 940 <-> 155, 327, 604, 913, 1012 941 <-> 280, 1087, 1288 942 <-> 545, 892, 1222 943 <-> 1828 944 <-> 292 945 <-> 708 946 <-> 598 947 <-> 1540, 1593 948 <-> 228 949 <-> 1104 950 <-> 950 951 <-> 1834 952 <-> 122, 586, 952, 1356, 1771, 1909 953 <-> 414, 539, 1876 954 <-> 980, 1199, 1578, 1815 955 <-> 955 956 <-> 269, 774, 956, 1023 957 <-> 1690 958 <-> 425, 1041 959 <-> 625, 869, 939 960 <-> 960 961 <-> 611 962 <-> 1188, 1594 963 <-> 1824 964 <-> 1391, 1982 965 <-> 41, 1332, 1656 966 <-> 143, 438, 1131, 1607 967 <-> 967 968 <-> 1737 969 <-> 263, 1243 970 <-> 825, 1089, 1125, 1988 971 <-> 771 972 <-> 1657 973 <-> 973 974 <-> 338, 547 975 <-> 975, 1213 976 <-> 381, 1860 977 <-> 1235, 1300 978 <-> 162, 321, 1736 979 <-> 979 980 <-> 954, 1493, 1521 981 <-> 774 982 <-> 378, 1687 983 <-> 909, 1581 984 <-> 228 985 <-> 1318 986 <-> 579, 989 987 <-> 1525, 1975 988 <-> 290, 337, 1488 989 <-> 194, 391, 986 990 <-> 1047 991 <-> 1276 992 <-> 224, 1900 993 <-> 300, 1677, 1921 994 <-> 1914 995 <-> 477, 1459, 1717 996 <-> 640 997 <-> 535, 1639 998 <-> 1834 999 <-> 1164, 1352, 1819 1000 <-> 1000 1001 <-> 28, 1001 1002 <-> 202, 611 1003 <-> 3 1004 <-> 1714 1005 <-> 1326, 1494, 1543 1006 <-> 366 1007 <-> 144, 1557 1008 <-> 469, 1029 1009 <-> 514, 1039 1010 <-> 1860 1011 <-> 1649, 1845 1012 <-> 937, 940 1013 <-> 926 1014 <-> 222, 1223 1015 <-> 1800 1016 <-> 1527, 1561 1017 <-> 211, 365, 617, 1452 1018 <-> 857, 1018 1019 <-> 1156, 1427, 1489 1020 <-> 429, 1087 1021 <-> 1197, 1773 1022 <-> 1861 1023 <-> 591, 956, 1846 1024 <-> 1024 1025 <-> 601, 1782 1026 <-> 405, 1026, 1050 1027 <-> 1335 1028 <-> 64, 198, 602 1029 <-> 1008 1030 <-> 545 1031 <-> 566 1032 <-> 40, 246, 837 1033 <-> 219, 1495 1034 <-> 1079, 1190, 1301, 1444, 1579 1035 <-> 81 1036 <-> 1621 1037 <-> 1605 1038 <-> 497, 1514 1039 <-> 229, 1009, 1382, 1965 1040 <-> 1116, 1596 1041 <-> 958 1042 <-> 321, 1171 1043 <-> 445 1044 <-> 306 1045 <-> 1432 1046 <-> 1965 1047 <-> 297, 990, 1047 1048 <-> 1599 1049 <-> 535 1050 <-> 1026 1051 <-> 854 1052 <-> 1410 1053 <-> 1819 1054 <-> 309, 833 1055 <-> 106, 1744 1056 <-> 515, 1919 1057 <-> 560, 1374, 1469, 1559 1058 <-> 1519, 1786 1059 <-> 5, 808 1060 <-> 1275, 1380, 1838 1061 <-> 1951 1062 <-> 173, 540, 1167 1063 <-> 1086 1064 <-> 335 1065 <-> 237, 570, 854 1066 <-> 249, 890, 903, 1854 1067 <-> 661 1068 <-> 341 1069 <-> 1202, 1370, 1844 1070 <-> 461 1071 <-> 404, 588, 1575 1072 <-> 1797 1073 <-> 692 1074 <-> 723, 1074 1075 <-> 352, 797 1076 <-> 152 1077 <-> 373, 483 1078 <-> 1291 1079 <-> 1034 1080 <-> 1915 1081 <-> 1081, 1510 1082 <-> 572, 1981 1083 <-> 316 1084 <-> 47 1085 <-> 1243 1086 <-> 1063, 1086, 1551 1087 <-> 143, 941, 1020, 1480 1088 <-> 921, 929 1089 <-> 57, 970 1090 <-> 613 1091 <-> 143 1092 <-> 1092 1093 <-> 568, 1573 1094 <-> 1458 1095 <-> 129, 694 1096 <-> 150, 1164 1097 <-> 214, 645, 1354, 1462, 1723 1098 <-> 353 1099 <-> 1272 1100 <-> 1386 1101 <-> 1332 1102 <-> 8 1103 <-> 925 1104 <-> 802, 949 1105 <-> 1105, 1304 1106 <-> 658, 1212, 1674 1107 <-> 1642, 1858 1108 <-> 1135, 1509 1109 <-> 344, 1184 1110 <-> 1562 1111 <-> 262, 1214, 1426, 1794 1112 <-> 517 1113 <-> 504, 1113, 1490, 1545 1114 <-> 1670 1115 <-> 865, 1115, 1636 1116 <-> 1040 1117 <-> 1486 1118 <-> 1145 1119 <-> 1393, 1406 1120 <-> 823, 1120, 1518 1121 <-> 726, 1121 1122 <-> 1375 1123 <-> 1123 1124 <-> 124, 384, 1827, 1853 1125 <-> 583, 970 1126 <-> 199 1127 <-> 203, 363, 689, 773, 1341, 1602 1128 <-> 296, 1610 1129 <-> 1562 1130 <-> 1476 1131 <-> 966 1132 <-> 1389 1133 <-> 3, 15 1134 <-> 425 1135 <-> 1108, 1970 1136 <-> 882 1137 <-> 202 1138 <-> 94, 307, 1287 1139 <-> 1139 1140 <-> 1484, 1658 1141 <-> 1361 1142 <-> 132 1143 <-> 7, 1143 1144 <-> 1357 1145 <-> 812, 1118 1146 <-> 567, 934 1147 <-> 1763 1148 <-> 178, 1779 1149 <-> 71 1150 <-> 140, 236, 1699 1151 <-> 38, 852, 1807 1152 <-> 584, 1906 1153 <-> 123 1154 <-> 1435, 1703 1155 <-> 791, 1303 1156 <-> 389, 1019 1157 <-> 237, 576, 1790 1158 <-> 880, 1653 1159 <-> 1836 1160 <-> 676, 1376 1161 <-> 674 1162 <-> 1874 1163 <-> 23, 475 1164 <-> 999, 1096 1165 <-> 100, 538 1166 <-> 641, 723 1167 <-> 1062 1168 <-> 1168, 1927 1169 <-> 530, 1748, 1775, 1995 1170 <-> 1521 1171 <-> 1042 1172 <-> 114, 303, 1687 1173 <-> 124, 163, 1298 1174 <-> 320, 664 1175 <-> 245 1176 <-> 397, 918 1177 <-> 820 1178 <-> 126, 1265 1179 <-> 521, 1926 1180 <-> 214 1181 <-> 1313 1182 <-> 447, 1837 1183 <-> 145, 1299, 1578, 1869 1184 <-> 529, 1109, 1816 1185 <-> 1494, 1972 1186 <-> 227, 1220 1187 <-> 103, 1688 1188 <-> 962 1189 <-> 168, 585 1190 <-> 209, 389, 411, 1034, 1206 1191 <-> 1191, 1477, 1639 1192 <-> 323, 757, 1461 1193 <-> 612, 1193 1194 <-> 108, 369 1195 <-> 716, 1392 1196 <-> 179 1197 <-> 523, 701, 1021 1198 <-> 186 1199 <-> 954 1200 <-> 1562 1201 <-> 88, 462, 1297 1202 <-> 1069 1203 <-> 635, 789 1204 <-> 1204, 1563 1205 <-> 1205, 1219 1206 <-> 1190 1207 <-> 651 1208 <-> 380 1209 <-> 1758 1210 <-> 1469 1211 <-> 1475, 1998 1212 <-> 853, 1106, 1836 1213 <-> 111, 975, 1216, 1932 1214 <-> 1111, 1709 1215 <-> 383 1216 <-> 1213 1217 <-> 110, 1394 1218 <-> 346 1219 <-> 699, 1205 1220 <-> 746, 1186 1221 <-> 1664 1222 <-> 942, 1672, 1946 1223 <-> 284, 1014 1224 <-> 777, 1278, 1655 1225 <-> 592 1226 <-> 687, 809 1227 <-> 529 1228 <-> 524 1229 <-> 1229 1230 <-> 395, 421 1231 <-> 1628 1232 <-> 629 1233 <-> 1732 1234 <-> 1813 1235 <-> 977, 1883 1236 <-> 648, 1539, 1708 1237 <-> 1977 1238 <-> 900 1239 <-> 196, 324, 764 1240 <-> 566, 574, 1516, 1531 1241 <-> 498, 691, 843 1242 <-> 536, 1780 1243 <-> 969, 1085, 1771, 1800 1244 <-> 1637 1245 <-> 1460 1246 <-> 1483, 1911 1247 <-> 233, 519 1248 <-> 353, 1440 1249 <-> 205, 1890 1250 <-> 713, 841, 1702 1251 <-> 722, 1882 1252 <-> 777 1253 <-> 747, 1659 1254 <-> 114 1255 <-> 1512, 1593 1256 <-> 277 1257 <-> 428, 479, 814 1258 <-> 269, 478, 932 1259 <-> 1901, 1920 1260 <-> 423, 1752 1261 <-> 628, 1328 1262 <-> 737 1263 <-> 257, 1943 1264 <-> 1837 1265 <-> 1178, 1958 1266 <-> 76 1267 <-> 46 1268 <-> 299, 1409 1269 <-> 92, 730 1270 <-> 1687 1271 <-> 453, 1457 1272 <-> 370, 534, 1099 1273 <-> 358, 539, 858 1274 <-> 1503 1275 <-> 1060, 1275 1276 <-> 991, 1551 1277 <-> 462 1278 <-> 1224, 1906 1279 <-> 295, 727, 1737 1280 <-> 26, 762 1281 <-> 1825 1282 <-> 4, 415 1283 <-> 745, 1813 1284 <-> 615 1285 <-> 277, 1285 1286 <-> 719, 1302 1287 <-> 156, 1138 1288 <-> 91, 134, 941 1289 <-> 1289 1290 <-> 1418, 1750 1291 <-> 311, 1078, 1291, 1582 1292 <-> 599 1293 <-> 282, 658, 1681, 1983 1294 <-> 155, 226 1295 <-> 293, 780, 1362 1296 <-> 581, 1643 1297 <-> 89, 531, 562, 632, 1201 1298 <-> 1173 1299 <-> 450, 1183, 1299, 1382, 1722 1300 <-> 512, 977, 1903 1301 <-> 509, 1034 1302 <-> 176, 1286, 1561, 1843 1303 <-> 911, 1155, 1850 1304 <-> 419, 524, 1105 1305 <-> 1472 1306 <-> 1615 1307 <-> 785, 1440 1308 <-> 359, 618, 1850 1309 <-> 909, 1984 1310 <-> 1400 1311 <-> 569, 1726 1312 <-> 902, 1830 1313 <-> 1181, 1673, 1945 1314 <-> 1725 1315 <-> 876, 1687 1316 <-> 312, 645 1317 <-> 1496, 1770 1318 <-> 6, 985 1319 <-> 563, 1999 1320 <-> 193, 355, 506 1321 <-> 1436 1322 <-> 562 1323 <-> 301, 623 1324 <-> 1757 1325 <-> 676, 1888 1326 <-> 1005, 1348 1327 <-> 1731 1328 <-> 1261, 1464, 1718 1329 <-> 561 1330 <-> 843 1331 <-> 32, 564, 805 1332 <-> 965, 1101 1333 <-> 549, 1666 1334 <-> 800 1335 <-> 196, 1027, 1534 1336 <-> 788 1337 <-> 903 1338 <-> 1439 1339 <-> 185, 481 1340 <-> 1340 1341 <-> 696, 1127 1342 <-> 188, 1636 1343 <-> 689 1344 <-> 390, 1368 1345 <-> 467, 1345 1346 <-> 140 1347 <-> 264, 387, 552, 1691 1348 <-> 509, 1326 1349 <-> 9, 1829 1350 <-> 384 1351 <-> 1408 1352 <-> 999 1353 <-> 706, 1910 1354 <-> 406, 1097 1355 <-> 836 1356 <-> 281, 952 1357 <-> 1144, 1666, 1701 1358 <-> 1358, 1422 1359 <-> 228, 1359 1360 <-> 266, 1360 1361 <-> 142, 605, 1141, 1364 1362 <-> 540, 1295, 1604 1363 <-> 1686, 1996 1364 <-> 836, 1361, 1554 1365 <-> 772, 1472 1366 <-> 454, 1366 1367 <-> 1367 1368 <-> 465, 1344 1369 <-> 121 1370 <-> 254, 1069 1371 <-> 1371 1372 <-> 158, 400 1373 <-> 321, 377 1374 <-> 13, 1057, 1546 1375 <-> 121, 1122 1376 <-> 0, 22, 1160 1377 <-> 736 1378 <-> 628 1379 <-> 144, 475, 751 1380 <-> 113, 1060 1381 <-> 1649 1382 <-> 401, 1039, 1299 1383 <-> 1383 1384 <-> 300, 1384 1385 <-> 466, 860, 1818 1386 <-> 61, 599, 1100, 1386 1387 <-> 1387 1388 <-> 1685 1389 <-> 676, 761, 1132 1390 <-> 179, 855, 882 1391 <-> 964 1392 <-> 851, 1195, 1553 1393 <-> 1119 1394 <-> 244, 1217, 1973 1395 <-> 897 1396 <-> 874, 1922 1397 <-> 85 1398 <-> 1730, 1905 1399 <-> 1735, 1879, 1885 1400 <-> 7, 1310, 1570 1401 <-> 497 1402 <-> 1402 1403 <-> 833, 1931 1404 <-> 1943 1405 <-> 40, 380, 1407, 1456 1406 <-> 127, 1119, 1502 1407 <-> 1405 1408 <-> 78, 592, 1351 1409 <-> 1268, 1662 1410 <-> 1052, 1618 1411 <-> 531 1412 <-> 396, 464, 757 1413 <-> 367, 1481 1414 <-> 70 1415 <-> 141 1416 <-> 812 1417 <-> 395, 1417 1418 <-> 1290, 1430, 1852 1419 <-> 105, 1762 1420 <-> 765 1421 <-> 554, 571, 852 1422 <-> 202, 1358, 1729 1423 <-> 412, 1665 1424 <-> 783, 1927 1425 <-> 1584 1426 <-> 1111 1427 <-> 1019 1428 <-> 310 1429 <-> 624, 699, 1459 1430 <-> 1418, 1588 1431 <-> 1518 1432 <-> 274, 1045, 1839 1433 <-> 1717 1434 <-> 257, 366 1435 <-> 176, 742, 834, 1154, 1507 1436 <-> 567, 614, 1321 1437 <-> 1572, 1732 1438 <-> 310 1439 <-> 582, 851, 1338, 1751, 1763 1440 <-> 1248, 1307 1441 <-> 478 1442 <-> 254 1443 <-> 1566 1444 <-> 357, 1034, 1844 1445 <-> 787, 1481, 1821 1446 <-> 97 1447 <-> 91 1448 <-> 292, 330 1449 <-> 869, 1748 1450 <-> 1581, 1648 1451 <-> 756, 1742 1452 <-> 1017 1453 <-> 218, 1499 1454 <-> 1454 1455 <-> 725, 735, 736, 1668 1456 <-> 1405 1457 <-> 1271 1458 <-> 579, 1094 1459 <-> 995, 1429, 1848 1460 <-> 794, 1245 1461 <-> 1192 1462 <-> 394, 1097 1463 <-> 1693 1464 <-> 1328 1465 <-> 1, 1901 1466 <-> 42, 221, 1513 1467 <-> 863 1468 <-> 339, 472 1469 <-> 1057, 1210 1470 <-> 588 1471 <-> 33 1472 <-> 1305, 1365, 1872 1473 <-> 1473 1474 <-> 1540, 1700 1475 <-> 1211 1476 <-> 1130, 1718 1477 <-> 1191 1478 <-> 1478 1479 <-> 525, 548 1480 <-> 1087 1481 <-> 1413, 1445, 1740 1482 <-> 1522 1483 <-> 55, 1246 1484 <-> 803, 1140 1485 <-> 894 1486 <-> 1117, 1486 1487 <-> 436, 700 1488 <-> 800, 988 1489 <-> 1019, 1685 1490 <-> 1113 1491 <-> 1546 1492 <-> 720, 1834 1493 <-> 128, 658, 980 1494 <-> 1005, 1185, 1535 1495 <-> 425, 1033, 1727 1496 <-> 399, 821, 1317 1497 <-> 393 1498 <-> 268, 1863 1499 <-> 1453, 1499 1500 <-> 271, 1647 1501 <-> 1733 1502 <-> 1406, 1574, 1960 1503 <-> 134, 1274 1504 <-> 1504 1505 <-> 80, 1711 1506 <-> 29, 381 1507 <-> 17, 1435 1508 <-> 1508, 1774 1509 <-> 1108 1510 <-> 1081 1511 <-> 643, 1562, 1772, 1920 1512 <-> 1255 1513 <-> 1466 1514 <-> 240, 619, 1038 1515 <-> 175, 1748 1516 <-> 255, 1240 1517 <-> 216, 1716, 1936 1518 <-> 1120, 1431 1519 <-> 1058, 1729 1520 <-> 569 1521 <-> 980, 1170 1522 <-> 602, 1482 1523 <-> 408, 552 1524 <-> 693, 1714 1525 <-> 987, 1525 1526 <-> 857, 1805 1527 <-> 1016 1528 <-> 299, 329 1529 <-> 1630, 1736 1530 <-> 936, 1712, 1908 1531 <-> 1240 1532 <-> 256, 917 1533 <-> 44 1534 <-> 1335 1535 <-> 1494 1536 <-> 583 1537 <-> 572 1538 <-> 493, 719 1539 <-> 633, 1236 1540 <-> 910, 947, 1474, 1741 1541 <-> 793, 859, 1793 1542 <-> 70, 160, 1542 1543 <-> 598, 1005 1544 <-> 882 1545 <-> 1113 1546 <-> 1374, 1491, 1716 1547 <-> 344 1548 <-> 1548 1549 <-> 1549 1550 <-> 386 1551 <-> 371, 819, 1086, 1276 1552 <-> 357, 471 1553 <-> 546, 1392 1554 <-> 540, 599, 1364 1555 <-> 185 1556 <-> 6, 573 1557 <-> 1007 1558 <-> 149, 763 1559 <-> 1057, 1559 1560 <-> 347 1561 <-> 1016, 1302 1562 <-> 1110, 1129, 1200, 1511 1563 <-> 901, 1204, 1964 1564 <-> 1564 1565 <-> 247, 670 1566 <-> 596, 699, 1443 1567 <-> 1929 1568 <-> 411 1569 <-> 30, 146, 1571 1570 <-> 1400, 1776 1571 <-> 749, 1569 1572 <-> 813, 1437, 1676 1573 <-> 1093, 1573 1574 <-> 853, 1502 1575 <-> 1071 1576 <-> 559, 1842 1577 <-> 58, 153, 752 1578 <-> 2, 451, 831, 878, 954, 1183 1579 <-> 1034 1580 <-> 332, 491 1581 <-> 983, 1450, 1942 1582 <-> 1291, 1824 1583 <-> 252, 1998 1584 <-> 1425, 1584 1585 <-> 1851 1586 <-> 601, 1877 1587 <-> 40, 257, 1713 1588 <-> 101, 1430 1589 <-> 1589 1590 <-> 47, 561 1591 <-> 1605 1592 <-> 577, 600, 830 1593 <-> 947, 1255 1594 <-> 867, 962 1595 <-> 424 1596 <-> 1040, 1687 1597 <-> 581, 1619 1598 <-> 546, 1778 1599 <-> 175, 1048 1600 <-> 408, 1938 1601 <-> 870 1602 <-> 721, 877, 1127 1603 <-> 553, 1955 1604 <-> 50, 1362 1605 <-> 327, 1037, 1591 1606 <-> 1875, 1887 1607 <-> 452, 705, 966 1608 <-> 96, 448 1609 <-> 427, 755 1610 <-> 1128 1611 <-> 247, 302 1612 <-> 1612 1613 <-> 465 1614 <-> 1841 1615 <-> 529, 1306 1616 <-> 1849 1617 <-> 674 1618 <-> 1410, 1758 1619 <-> 1597 1620 <-> 654, 1778 1621 <-> 1036, 1779 1622 <-> 921, 1851 1623 <-> 100, 358 1624 <-> 1728 1625 <-> 823 1626 <-> 1743 1627 <-> 663 1628 <-> 843, 1231 1629 <-> 502 1630 <-> 532, 1529 1631 <-> 414 1632 <-> 56, 1632 1633 <-> 432, 718, 901 1634 <-> 900, 1857 1635 <-> 1675, 1925 1636 <-> 1115, 1342, 1912 1637 <-> 255, 1244 1638 <-> 217, 473 1639 <-> 382, 997, 1191 1640 <-> 900 1641 <-> 761 1642 <-> 1107 1643 <-> 1296, 1643 1644 <-> 1945 1645 <-> 1997 1646 <-> 634 1647 <-> 1500 1648 <-> 360, 1450 1649 <-> 40, 1011, 1381, 1958 1650 <-> 50 1651 <-> 398 1652 <-> 560, 644 1653 <-> 1158, 1749 1654 <-> 1654 1655 <-> 495, 1224 1656 <-> 187, 204, 965 1657 <-> 122, 265, 972 1658 <-> 1140, 1658, 1718, 1744 1659 <-> 29, 359, 1253 1660 <-> 445, 1978 1661 <-> 167, 437 1662 <-> 342, 713, 1409 1663 <-> 1758, 1937 1664 <-> 677, 832, 1221, 1788 1665 <-> 443, 1423 1666 <-> 243, 1333, 1357, 1666 1667 <-> 758, 865, 1896 1668 <-> 95, 1455 1669 <-> 639, 1686, 1761 1670 <-> 558, 1114, 1670 1671 <-> 1769 1672 <-> 1222 1673 <-> 212, 1313 1674 <-> 494, 1106 1675 <-> 838, 1635 1676 <-> 1572 1677 <-> 455, 993 1678 <-> 256 1679 <-> 513 1680 <-> 616, 838, 1928 1681 <-> 1293 1682 <-> 656, 1881 1683 <-> 640, 1827 1684 <-> 670 1685 <-> 1388, 1489 1686 <-> 1363, 1669 1687 <-> 982, 1172, 1270, 1315, 1596, 1913 1688 <-> 174, 1187 1689 <-> 338, 895 1690 <-> 78, 957, 1764 1691 <-> 1347 1692 <-> 818 1693 <-> 934, 1463 1694 <-> 338, 392, 435 1695 <-> 815, 872 1696 <-> 1696 1697 <-> 768, 1697 1698 <-> 620 1699 <-> 306, 1150 1700 <-> 348, 660, 1474 1701 <-> 1357 1702 <-> 562, 1250 1703 <-> 38, 1154 1704 <-> 517 1705 <-> 433, 688, 1895 1706 <-> 102, 785 1707 <-> 505 1708 <-> 1236 1709 <-> 192, 1214 1710 <-> 702, 1791, 1840 1711 <-> 10, 1505 1712 <-> 1530 1713 <-> 335, 542, 935, 1587, 1923 1714 <-> 674, 1004, 1524, 1793 1715 <-> 491, 724, 1738 1716 <-> 1517, 1546, 1891 1717 <-> 11, 995, 1433 1718 <-> 1328, 1476, 1658 1719 <-> 930 1720 <-> 278, 827, 1798 1721 <-> 407, 468 1722 <-> 928, 1299, 1754, 1939 1723 <-> 1097 1724 <-> 683 1725 <-> 452, 927, 1314 1726 <-> 402, 766, 1311 1727 <-> 1495 1728 <-> 1624, 1937 1729 <-> 1422, 1519 1730 <-> 378, 839, 1398 1731 <-> 239, 513, 1327 1732 <-> 285, 1233, 1437 1733 <-> 1501, 1844 1734 <-> 345, 1759 1735 <-> 292, 1399 1736 <-> 346, 978, 1529 1737 <-> 968, 1279, 1737 1738 <-> 1715, 1809 1739 <-> 109 1740 <-> 669, 830, 1481 1741 <-> 1540 1742 <-> 189, 1451 1743 <-> 584, 1626 1744 <-> 1055, 1658 1745 <-> 745 1746 <-> 336, 1957, 1997 1747 <-> 652 1748 <-> 1169, 1449, 1515 1749 <-> 276, 1653, 1940 1750 <-> 710, 931, 1290 1751 <-> 682, 1439 1752 <-> 589, 1260 1753 <-> 1806 1754 <-> 1722 1755 <-> 1846 1756 <-> 775, 1756 1757 <-> 1324, 1757 1758 <-> 1209, 1618, 1663 1759 <-> 1734 1760 <-> 243, 594 1761 <-> 1669, 1878 1762 <-> 521, 537, 1419 1763 <-> 1147, 1439 1764 <-> 630, 1690 1765 <-> 616 1766 <-> 1833 1767 <-> 65 1768 <-> 139, 273, 742, 801, 889, 1781 1769 <-> 689, 1671 1770 <-> 1317, 1770 1771 <-> 449, 735, 952, 1243 1772 <-> 1511 1773 <-> 1021 1774 <-> 1508 1775 <-> 829, 1169 1776 <-> 1570 1777 <-> 272, 289, 737, 1950 1778 <-> 1598, 1620 1779 <-> 400, 1148, 1621 1780 <-> 1242 1781 <-> 1768 1782 <-> 519, 1025 1783 <-> 1836 1784 <-> 486 1785 <-> 333 1786 <-> 1058 1787 <-> 1858 1788 <-> 1664 1789 <-> 35, 884 1790 <-> 1157 1791 <-> 138, 1710, 1847 1792 <-> 1792 1793 <-> 1541, 1714 1794 <-> 645, 771, 1111 1795 <-> 1795 1796 <-> 1966 1797 <-> 1072, 1944 1798 <-> 1720, 1834 1799 <-> 655 1800 <-> 1015, 1243 1801 <-> 1801 1802 <-> 1802 1803 <-> 393 1804 <-> 1967 1805 <-> 1526 1806 <-> 669, 1753 1807 <-> 1151, 1844 1808 <-> 199 1809 <-> 256, 1738, 1918 1810 <-> 1810, 1840 1811 <-> 85 1812 <-> 5, 602 1813 <-> 130, 1234, 1283 1814 <-> 742 1815 <-> 954 1816 <-> 1184 1817 <-> 1817 1818 <-> 706, 792, 1385 1819 <-> 999, 1053 1820 <-> 102 1821 <-> 532, 1445 1822 <-> 361 1823 <-> 287 1824 <-> 963, 1582 1825 <-> 22, 230, 1281, 1861 1826 <-> 730, 1826 1827 <-> 678, 1124, 1683, 1880 1828 <-> 606, 943 1829 <-> 154, 587, 1349 1830 <-> 626, 1312 1831 <-> 593 1832 <-> 37, 1832 1833 <-> 1766, 1833 1834 <-> 584, 951, 998, 1492, 1798 1835 <-> 913 1836 <-> 555, 631, 1159, 1212, 1783 1837 <-> 1182, 1264 1838 <-> 1060 1839 <-> 1432 1840 <-> 1710, 1810 1841 <-> 261, 1614, 1867 1842 <-> 1576 1843 <-> 776, 1302 1844 <-> 622, 1069, 1444, 1733, 1807 1845 <-> 1011 1846 <-> 1023, 1755 1847 <-> 1791 1848 <-> 1459 1849 <-> 751, 1616 1850 <-> 1303, 1308 1851 <-> 1585, 1622 1852 <-> 1418 1853 <-> 1124 1854 <-> 1066 1855 <-> 381 1856 <-> 1925 1857 <-> 305, 744, 1634 1858 <-> 1107, 1787, 1858 1859 <-> 458 1860 <-> 976, 1010 1861 <-> 551, 1022, 1825 1862 <-> 500 1863 <-> 248, 1498 1864 <-> 402, 918 1865 <-> 314, 642 1866 <-> 1866 1867 <-> 1841, 1867 1868 <-> 532 1869 <-> 374, 1183, 1994 1870 <-> 507, 802 1871 <-> 325 1872 <-> 87, 492, 1472 1873 <-> 90, 509, 897 1874 <-> 220, 1162, 1957 1875 <-> 63, 1606 1876 <-> 65, 953 1877 <-> 259, 1586, 1907 1878 <-> 1761, 1989 1879 <-> 1399 1880 <-> 1827 1881 <-> 1682 1882 <-> 510, 1251 1883 <-> 531, 1235 1884 <-> 1884 1885 <-> 1399, 1885 1886 <-> 814 1887 <-> 3, 1606 1888 <-> 1325 1889 <-> 1 1890 <-> 628, 1249 1891 <-> 1716 1892 <-> 118 1893 <-> 400, 570 1894 <-> 637, 1937 1895 <-> 526, 1705 1896 <-> 1667, 1991 1897 <-> 875, 1976 1898 <-> 798 1899 <-> 297 1900 <-> 992 1901 <-> 1259, 1465 1902 <-> 494, 1917 1903 <-> 480, 1300 1904 <-> 545 1905 <-> 1398 1906 <-> 1152, 1278 1907 <-> 84, 731, 1877 1908 <-> 1530 1909 <-> 952 1910 <-> 1353 1911 <-> 686, 795, 1246 1912 <-> 1636 1913 <-> 1687 1914 <-> 118, 994, 1914 1915 <-> 1080, 1993 1916 <-> 326, 861, 870 1917 <-> 403, 720, 1902, 1933 1918 <-> 71, 1809 1919 <-> 1056 1920 <-> 559, 1259, 1511 1921 <-> 993 1922 <-> 663, 1396 1923 <-> 1713 1924 <-> 166, 862 1925 <-> 1635, 1856 1926 <-> 1179 1927 <-> 1168, 1424 1928 <-> 1680, 1928 1929 <-> 729, 1567 1930 <-> 238, 1933 1931 <-> 1403 1932 <-> 322, 929, 1213 1933 <-> 1917, 1930 1934 <-> 407 1935 <-> 456 1936 <-> 1517 1937 <-> 461, 1663, 1728, 1894, 1937 1938 <-> 1600 1939 <-> 1722 1940 <-> 1749 1941 <-> 755 1942 <-> 1581, 1967 1943 <-> 1263, 1404 1944 <-> 71, 1797 1945 <-> 398, 1313, 1644 1946 <-> 1222, 1946 1947 <-> 1998 1948 <-> 503 1949 <-> 520 1950 <-> 1777 1951 <-> 71, 152, 397, 1061 1952 <-> 500 1953 <-> 199, 642 1954 <-> 230, 356, 675 1955 <-> 1603 1956 <-> 181 1957 <-> 501, 898, 1746, 1874 1958 <-> 1265, 1649 1959 <-> 449 1960 <-> 1502 1961 <-> 1961 1962 <-> 302, 783 1963 <-> 345 1964 <-> 1563 1965 <-> 197, 1039, 1046 1966 <-> 127, 1796 1967 <-> 314, 1804, 1942 1968 <-> 12, 110 1969 <-> 316, 878 1970 <-> 442, 1135 1971 <-> 693 1972 <-> 1185 1973 <-> 1394, 1973 1974 <-> 71 1975 <-> 52, 987 1976 <-> 341, 1897 1977 <-> 197, 879, 1237 1978 <-> 1660 1979 <-> 336 1980 <-> 321, 465 1981 <-> 1082 1982 <-> 964, 1982 1983 <-> 1293 1984 <-> 301, 638, 1309 1985 <-> 635 1986 <-> 631 1987 <-> 92 1988 <-> 970 1989 <-> 1878, 1989 1990 <-> 565 1991 <-> 1896 1992 <-> 241, 334 1993 <-> 466, 1915 1994 <-> 1869 1995 <-> 741, 1169 1996 <-> 1363 1997 <-> 1645, 1746 1998 <-> 890, 1211, 1583, 1947 1999 <-> 379, 1319 pathfinding-4.14.0/tests/aoc-2020-10.rs000064400000000000000000000010321046102023000152520ustar 00000000000000use pathfinding::directed::count_paths::count_paths; #[test] fn part2() { let mut adapters: Vec = include_str!("aoc-2020-10.txt") .lines() .map(|x| x.parse().unwrap()) .collect(); adapters.sort_unstable(); let &last = adapters.last().unwrap(); let n = count_paths( 0, |&x| { adapters .iter() .filter(move |&&y| y > x && y <= x + 3) .copied() }, |&x| x == last, ); assert_eq!(n, 19208); } pathfinding-4.14.0/tests/aoc-2020-10.txt000064400000000000000000000001261046102023000154500ustar 0000000000000028 33 18 42 31 14 46 20 48 47 24 23 49 45 19 38 39 11 1 32 25 35 8 17 7 9 4 2 34 10 3 pathfinding-4.14.0/tests/aoc-2021-12.rs000064400000000000000000000030541046102023000152630ustar 00000000000000use std::collections::HashMap; use itertools::Itertools; use pathfinding::directed::count_paths::count_paths; fn input(input: &str) -> HashMap<&str, Vec<&str>> { let mut map: HashMap<&str, Vec<&str>> = HashMap::new(); for line in input.lines() { let (a, b) = line.split_once('-').unwrap(); map.entry(a).or_default().push(b); map.entry(b).or_default().push(a); } map } #[derive(PartialEq, Eq, Hash, Clone)] struct State<'a> { current: &'a str, small_caves: Vec<&'a str>, small_cave_twice: bool, } fn solve(small_cave_twice: bool) -> usize { let map = input(include_str!("aoc-2021-12.txt")); count_paths( State { current: "start", small_caves: Vec::new(), small_cave_twice, }, |c| { map[&c.current] .iter() .filter(|&&x| x != "start" && (!c.small_caves.contains(&x) || c.small_cave_twice)) .map(move |x| State { current: x, small_caves: c .small_caves .iter() .copied() .chain((x.as_bytes()[0] >= b'a').then_some(*x)) .collect(), small_cave_twice: c.small_cave_twice && !c.small_caves.contains(x), }) .collect_vec() }, |c| c.current == "end", ) } #[test] fn part1() { assert_eq!(solve(false), 226); } #[test] fn part2() { assert_eq!(solve(true), 3509); } pathfinding-4.14.0/tests/aoc-2021-12.txt000064400000000000000000000001671046102023000154600ustar 00000000000000fs-end he-DX fs-he start-DX pj-DX end-zg zg-sl zg-pj pj-he RW-he fs-DX pj-RW zg-RW start-pj he-WI zg-he pj-fs start-RW pathfinding-4.14.0/tests/aoc-2023-17.rs000064400000000000000000000031761046102023000152770ustar 00000000000000use pathfinding::{directed::dijkstra::dijkstra, matrix::Matrix}; static TEST_INPUT: &str = " 2413432311323 3215453535623 3255245654254 3446585845452 4546657867536 1438598798454 4457876987766 3637877979653 4654967986887 4564679986453 1224686865563 2546548887735 4322674655533 "; static TEST_INPUT_2: &str = " 111111111111 999999999991 999999999991 999999999991 999999999991 "; fn part1(input: &str) -> u32 { part(input, 1, 3) } fn part2(input: &str) -> u32 { part(input, 4, 10) } fn part(input: &str, min_move: usize, max_move: usize) -> u32 { let grid = Matrix::from_rows( input .trim() .lines() .map(|l| l.chars().filter_map(|c| c.to_digit(10))), ) .unwrap(); dijkstra( &((0, 0), (0, 0), 0), |&(pos, (dr, dc), l)| { let mut next = Vec::with_capacity(3); let mut e = |dir, l| { next.extend( &grid .move_in_direction(pos, dir) .map(|t| ((t, dir, l), grid[t])), ); }; if l < max_move { e((dr, dc), l + 1); } if l >= min_move { e((-dc, -dr), 1); e((dc, dr), 1); } else if l == 0 { e((1, 0), 1); e((0, 1), 1); } next }, |&(pos, _, l)| pos == (grid.rows - 1, grid.columns - 1) && l >= min_move, ) .unwrap() .1 } #[test] fn aoc_2023_17() { assert_eq!(102, part1(TEST_INPUT)); assert_eq!(94, part2(TEST_INPUT)); assert_eq!(71, part2(TEST_INPUT_2)); } pathfinding-4.14.0/tests/astar_bag.rs000064400000000000000000000025601046102023000156430ustar 00000000000000use itertools::Itertools; use pathfinding::directed::astar::astar_bag; #[test] fn multiple_sinks() { // 1 --> 2 --> 4 // --> 3 --> 4 // // 2 --> 5 --> 6 --> 7 // 3 --> 5 --> 6 --> 7 let (solutions, cost) = astar_bag( &1, |&n| match n { 1 => vec![(2, 1), (3, 1)], 2 | 3 => vec![(4, 3), (5, 1)], 5 => vec![(6, 1)], 6 => vec![(7, 1)], _ => vec![], }, |_| 0, |&n| n == 4 || n == 7, ) .unwrap(); assert_eq!(cost, 4); assert_eq!( solutions.sorted().collect_vec(), vec![ vec![1, 2, 4], vec![1, 2, 5, 6, 7], vec![1, 3, 4], vec![1, 3, 5, 6, 7], ] ); } #[test] fn numerous_solutions() { const N: usize = 10; const GOAL: usize = 3 * N; // ---> 1 -- // / | \ // 0-- | --> 3 … --> 3*N with 2^N paths and a cost of 2*N // \ v / (path from 1 to 2 is unused) // ---> 2 -- let (solutions, cost) = astar_bag( &0, |&n| match n { x if x % 3 == 2 => vec![(x + 1, 1)], x => vec![(x + 1, 1), (x + 2, 1)], }, |&n| GOAL.saturating_sub(n) / 2, |&n| n == GOAL, ) .unwrap(); assert_eq!(cost, N * 2); assert_eq!(solutions.count(), 1 << N); } pathfinding-4.14.0/tests/check-msrv-consistency.sh000075500000000000000000000003061046102023000203060ustar 00000000000000#! /bin/sh # set -e MSRV=$(awk -F '"' '/^rust-version =/ {print $2}' < Cargo.toml) if ! grep "Rust $MSRV" src/lib.rs > /dev/null 2>&1; then echo "MSRV $MSRV not found in src/lib.rs" exit 1 fi pathfinding-4.14.0/tests/cliques.rs000064400000000000000000000024021046102023000153600ustar 00000000000000use std::collections::HashSet; use itertools::Itertools; use pathfinding::prelude::*; #[test] fn find_cliques() { let vertices: Vec = (1..10).collect_vec(); let cliques = maximal_cliques_collect(&vertices, &mut |a, b| (*a - *b) % 3 == 0); let cliques_as_vectors: Vec> = sort(&cliques); assert_eq!( vec![vec![1, 4, 7], vec![2, 5, 8], vec![3, 6, 9]], cliques_as_vectors ); } #[test] fn test_same_node_appears_in_multiple_clique() { let vertices: Vec = (1..10).collect_vec(); let cliques = maximal_cliques_collect(&vertices, &mut |a, b| { (*a % 3 == 0) && (*b % 3 == 0) || ((*a - *b) % 4 == 0) }); let cliques_as_vectors: Vec> = sort(&cliques); assert_eq!( vec![ vec![1, 5, 9], vec![2, 6], vec![3, 6, 9], vec![3, 7], vec![4, 8] ], cliques_as_vectors ); } fn sort(cliques: &[HashSet<&i32>]) -> Vec> { let mut cliques_as_vectors: Vec> = cliques .iter() .map(|cliq| { let mut s = cliq.iter().map(|&x| *x).collect_vec(); s.sort_unstable(); s }) .collect(); cliques_as_vectors.sort(); cliques_as_vectors } pathfinding-4.14.0/tests/codejam-2017-a.rs000064400000000000000000000114631046102023000161310ustar 00000000000000// Problem A from the Google Code Jam finals 2017. // https://code.google.com/codejam/contest/dashboard?c=6314486#s=p0&a=0 use pathfinding::prelude::*; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::io::prelude::*; use std::io::{self, Cursor}; use std::num::ParseIntError; #[derive(Debug)] #[allow(dead_code)] enum Error { Io(io::Error), Parse(ParseIntError), } impl From for Error { fn from(err: io::Error) -> Self { Self::Io(err) } } impl From for Error { fn from(err: ParseIntError) -> Self { Self::Parse(err) } } fn read_ints(file: &mut dyn BufRead) -> Result, Error> { let mut s = String::new(); file.read_line(&mut s)?; s.pop(); s.split(' ') .map(|w| w.parse::().map_err(Into::into)) .collect() } fn test>(n: usize, file: &mut dyn BufRead) -> Result { let n_dices = read_ints(file)?[0]; let mut dices = Vec::new(); let mut values = HashMap::new(); for d in 0..n_dices { let mut dice = read_ints(file)?; for v in dice.clone() { values.entry(v).or_insert_with(HashSet::new).insert(d); } dice.sort_unstable(); dices.push(dice); } let mut groups: Vec> = Vec::new(); let mut keys = values.keys().collect::>(); keys.sort(); for &v in keys { if groups.is_empty() || *groups.last().unwrap().last().unwrap() != v - 1 { groups.push(vec![v]); } else { groups.last_mut().unwrap().push(v); } } let answer = groups .into_iter() .map(|group| { // Extract the dices used for this group. let subdices = group .iter() .flat_map(|&v| values[&v].clone()) .collect::>() .into_iter() .enumerate() .map(|(a, b)| (b, a)) .collect::>(); // Source is 0, sink is 1. Group members are 2 .. 2 + group.len(), dices are // 2 + group.len() .. 2 + group.len() + dices.len() let value_offset = 2; let dice_offset = value_offset + group.len(); let size = dice_offset + subdices.len(); let mut ek = EK::new(size, 0, 1); ek.omit_details(); // Set capacity 1 between each value and the dice holding this value. let smallest_value = group[0]; for &value in &group { for dice in &values[&value] { ek.set_capacity( value - smallest_value + value_offset, subdices[dice] + dice_offset, 1, ); } } // Set capacity 1 between each dice and the sink. for i in 0..subdices.len() { ek.set_capacity(i + dice_offset, 1, 1); } // Add path from the source to the first value. ek.set_capacity(0, value_offset, 1); let mut bi = 0; let mut ei = 1; let mut max = 0; loop { let (_, n, _) = ek.augment(); debug_assert!(n >= 0); #[allow(clippy::cast_sign_loss)] let n = n as usize; if n > max { max = n; } if max >= group.len() - bi { break; } if n == ei - bi { if ei == group.len() { break; } // Add path from source to value group[ei] ek.set_capacity(0, group[ei] - smallest_value + value_offset, 1); ei += 1; } else { // Remove path from source to value group[bi] ek.set_capacity(0, group[bi] - smallest_value + value_offset, 0); bi += 1; if bi == ei { ei += 1; } } } max }) .max() .unwrap(); Ok(format!("Case #{n}: {answer}")) } fn codejam>() { let mut file = Cursor::new(include_str!("A-small-practice.in")); let ntests = read_ints(&mut file).expect("cannot read number of test cases")[0]; let mut out = String::new(); for n in 1..=ntests { out += &test::(n, &mut file).expect("problem with test"); out += "\n"; } let expected = include_str!("A-small-practice.out"); assert_eq!(out, expected, "answers do not match"); } #[test] fn codejam_dense() { codejam::>(); } #[test] fn codejam_sparse() { codejam::>(); } pathfinding-4.14.0/tests/connected-components.rs000064400000000000000000000112611046102023000200430ustar 00000000000000use itertools::Itertools; use pathfinding::undirected::connected_components::*; use rand::prelude::*; use rand_xorshift::XorShiftRng; use std::collections::HashSet; #[test] fn basic_separate_components() { let groups = [vec![1, 2], vec![3, 4], vec![5, 6], vec![1, 4]]; let (h, g) = separate_components(&groups); assert!([1, 2, 3, 4].iter().map(|n| h[n]).all_equal()); assert_eq!(h[&5], h[&6]); assert!(h[&1] != h[&5]); assert_eq!(h.len(), 6); assert_eq!(g[0], g[1]); assert_eq!(g[0], g[3]); assert!(g[0] != g[2]); assert_eq!(g.len(), 4); } #[test] fn empty_separate_components() { let groups = [vec![1, 2], vec![3, 4], vec![], vec![1, 4]]; let (h, g) = separate_components(&groups); assert!([1, 2, 3, 4].iter().map(|n| h[n]).all_equal()); assert_eq!(h.len(), 4); assert_eq!(g[0], g[1]); assert_eq!(g[0], g[3]); assert!(g[0] != g[2]); assert_eq!(g[2], usize::MAX); assert_eq!(g.len(), 4); } #[test] fn basic_components() { let mut c = components(&[vec![1, 2], vec![3, 4], vec![5, 6], vec![1, 4, 7]]); c.sort_unstable_by_key(|v| *v.iter().min().unwrap()); assert_eq!(c.len(), 2); assert_eq!( c[0].clone().into_iter().sorted().collect_vec(), vec![1, 2, 3, 4, 7] ); assert_eq!(c[1].clone().into_iter().sorted().collect_vec(), vec![5, 6]); } #[test] fn empty_components() { let mut c = components(&[vec![1, 2], vec![3, 4], vec![], vec![1, 4, 7]]); c.sort_unstable_by_key(|v| *v.iter().min().unwrap()); assert_eq!(c.len(), 1); assert_eq!( c[0].clone().into_iter().sorted().collect_vec(), vec![1, 2, 3, 4, 7] ); } #[test] fn basic_connected_components() { let mut counter = 0; let mut c = connected_components(&[1, 4], |&n| { counter += 1; if n % 2 == 0 { vec![2, 4, 6, 8] } else { vec![1, 3, 5, 7] } }); c.sort_unstable_by_key(|v| *v.iter().min().unwrap()); assert_eq!(c.len(), 2); assert_eq!( c[0].clone().into_iter().sorted().collect_vec(), vec![1, 3, 5, 7] ); assert_eq!( c[1].clone().into_iter().sorted().collect_vec(), vec![2, 4, 6, 8] ); assert_eq!(counter, 2); } #[test] fn larger_separate_components() { // Create 100 groups of 100 elements, then randomly split // into sub-groups. let mut rng = XorShiftRng::from_seed([ 3, 42, 93, 129, 1, 85, 72, 42, 84, 23, 95, 212, 253, 10, 4, 2, ]); let mut seen = HashSet::new(); let mut components = (0..100) .map(|_| { let mut component = Vec::new(); for _ in 0..100 { let node = rng.next_u64(); if !seen.contains(&node) { seen.insert(node); component.push(node); } } component.sort_unstable(); assert!( !component.is_empty(), "component is empty, rng seed needs changing" ); component }) .collect_vec(); components.sort_unstable_by_key(|v| *v.iter().min().unwrap()); let mut groups = components .iter() .flat_map(|component| { let mut component = component.clone(); component.shuffle(&mut rng); let mut subcomponents = Vec::new(); while !component.is_empty() { let cut = rng.gen_range(0..component.len()); let mut subcomponent = component.drain(cut..).collect_vec(); if !component.is_empty() { subcomponent.push(component[0]); } subcomponent.shuffle(&mut rng); subcomponents.push(subcomponent); } subcomponents }) .collect_vec(); groups.shuffle(&mut rng); let (_, group_mappings) = separate_components(&groups); let mut out_groups = vec![HashSet::new(); groups.len()]; for (i, n) in group_mappings.into_iter().enumerate() { assert!( n < groups.len(), "group index is greater than expected: {}/{}", n, groups.len() ); for e in &groups[i] { out_groups[n].insert(*e); } } let out_groups = out_groups .into_iter() .map(|g| g.into_iter().collect_vec()) .collect_vec(); let mut out_groups = out_groups .into_iter() .filter_map(|mut group| { if group.is_empty() { None } else { group.sort_unstable(); Some(group) } }) .collect_vec(); out_groups.sort_by_key(|c| c[0]); assert_eq!(out_groups, components); } pathfinding-4.14.0/tests/count_paths.rs000064400000000000000000000005021046102023000162410ustar 00000000000000use pathfinding::directed::count_paths::count_paths; #[test] fn grid() { let n = count_paths( (0, 0), |&(x, y)| { [(x + 1, y), (x, y + 1)] .into_iter() .filter(|&(x, y)| x < 8 && y < 8) }, |&c| c == (7, 7), ); assert_eq!(n, 3432); } pathfinding-4.14.0/tests/cycle_detection.rs000064400000000000000000000003431046102023000170520ustar 00000000000000use pathfinding::directed::cycle_detection::*; #[test] fn floyd_works() { assert_eq!(floyd(-10, |x| (x + 5) % 6 + 3), (3, 6, 2)); } #[test] fn brent_works() { assert_eq!(brent(-10, |x| (x + 5) % 6 + 3), (3, 6, 2)); } pathfinding-4.14.0/tests/dfs-reach.rs000064400000000000000000000006761046102023000155620ustar 00000000000000use pathfinding::directed::dfs::dfs_reach; #[test] fn issue_511() { let it = dfs_reach(0, |&n| [n + 1, n + 5].into_iter().filter(|&x| x <= 10)); assert_eq!( vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], it.collect::>() ); } #[test] fn issue_511_branches() { let it = dfs_reach(0, |&n| [n + 2, n + 5].into_iter().filter(|&x| x <= 10)); assert_eq!(vec![0, 2, 4, 6, 8, 10, 9, 7, 5], it.collect::>()); } pathfinding-4.14.0/tests/dijkstra-all.rs000064400000000000000000000073401046102023000163020ustar 00000000000000use pathfinding::prelude::*; use rand::{rngs, Rng as _}; fn build_network(size: usize) -> Matrix { let mut network = Matrix::new(size, size, 0); let mut rng = rngs::OsRng; for a in 0..size { for b in 0..size { if rng.gen_ratio(2, 3) { network[(a, b)] = rng.r#gen::() as usize; } } } network } fn neighbours(network: Matrix) -> impl FnMut(&usize) -> Vec<(usize, usize)> { move |&a| { (0..network.rows) .filter_map(|b| match network[(a, b)] { 0 => None, p => Some((b, p)), }) .collect() } } #[test] fn all_paths() { const SIZE: usize = 30; let network = build_network(SIZE); for start in 0..SIZE { let paths = dijkstra_all(&start, neighbours(network.clone())); for target in 0..SIZE { if let Some((path, cost)) = dijkstra(&start, neighbours(network.clone()), |&n| n == target) { if start == target { assert!( !paths.contains_key(&target), "path {start} -> {target} is present in {network:?}" ); } else { assert!( paths.contains_key(&target), "path {start} -> {target} is not found in {network:?}" ); assert_eq!( cost, paths[&target].1, "cost differ in path {start} -> {target} in {network:?}" ); let other_path = build_path(&target, &paths); // There might be several paths, but we know that internally we use the // same algorithm so the comparison holds. assert_eq!(path, other_path, "path {start} -> {target} differ in {network:?}: {path:?} vs {other_path:?}"); } } else { assert!( !paths.contains_key(&target), "path {start} -> {target} is present in {network:?}" ); } } } } #[test] fn partial_paths() { const SIZE: usize = 100; let network = build_network(SIZE); for start in 0..SIZE { let (paths, reached) = dijkstra_partial(&start, neighbours(network.clone()), |&n| { start != 0 && n != 0 && n != start && n % start == 0 }); if let Some(target) = reached { assert!(target % start == 0, "bad stop condition"); // We cannot compare other paths since there is no guarantee that the // paths variable is up-to-date as the algorithm stopped prematurely. let cost = paths[&target].1; let (path, dijkstra_cost) = dijkstra(&start, neighbours(network.clone()), |&n| n == target).unwrap(); assert_eq!( cost, dijkstra_cost, "costs {start} -> {target} differ in {network:?}" ); let other_path = build_path(&target, &paths); // There might be several paths, but we know that internally we use the // same algorithm so the comparison holds. assert_eq!( path, other_path, "path {start} -> {target} differ in {network:?}: {path:?} vs {other_path:?}" ); } else if start != 0 && start <= (SIZE - 1) / 2 { for target in 1..(SIZE / start) { assert!( dijkstra(&start, neighbours(network.clone()), |&n| n == target).is_none(), "path {start} -> {target} found in {network:?}" ); } } } } pathfinding-4.14.0/tests/dijkstra-reach.rs000064400000000000000000000034441046102023000166150ustar 00000000000000use itertools::Itertools; use pathfinding::prelude::{dijkstra_reach, DijkstraReachableItem}; use std::collections::HashMap; #[test] fn dijkstra_reach_numbers() { let reach = dijkstra_reach(&0, |prev| vec![(prev + 1, 1), (prev * 2, *prev)]) .take_while(|x| x.total_cost < 100) .collect_vec(); // the total cost should equal to the node's value, since the starting node is 0 and the cost to reach a successor node is equal to the increase in the node's value assert!(reach.iter().all(|x| x.node == x.total_cost)); assert!((0..100).all(|x| reach.iter().any(|y| x == y.total_cost))); // dijkstra_reach should return reachable nodes in order of cost assert!(reach .iter() .map(|x| x.total_cost) .tuple_windows() .all(|(a, b)| b >= a)); } #[test] fn dijkstra_reach_graph() { // 2 2 // A --> B --> C // \__________/ // 5 let mut graph = HashMap::new(); graph.insert("A", vec![("B", 2), ("C", 5)]); graph.insert("B", vec![("C", 2)]); graph.insert("C", vec![]); let reach = dijkstra_reach(&"A", |prev| graph[prev].clone()).collect_vec(); // need to make sure that a node won't be returned twice when a better path is found after the first candidate assert!( reach == vec![ DijkstraReachableItem { node: "A", parent: None, total_cost: 0, }, DijkstraReachableItem { node: "B", parent: Some("A"), total_cost: 2, }, DijkstraReachableItem { node: "C", parent: Some("B"), total_cost: 4, }, ] ); } pathfinding-4.14.0/tests/edmondskarp.rs000064400000000000000000000167311046102023000162340ustar 00000000000000use pathfinding::directed::edmonds_karp::*; use std::collections::HashMap; /// Return a list of edges with their capacities. fn successors_wikipedia() -> Vec<((char, char), i32)> { vec![ ("AB", 3), ("AD", 3), ("BC", 4), ("CA", 3), ("CD", 1), ("CE", 2), ("DE", 2), ("DF", 6), ("EB", 1), ("EG", 1), ("FG", 9), ] .into_iter() .map(|(s, c)| { let mut name = s.chars(); ((name.next().unwrap(), name.next().unwrap()), c) }) .collect() } fn check_wikipedia_result(flows: EKFlows) { let (caps, total, mut cut) = flows; assert_eq!(caps.len(), 8); let caps = HashMap::<(char, char), i32>::from_iter(caps); assert_eq!(caps[&('A', 'B')], 2); assert_eq!(caps[&('A', 'D')], 3); assert_eq!(caps[&('B', 'C')], 2); assert_eq!(caps[&('C', 'D')], 1); assert_eq!(caps[&('C', 'E')], 1); assert_eq!(caps[&('D', 'F')], 4); assert_eq!(caps[&('E', 'G')], 1); assert_eq!(caps[&('F', 'G')], 4); assert_eq!(total, 5); cut.sort_unstable(); assert_eq!(cut, vec![(('A', 'D'), 3), (('C', 'D'), 1), (('E', 'G'), 1)]); } fn wikipedia_example>() { check_wikipedia_result(edmonds_karp::<_, _, _, EK>( &"ABCDEFGH".chars().collect::>(), &'A', &'G', successors_wikipedia(), )); } #[test] fn wikipedia_example_dense() { wikipedia_example::>(); } #[test] fn wikipedia_example_sparse() { wikipedia_example::>(); } #[allow(clippy::cast_possible_truncation)] fn wikipedia_progressive_example>() { let successors = successors_wikipedia(); let size = successors.len(); let mut ek = EK::new(size, 0, 6); for ((from, to), cap) in successors { let (_, total, _) = ek.augment(); assert!(total < 5); ek.set_capacity(from as usize - 65, to as usize - 65, cap); } let (caps, total, flows) = ek.augment(); let mkletter = |d| char::from_u32(d as u32 + 65).unwrap(); let mkedge = |((a, b), c)| ((mkletter(a), mkletter(b)), c); let caps = caps.into_iter().map(mkedge).collect::>(); let flows = flows.into_iter().map(mkedge).collect(); check_wikipedia_result((caps, total, flows)); } #[test] fn wikipedia_progressive_example_dense() { wikipedia_progressive_example::>(); } #[test] fn wikipedia_progressive_example_sparse() { wikipedia_progressive_example::>(); } fn disconnected>() { let (caps, total, _) = edmonds_karp::<_, _, _, EK>( &['A', 'B'], &'A', &'B', std::iter::empty::<((char, char), isize)>(), ); assert_eq!(caps.len(), 0); assert_eq!(total, 0); } #[test] fn disconnected_dense() { disconnected::>(); } #[test] fn disconnected_sparse() { disconnected::>(); } fn modified>() { // Graph is: // // 0 -(6)-> 1 -(5)-> 2 -(7)-> 3 // | ^ // +--(4)-> 4 -(8)-> 5 -(9)---+ // // Upper branch has capacity 5, lower branch 4. let mut ek = EK::new(6, 0, 3); ek.set_capacity(0, 1, 6); ek.set_capacity(1, 2, 5); ek.set_capacity(2, 3, 7); ek.set_capacity(0, 4, 4); ek.set_capacity(4, 5, 8); ek.set_capacity(5, 3, 9); assert_eq!(ek.augment().1, 9); // Set lower branch capacity to 5. ek.set_capacity(0, 4, 5); assert_eq!(ek.augment().1, 10); // Try setting lower branch individual capacities // to 4 one at a time. for &(from, to) in &[(0, 4), (4, 5), (5, 3)] { ek.set_capacity(from, to, 4); assert_eq!(ek.augment().1, 9); ek.set_capacity(from, to, 5); assert_eq!(ek.augment().1, 10); } // Set capacity 0->4 to 4. ek.set_capacity(0, 4, 4); assert_eq!(ek.augment().1, 9); // Add a branch 1->4 of 2. ek.set_capacity(1, 4, 2); assert_eq!(ek.augment().1, 10); } #[test] fn modified_dense() { modified::>(); } #[test] fn modified_sparse() { modified::>(); } #[test] #[should_panic(expected = "source is greater or equal than size")] fn empty() { let mut ek = DenseCapacity::::new(0, 0, 0); ek.augment(); } #[test] #[should_panic(expected = "source not found in vertices")] fn unknown_source() { edmonds_karp_dense(&[1, 2, 3], &0, &3, Vec::<((i32, i32), i32)>::new()); } #[test] #[should_panic(expected = "source not found in vertices")] fn unknown_source_2() { edmonds_karp_sparse(&[1, 2, 3], &0, &3, Vec::<((i32, i32), i32)>::new()); } #[test] #[should_panic(expected = "sink not found in vertices")] fn unknown_sink() { edmonds_karp_dense(&[1, 2, 3], &1, &4, Vec::<((i32, i32), i32)>::new()); } #[test] #[should_panic(expected = "sink not found in vertices")] fn unknown_sink_2() { edmonds_karp_sparse(&[1, 2, 3], &1, &4, Vec::<((i32, i32), i32)>::new()); } fn str_to_graph(desc: &str) -> (Vec, Vec>) { let vertices = (0..desc.lines().count() - 1).collect(); let edges = desc .lines() .skip(1) .enumerate() .flat_map(|(from, line)| { line.split_whitespace() .skip(1) .enumerate() .filter_map(|(to, cap)| Some(((from, to), cap.parse().ok()?))) .collect::>() }) .collect(); (vertices, edges) } #[test] fn mincut_basic() { let (vertices, edges) = str_to_graph( " 0 1 2 3 4 5 0 . 5 . 6 . . 1 . . 4 . 7 . 2 . . . 6 . 1 3 4 . 4 . . . 4 . . . . . 6 5 5 . . 5 . .", ); let (_, cap, mut mincut) = edmonds_karp_dense(&vertices, &vertices[0], vertices.last().unwrap(), edges); mincut.sort_unstable(); assert_eq!((mincut, cap), (vec![((0, 1), 5), ((2, 5), 1)], 6)); } #[test] fn mincut_wikipedia() { let (vertices, edges) = str_to_graph( " 0 1 2 3 4 5 6 7 0 . 10 . 5 . 15 . . 1 . . 9 4 15 . . . 2 . . . . 15 . . 10 3 . 2 . . 8 4 . . 4 . . . . . . 15 10 5 . . . . . . 16 . 6 . . . 6 . . . 10 7 . . . . . . . . ", ); let (_, cap, mut mincut) = edmonds_karp_dense(&vertices, &vertices[0], vertices.last().unwrap(), edges); mincut.sort_unstable(); assert_eq!( (mincut, cap), (vec![((1, 2), 9), ((4, 7), 10), ((6, 7), 10)], 29) ); } #[test] fn set_capacity_test() { let n_nodes = 6; let source = 0; let target = 5; let mut ek = DenseCapacity::new(n_nodes, source, target); { ek.set_capacity(0, 1, 2); ek.set_capacity(0, 2, 2); ek.set_capacity(1, 3, 1); ek.set_capacity(1, 4, 1); ek.set_capacity(2, 3, 1); ek.set_capacity(2, 4, 1); ek.set_capacity(3, 5, 4); ek.set_capacity(4, 3, 2); } let (_flows, max_flow_value, _) = ek.augment(); assert_eq!(max_flow_value, 4); // reduce capacity from 4 to 2 let residual_capacities_non_negative = |ek: &DenseCapacity| { for v1 in 0..n_nodes { for v2 in 0..n_nodes { let c = ek.residual_capacity(v1, v2); assert!(c >= 0, "residual_capacity({v1}, {v2}) == {c} < 0"); } } }; ek.set_capacity(3, 5, 2); residual_capacities_non_negative(&ek); ek.augment(); residual_capacities_non_negative(&ek); } pathfinding-4.14.0/tests/gps.rs000064400000000000000000000074531046102023000145170ustar 00000000000000#![cfg(test)] use pathfinding::prelude::*; use std::collections::HashMap; // Latitude, longitude struct Coords(f32, f32); impl Coords { fn lat_rad(&self) -> f32 { self.0.to_radians() } fn lon_rad(&self) -> f32 { self.1.to_radians() } #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] fn distance_in_meters(&self, other: &Self) -> u64 { let x = (other.lon_rad() - self.lon_rad()) * ((other.lat_rad() + self.lat_rad()) / 2.0).cos(); let y = other.lat_rad() - self.lat_rad(); (x.hypot(y) * 6_371_000.0).round() as u64 } } fn coords() -> HashMap<&'static str, Coords> { vec![ ("Paris", Coords(48.8567, 2.3508)), ("Lyon", Coords(45.76, 4.84)), ("Marseille", Coords(43.2964, 5.37)), ("Bordeaux", Coords(44.84, -0.58)), ("Cannes", Coords(43.5513, 7.0128)), ("Toulouse", Coords(43.6045, 1.444)), ("Reims", Coords(49.2628, 4.0347)), ] .into_iter() .collect() } fn successor_distances( coords: &HashMap<&str, Coords>, ) -> HashMap<&'static str, Vec<(&'static str, u64)>> { let mut successors = HashMap::new(); { let mut insert_successor = |from: &'static str, to: &'static str| { let from_coords = &coords[from]; let ns = to .split(',') .map(|successor| { ( successor, from_coords.distance_in_meters(&coords[successor]), ) }) .collect(); successors.insert(from, ns); }; insert_successor("Paris", "Lyon,Bordeaux,Reims"); insert_successor("Lyon", "Paris,Marseille"); insert_successor("Marseille", "Lyon,Cannes,Toulouse"); insert_successor("Bordeaux", "Toulouse,Paris"); insert_successor("Cannes", "Marseille"); insert_successor("Toulouse", "Marseille,Bordeaux"); insert_successor("Reims", "Paris"); } successors } #[test] fn gps() { let coords = coords(); let successor_distances = successor_distances(&coords); let (start, goal) = ("Paris", "Cannes"); let goal_coords = &coords[goal]; let expected_path = vec!["Paris", "Lyon", "Marseille", "Cannes"]; let r = astar( &start, |city| successor_distances[city].clone(), |city| goal_coords.distance_in_meters(&coords[city]), |city| city == &goal, ); let (path, cost_astar) = r.expect("no path found with astar"); assert_eq!(path, expected_path, "bad path found with astar"); let r = fringe( &start, |city| successor_distances[city].clone(), |city| goal_coords.distance_in_meters(&coords[city]), |city| city == &goal, ); let (path, cost_fringe) = r.expect("no path found with fringe"); assert_eq!(path, expected_path, "bad path found with fringe"); assert_eq!( cost_astar, cost_fringe, "costs for astar and fringe are different" ); let r = dijkstra( &start, |city| successor_distances[city].clone(), |city| city == &goal, ); let (path, cost_dijkstra) = r.expect("no path found with dijkstra"); assert_eq!(path, expected_path, "bad path found with dijkstra"); assert_eq!( cost_astar, cost_dijkstra, "costs for astar and dijkstra are different" ); let r = idastar( &start, |city| successor_distances[city].clone(), |city| goal_coords.distance_in_meters(&coords[city]), |city| city == &goal, ); let (path, cost_idastar) = r.expect("no path found with idastar"); assert_eq!(path, expected_path, "bad path found with idastar"); assert_eq!( cost_astar, cost_idastar, "costs for astar and idastar are different" ); } pathfinding-4.14.0/tests/grid.rs000064400000000000000000000347271046102023000146570ustar 00000000000000use itertools::*; use pathfinding::grid::Grid; use rand::prelude::*; #[test] fn empty_grid() { let mut g = Grid::new(0, 0); assert_eq!(g.iter().next(), None); assert!(g.is_empty()); assert!(g.is_full()); assert!(!g.clear()); assert!(!g.fill()); assert_eq!(g.iter().next(), None); assert!(g.is_empty()); assert!(g.is_full()); g.invert(); assert_eq!(g.iter().next(), None); assert!(g.is_empty()); assert!(g.is_full()); assert_eq!(g.edges().next(), None); } #[test] fn one_point_grid() { let mut g = Grid::new(1, 1); assert_eq!(g.iter().next(), None); g.fill(); assert_eq!(g.iter().collect_vec(), vec![(0, 0)]); assert_eq!(g.neighbours((0, 0)), vec![]); assert_eq!(g.edges().next(), None); } #[test] fn grid_iter_is_fused() { let mut g = Grid::new(1, 1); g.fill(); let mut it = g.iter(); assert!(it.next().is_some()); for _ in 0..3 { assert!(it.next().is_none()); } } #[test] fn grid_into_iter_is_fused() { let mut g = Grid::new(1, 1); g.fill(); let mut it = g.into_iter(); assert!(it.next().is_some()); for _ in 0..3 { assert!(it.next().is_none()); } } #[test] fn grid_edges_iter_is_fused() { let mut g = Grid::new(2, 2); g.fill(); let mut it = g.edges(); for _ in 0..4 { assert!(it.next().is_some()); } for _ in 0..3 { assert!(it.next().is_none()); } } #[test] fn diagonal_mode() { let mut g = Grid::new(3, 3); assert_eq!(g.iter().count(), 0); g.fill(); assert_eq!(g.iter().count(), 9); let mut ns = g.neighbours((1, 1)); ns.sort_unstable(); assert_eq!(ns, vec![(0, 1), (1, 0), (1, 2), (2, 1)]); g.enable_diagonal_mode(); let mut ns = g.neighbours((1, 1)); ns.sort_unstable(); assert_eq!( ns, vec![ (0, 0), (0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1), (2, 2), ] ); g.disable_diagonal_mode(); let mut ns = g.neighbours((1, 1)); ns.sort_unstable(); assert_eq!(ns, vec![(0, 1), (1, 0), (1, 2), (2, 1)]); } #[test] fn resize() { let mut g = Grid::new(3, 3); assert_eq!(g.vertices_len(), 0); assert!(!g.resize(4, 4)); assert_eq!(g.vertices_len(), 0); assert!(!g.resize(3, 3)); assert_eq!(g.vertices_len(), 0); g.fill(); assert_eq!(g.vertices_len(), 9); assert!(!g.resize(4, 4)); assert_eq!(g.vertices_len(), 9); assert!(!g.resize(3, 4)); assert_eq!(g.vertices_len(), 9); assert!(!g.resize(3, 3)); assert_eq!(g.vertices_len(), 9); assert!(g.resize(2, 2)); assert_eq!(g.vertices_len(), 4); assert!(!g.resize(3, 3)); assert_eq!(g.vertices_len(), 4); assert!(!g.resize(10, 10)); assert_eq!(g.vertices_len(), 4); let mut ns = g.neighbours((1, 1)); ns.sort_unstable(); assert_eq!(ns, vec![(0, 1), (1, 0)]); for _ in 0..2 { let ns = g.neighbours((1, 1)); for n in iproduct!(0..g.width, 0..g.height) { let present = ns.contains(&n); assert_eq!(g.has_edge((1, 1), n), present); assert_eq!(g.has_edge(n, (1, 1)), present); } g.enable_diagonal_mode(); } } #[test] fn dimensions() { let mut g = Grid::new(3, 4); assert_eq!(g.width, 3); assert_eq!(g.height, 4); assert_eq!(g.size(), 12); g.resize(2, 7); assert_eq!(g.width, 2); assert_eq!(g.height, 7); assert_eq!(g.size(), 14); } #[test] fn add_remove() { let mut g = Grid::new(3, 3); g.fill(); for _ in 0..2 { assert!(g.has_vertex((1, 1))); assert!(g.remove_vertex((1, 1))); assert!(!g.has_vertex((1, 1))); assert!(!g.remove_vertex((1, 1))); assert!(!g.has_vertex((1, 1))); assert!(g.add_vertex((1, 1))); assert!(g.has_vertex((1, 1))); assert!(!g.add_vertex((1, 1))); assert!(g.has_vertex((1, 1))); g.resize(1000, 1000); } } #[test] fn fill_clear_invert_empty_full() { let mut g = Grid::new(3, 3); assert_eq!(g.iter().count(), 0); assert!(g.is_empty()); assert!(!g.is_full()); assert!(g.fill()); assert!(!g.fill()); assert_eq!(g.iter().count(), 9); assert!(!g.is_empty()); assert!(g.is_full()); assert!(g.clear()); assert!(!g.clear()); assert_eq!(g.iter().count(), 0); assert!(g.is_empty()); assert!(!g.is_full()); g.invert(); assert_eq!(g.iter().count(), 9); assert!(!g.is_empty()); assert!(g.is_full()); g.resize(3, 4); assert!(!g.is_empty()); assert!(!g.is_full()); } #[test] fn iterators() { let mut rng = StdRng::from_entropy(); for _ in 0..100 { let mut g = Grid::new(10, 20); if rng.gen_bool(0.5) { g.fill(); } for _ in 0..1000 { let x = rng.next_u32() as usize % g.width; let y = rng.next_u32() as usize % g.height; if rng.gen_bool(0.5) { g.add_vertex((x, y)); } else { g.remove_vertex((x, y)); } } if rng.gen_bool(0.2) { g.invert(); } let mut ns1 = g.iter().collect_vec(); ns1.sort_unstable(); let mut ns2 = g.into_iter().collect_vec(); ns2.sort_unstable(); assert_eq!(ns1, ns2); } } #[test] fn collect() { let g = vec![(1, 7), (1, 8), (3, 4), (1, 7)] .into_iter() .collect::(); assert_eq!(g.width, 4); assert_eq!(g.height, 9); assert_eq!(g.vertices_len(), 3); } #[test] fn is_inside() { let g = Grid::new(2, 4); for x in 0..2 { for y in 0..4 { assert!(g.is_inside((x, y))); } } for x in 0..2 { assert!(!g.is_inside((x, 4))); } for y in 0..4 { assert!(!g.is_inside((2, y))); } } #[test] fn add_outside_vertex() { let mut g = Grid::new(10, 10); assert!(!g.add_vertex((10, 10))); } #[test] fn remove_outside_vertex() { let mut g = Grid::new(10, 10); assert!(!g.remove_vertex((10, 10))); } #[test] fn outside_vertex() { let mut g = Grid::new(10, 10); assert!(!g.has_vertex((10, 10))); g.fill(); assert!(!g.has_vertex((10, 10))); } #[test] fn neighbours_outside_vertex() { let mut g = Grid::new(10, 10); assert_eq!(g.neighbours((10, 10)), vec![]); g.fill(); assert_eq!(g.neighbours((10, 10)), vec![]); } #[test] fn neighbours_of_border() { let sort = |mut v: Vec<(usize, usize)>| { v.sort_unstable(); v }; let mut g = Grid::new(3, 3); assert_eq!(g.neighbours((2, 2)), vec![]); g.enable_diagonal_mode(); assert_eq!(g.neighbours((2, 2)), vec![]); g.fill(); assert_eq!(sort(g.neighbours((2, 2))), vec![(1, 1), (1, 2), (2, 1)]); g.disable_diagonal_mode(); assert_eq!(sort(g.neighbours((2, 2))), vec![(1, 2), (2, 1)]); let mut g = Grid::new(3, 3); assert_eq!(g.neighbours((2, 1)), vec![]); g.enable_diagonal_mode(); assert_eq!(g.neighbours((2, 1)), vec![]); g.fill(); assert_eq!( sort(g.neighbours((2, 1))), vec![(1, 0), (1, 1), (1, 2), (2, 0), (2, 2)] ); g.disable_diagonal_mode(); assert_eq!(sort(g.neighbours((2, 1))), vec![(1, 1), (2, 0), (2, 2)]); let mut g = Grid::new(3, 3); assert_eq!(g.neighbours((1, 2)), vec![]); g.enable_diagonal_mode(); assert_eq!(g.neighbours((1, 2)), vec![]); g.fill(); assert_eq!( sort(g.neighbours((1, 2))), vec![(0, 1), (0, 2), (1, 1), (2, 1), (2, 2)] ); g.disable_diagonal_mode(); assert_eq!(sort(g.neighbours((1, 2))), vec![(0, 2), (1, 1), (2, 2)]); } #[test] fn totally_empty() { let g = Grid::new(0, 0); assert_eq!(g.vertices_len(), 0); } #[test] fn empty() { let g = Grid::new(0, 4); assert_eq!(g.vertices_len(), 0); } #[test] fn add_borders() { let mut g = Grid::new(3, 4); assert_eq!(g.add_borders(), 10); assert_eq!(g.vertices_len(), 10); for x in 0..3 { assert!(g.has_vertex((x, 0))); assert!(g.has_vertex((x, 3))); } for y in 0..4 { assert!(g.has_vertex((0, y))); assert!(g.has_vertex((2, y))); } assert_eq!(g.add_borders(), 0); } #[test] fn add_borders_empty() { let mut g = Grid::new(4, 0); assert_eq!(g.add_borders(), 0); } #[test] fn add_borders_flat() { let mut g = Grid::new(4, 1); assert_eq!(g.add_borders(), 4); } #[test] fn bfs_reachable() { let mut g = vec![(1, 7), (1, 8), (3, 4), (2, 7), (0, 6)] .into_iter() .collect::(); assert_eq!(g.bfs_reachable((1, 8), |_| true).len(), 3); assert_eq!(g.bfs_reachable((1, 8), |_| false).len(), 1); let mut counter = 1; assert_eq!( g.bfs_reachable((1, 8), |_| { counter += 1; true }) .len(), 3 ); assert_eq!(counter, 5); assert_eq!( g.bfs_reachable((1, 8), |_| true) .into_iter() .collect::>(), vec![(1, 7), (1, 8), (2, 7)] ); assert_eq!(g.bfs_reachable((3, 4), |_| true).len(), 1); assert_eq!(g.bfs_reachable((0, 8), |_| true).len(), 1); g.enable_diagonal_mode(); assert_eq!(g.bfs_reachable((1, 8), |_| true).len(), 4); assert_eq!(g.bfs_reachable((3, 4), |_| true).len(), 1); assert_eq!(g.bfs_reachable((0, 8), |_| true).len(), 1); } #[test] fn dfs_reachable() { let mut g = vec![(1, 7), (1, 8), (3, 4), (2, 7), (0, 6)] .into_iter() .collect::(); assert_eq!(g.dfs_reachable((1, 8), |_| true).len(), 3); assert_eq!(g.bfs_reachable((1, 8), |_| false).len(), 1); let mut counter = 1; assert_eq!( g.dfs_reachable((1, 8), |_| { counter += 1; true }) .len(), 3 ); assert_eq!(counter, 5); assert_eq!( g.dfs_reachable((1, 8), |_| true) .into_iter() .collect::>(), vec![(1, 7), (1, 8), (2, 7)] ); assert_eq!(g.dfs_reachable((3, 4), |_| true).len(), 1); assert_eq!(g.dfs_reachable((0, 8), |_| true).len(), 1); g.enable_diagonal_mode(); assert_eq!(g.dfs_reachable((1, 8), |_| true).len(), 4); assert_eq!(g.dfs_reachable((3, 4), |_| true).len(), 1); assert_eq!(g.dfs_reachable((0, 8), |_| true).len(), 1); } #[test] fn remove_borders() { let mut g = Grid::new(3, 4); g.fill(); assert_eq!(g.remove_borders(), 10); assert_eq!(g.vertices_len(), 2); for x in 0..3 { assert!(!g.has_vertex((x, 0))); assert!(!g.has_vertex((x, 3))); } for y in 0..4 { assert!(!g.has_vertex((0, y))); assert!(!g.has_vertex((2, y))); } assert_eq!(g.remove_borders(), 0); } #[test] fn remove_borders_empty() { let mut g = Grid::new(0, 0); assert_eq!(g.vertices_len(), 0); g.fill(); assert_eq!(g.vertices_len(), 0); assert_eq!(g.remove_borders(), 0); assert_eq!(g.vertices_len(), 0); let mut g = Grid::new(1, 0); assert_eq!(g.vertices_len(), 0); g.fill(); assert_eq!(g.vertices_len(), 0); assert_eq!(g.remove_borders(), 0); assert_eq!(g.vertices_len(), 0); let mut g = Grid::new(0, 1); assert_eq!(g.vertices_len(), 0); g.fill(); assert_eq!(g.vertices_len(), 0); assert_eq!(g.remove_borders(), 0); assert_eq!(g.vertices_len(), 0); } #[test] fn remove_borders_flat() { let mut g = Grid::new(4, 1); assert_eq!(g.remove_borders(), 0); g.fill(); assert_eq!(g.remove_borders(), 4); } #[test] fn edges() { let mut g = Grid::new(2, 2); g.fill(); let mut edges = g.edges().collect::>(); edges.sort_unstable(); assert_eq!( edges, vec![ ((0, 0), (0, 1)), ((0, 0), (1, 0)), ((0, 1), (1, 1)), ((1, 0), (1, 1)) ] ); g.enable_diagonal_mode(); let mut edges = g.edges().collect::>(); edges.sort_unstable(); assert_eq!( edges, vec![ ((0, 0), (0, 1)), ((0, 0), (1, 0)), ((0, 0), (1, 1)), ((0, 1), (1, 1)), ((1, 0), (0, 1)), ((1, 0), (1, 1)) ] ); let mut g = Grid::new(3, 3); g.fill(); g.remove_vertex((1, 1)); let mut edges = g.edges().collect::>(); edges.sort_unstable(); assert_eq!( edges, vec![ ((0, 0), (0, 1)), ((0, 0), (1, 0)), ((0, 1), (0, 2)), ((0, 2), (1, 2)), ((1, 0), (2, 0)), ((1, 2), (2, 2)), ((2, 0), (2, 1)), ((2, 1), (2, 2)) ] ); } #[test] fn distance() { let mut g = Grid::new(10, 10); assert_eq!(g.distance((2, 3), (7, 5)), 7); assert_eq!(g.distance((7, 5), (2, 3)), 7); assert_eq!(g.distance((3, 2), (5, 7)), 7); assert_eq!(g.distance((5, 7), (3, 2)), 7); g.enable_diagonal_mode(); assert_eq!(g.distance((2, 3), (7, 5)), 5); assert_eq!(g.distance((7, 5), (2, 3)), 5); assert_eq!(g.distance((3, 2), (5, 7)), 5); assert_eq!(g.distance((5, 7), (3, 2)), 5); } #[test] fn debug() { let g = [ (0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (0, 1), (4, 1), (0, 2), (4, 2), (0, 3), (4, 3), (0, 4), (1, 4), (2, 4), (3, 4), (4, 4), ] .into_iter() .collect::(); assert_eq!( format!("{g:?}"), String::from( "\ ##### #...# #...# #...# #####" ) ); assert_eq!( format!("{g:#?}"), String::from( "\ ▓▓▓▓▓ ▓░░░▓ ▓░░░▓ ▓░░░▓ ▓▓▓▓▓" ) ); } #[test] fn from_matrix() { let m = pathfinding::prelude::Matrix::square_from_vec(vec![ true, true, true, false, false, false, true, false, true, ]) .unwrap(); let g = Grid::from(&m); let g2 = Grid::from(m); assert_eq!(g, g2); let mut vertices = g.into_iter().collect::>(); vertices.sort_unstable(); assert_eq!(vertices, vec![(0, 0), (0, 2), (1, 0), (2, 0), (2, 2)]); } #[test] fn equality() { let g = [ (0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (0, 1), (4, 1), (0, 2), (4, 2), (0, 3), (4, 3), (0, 4), (1, 4), (2, 4), (3, 4), (4, 4), ] .into_iter() .collect::(); assert_eq!(g, g); let mut g2 = g.clone(); assert_eq!(g, g2); g2.remove_vertex((0, 0)); assert_ne!(g, g2); g2.add_vertex((0, 0)); assert_eq!(g, g2); } pathfinding-4.14.0/tests/kruskal.rs000064400000000000000000000020161046102023000153700ustar 00000000000000use itertools::Itertools; use pathfinding::prelude::*; #[test] fn grid_lines() { let mut g = Grid::new(2, 2); g.fill(); let weighted_edges = g .edges() .map(|((x1, y1), (x2, y2))| ((x1, y1), (x2, y2), y1.min(y2))) .collect::>(); assert_eq!(weighted_edges.len(), 4); let mst = kruskal(&weighted_edges).sorted().collect_vec(); assert_eq!( mst, vec![ (&(0, 0), &(0, 1), 0), (&(0, 0), &(1, 0), 0), (&(1, 0), &(1, 1), 0) ] ); } #[test] fn wikipedia() { // Example from https://en.wikipedia.org/wiki/Kruskal's_algorithm let edges = vec![ ('a', 'b', 3), ('a', 'e', 1), ('b', 'c', 5), ('b', 'e', 4), ('c', 'd', 2), ('c', 'e', 6), ('d', 'e', 7), ]; assert_eq!( kruskal(&edges).collect::>(), vec![ (&'a', &'e', 1), (&'c', &'d', 2), (&'a', &'b', 3), (&'b', &'c', 5) ] ); } pathfinding-4.14.0/tests/kuhn_munkres.rs000064400000000000000000000054251046102023000164340ustar 00000000000000use pathfinding::kuhn_munkres::*; use pathfinding::{matrix, matrix::Matrix}; #[test] fn tryalgo_examples() { // Some tests from https://github.com/jilljenn/tryalgo/blob/master/tests/test_tryalgo.py assert_eq!(kuhn_munkres(&matrix![[1]]), (1, vec![0])); assert_eq!(kuhn_munkres(&matrix![[1, 1], [1, 1]]).0, 2); assert_eq!(kuhn_munkres(&matrix![[1, 2], [1, 1]]), (3, vec![1, 0])); assert_eq!(kuhn_munkres(&matrix![[1, 1], [2, 1]]), (3, vec![1, 0])); assert_eq!(kuhn_munkres(&matrix![[2, 1], [1, 1]]), (3, vec![0, 1])); assert_eq!(kuhn_munkres(&matrix![[1, 1], [1, 2]]), (3, vec![0, 1])); assert_eq!( kuhn_munkres(&matrix![[-1, -2, -3], [-6, -5, -4], [-1, -1, -1]]), (-6, vec![0, 2, 1]) ); assert_eq!( kuhn_munkres(&matrix![[1, 2, 3], [6, 5, 4], [1, 1, 1]]), (10, vec![2, 0, 1]) ); assert_eq!( kuhn_munkres(&matrix![ [7, 53, 183, 439, 863], [497, 383, 563, 79, 973], [287, 63, 343, 169, 583], [627, 343, 773, 959, 943], [767, 473, 103, 699, 303], ]) .0, 3315 ); } #[test] fn cranes() { // Test from https://s-mat-pcs.oulu.fi/~mpa/matreng/eem1_2-1.htm. let distances = matrix![ [90, 75, 75, 80], [35, 85, 55, 65], [125, 95, 90, 105], [45, 110, 95, 115], ]; assert_eq!(kuhn_munkres_min(&distances).0, 275); } #[test] fn murray() { // Test from http://csclab.murraystate.edu/~bob.pilgrim/445/munkres.html let weights = matrix![[1, 2, 3], [2, 4, 6], [3, 6, 9],]; assert_eq!(kuhn_munkres_min(&weights).0, 10); } #[test] fn mattkrick() { // Test from https://github.com/mattkrick/hungarian-on3 let data = matrix![[400, 150, 400], [400, 450, 600], [300, 225, 300]]; assert_eq!(kuhn_munkres_min(&data).0, 850); } #[test] fn hungarian() { // Test from http://www.hungarianalgorithm.com/examplehungarianalgorithm.php let weights = matrix![ [82, 83, 69, 92], [77, 37, 49, 92], [11, 69, 5, 86], [8, 9, 98, 23], ]; assert_eq!(kuhn_munkres_min(&weights).0, 140); } #[test] fn non_square() { // Test from https://www.youtube.com/watch?v=aPVtIhnwHPE let data = matrix![ [62, 78, 50, 101, 82], [71, 84, 61, 73, 59], [87, 92, 111, 71, 81], [48, 64, 87, 77, 80] ]; let (total, assignments) = kuhn_munkres(&data); assert_eq!(total, 376); assert_eq!(assignments, vec![3, 1, 2, 4]); } #[test] fn empty() { let (total, assignments) = kuhn_munkres(&Matrix::::new_empty(0)); assert_eq!(total, 0); assert_eq!(assignments, vec![]); } #[test] #[should_panic(expected = "number of rows must not be larger than number of columns")] fn unbalanced() { kuhn_munkres(&Matrix::new(3, 2, 0)); } pathfinding-4.14.0/tests/matrix.rs000064400000000000000000000546121046102023000152310ustar 00000000000000#![cfg(test)] use pathfinding::{ matrix, matrix::{Matrix, MatrixFormatError}, }; #[test] fn sm() { let mut m = Matrix::new(2, 2, 0usize); m[(0, 0)] = 0; m[(0, 1)] = 1; m[(1, 0)] = 10; m[(1, 1)] = 11; m[(0, 1)] = 2; assert_eq!(m[(0, 0)], 0); assert_eq!(m[(0, 1)], 2); assert_eq!(m[(1, 0)], 10); assert_eq!(m[(1, 1)], 11); m.fill(33); assert_eq!(m[(0, 0)], 33); assert_eq!(m[(0, 1)], 33); assert_eq!(m[(1, 0)], 33); assert_eq!(m[(1, 1)], 33); } #[test] fn index_as_ref() { let mut m = Matrix::new(2, 2, 0usize); m[&(0, 0)] = 0; m[&(0, 1)] = 1; m[&(1, 0)] = 10; m[&(1, 1)] = 11; m[&(0, 1)] = 2; assert_eq!(m[&(0, 0)], 0); assert_eq!(m[&(0, 1)], 2); assert_eq!(m[&(1, 0)], 10); assert_eq!(m[&(1, 1)], 11); m.fill(33); assert_eq!(m[&(0, 0)], 33); assert_eq!(m[&(0, 1)], 33); assert_eq!(m[&(1, 0)], 33); assert_eq!(m[&(1, 1)], 33); } #[test] fn from_fn() { let m = Matrix::from_fn(2, 3, |(row, column)| 10 * row + column); assert_eq!(m.rows, 2); assert_eq!(m.columns, 3); assert!(!m.is_square()); assert_eq!(m[(0, 0)], 0); assert_eq!(m[(0, 1)], 1); assert_eq!(m[(0, 2)], 2); assert_eq!(m[(1, 0)], 10); assert_eq!(m[(1, 1)], 11); assert_eq!(m[(1, 2)], 12); } #[test] fn from_vec() { let m = Matrix::from_vec(2, 3, vec![10, 20, 30, 40, 50, 60]).unwrap(); assert_eq!(m.rows, 2); assert_eq!(m.columns, 3); assert!(!m.is_square()); assert_eq!(m[(0, 0)], 10); assert_eq!(m[(0, 1)], 20); assert_eq!(m[(0, 2)], 30); assert_eq!(m[(1, 0)], 40); assert_eq!(m[(1, 1)], 50); assert_eq!(m[(1, 2)], 60); } #[test] fn from_vec_error() { assert!(matches!( Matrix::from_vec(2, 3, vec![20, 30, 40, 50, 60]), Err(MatrixFormatError::WrongLength), )); } #[test] fn from_vec_empty_row_error() { assert!(matches!( Matrix::from_vec(2, 0, Vec::::new()), Err(MatrixFormatError::EmptyRow), )); } #[test] #[should_panic(expected = "unable to create a matrix with empty rows")] fn new_empty_row_panic() { _ = Matrix::new(1, 0, 42); } #[test] fn to_vec() { let mut m = Matrix::new(2, 2, 0usize); m[(0, 0)] = 0; m[(0, 1)] = 1; m[(1, 0)] = 10; m[(1, 1)] = 11; assert_eq!(m.to_vec(), vec![0, 1, 10, 11]); } #[test] fn square_from_vec() { let m = Matrix::square_from_vec(vec![10, 20, 30, 40]).unwrap(); assert_eq!(m.rows, 2); assert_eq!(m.columns, 2); assert!(m.is_square()); assert_eq!(m[(0, 0)], 10); assert_eq!(m[(0, 1)], 20); assert_eq!(m[(1, 0)], 30); assert_eq!(m[(1, 1)], 40); } #[test] fn from_vec_panic() { assert!(matches!( Matrix::from_vec(2, 3, vec![1, 2, 3]), Err(MatrixFormatError::WrongLength), )); } #[test] fn square_from_vec_panic() { assert!(matches!( Matrix::square_from_vec(vec![1, 2, 3]), Err(MatrixFormatError::WrongLength), )); } #[test] fn square_rotate() { // 0 1 => 2 0 => 3 2 => 1 3 // 2 3 3 1 1 0 0 2 let m1 = Matrix::square_from_vec(vec![0, 1, 2, 3]).unwrap(); let m2 = Matrix::square_from_vec(vec![2, 0, 3, 1]).unwrap(); let m3 = Matrix::square_from_vec(vec![3, 2, 1, 0]).unwrap(); let m4 = Matrix::square_from_vec(vec![1, 3, 0, 2]).unwrap(); assert_eq!(m1.rotated_cw(0), m1); assert_eq!(m1.rotated_cw(1), m2); assert_eq!(m1.rotated_cw(2), m3); assert_eq!(m1.rotated_cw(3), m4); assert_eq!(m1.rotated_ccw(0), m1); assert_eq!(m1.rotated_ccw(1), m4); assert_eq!(m1.rotated_ccw(2), m3); assert_eq!(m1.rotated_ccw(3), m2); let mut m = m1.clone(); m.rotate_cw(0); assert_eq!(m, m1); let mut m = m1.clone(); m.rotate_cw(1); assert_eq!(m, m2); let mut m = m1.clone(); m.rotate_cw(2); assert_eq!(m, m3); let mut m = m1.clone(); m.rotate_cw(3); assert_eq!(m, m4); let mut m = m1.clone(); m.rotate_ccw(0); assert_eq!(m, m1); let mut m = m1.clone(); m.rotate_ccw(1); assert_eq!(m, m4); let mut m = m1.clone(); m.rotate_ccw(2); assert_eq!(m, m3); let mut m = m1.clone(); m.rotate_ccw(3); assert_eq!(m, m2); // 0 1 2 6 3 0 8 7 6 2 5 8 // 3 4 5 => 7 4 1 => 5 4 3 => 1 4 7 // 6 7 8 8 5 2 2 1 0 0 3 6 let m1 = Matrix::square_from_vec(vec![0, 1, 2, 3, 4, 5, 6, 7, 8]).unwrap(); let m2 = Matrix::square_from_vec(vec![6, 3, 0, 7, 4, 1, 8, 5, 2]).unwrap(); let m3 = Matrix::square_from_vec(vec![8, 7, 6, 5, 4, 3, 2, 1, 0]).unwrap(); let m4 = Matrix::square_from_vec(vec![2, 5, 8, 1, 4, 7, 0, 3, 6]).unwrap(); assert_eq!(m1.rotated_cw(0), m1); assert_eq!(m1.rotated_cw(1), m2); assert_eq!(m1.rotated_cw(2), m3); assert_eq!(m1.rotated_cw(3), m4); assert_eq!(m1.rotated_ccw(0), m1); assert_eq!(m1.rotated_ccw(1), m4); assert_eq!(m1.rotated_ccw(2), m3); assert_eq!(m1.rotated_ccw(3), m2); // Same with 4 let m1 = Matrix::square_from_vec(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]) .unwrap(); let m2 = Matrix::square_from_vec(vec![12, 8, 4, 0, 13, 9, 5, 1, 14, 10, 6, 2, 15, 11, 7, 3]) .unwrap(); let m3 = Matrix::square_from_vec(vec![15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) .unwrap(); let m4 = Matrix::square_from_vec(vec![3, 7, 11, 15, 2, 6, 10, 14, 1, 5, 9, 13, 0, 4, 8, 12]) .unwrap(); assert_eq!(m1.rotated_cw(0), m1); assert_eq!(m1.rotated_cw(1), m2); assert_eq!(m1.rotated_cw(2), m3); assert_eq!(m1.rotated_cw(3), m4); assert_eq!(m1.rotated_ccw(0), m1); assert_eq!(m1.rotated_ccw(1), m4); assert_eq!(m1.rotated_ccw(2), m3); assert_eq!(m1.rotated_ccw(3), m2); // Same with 5 let m1 = Matrix::square_from_vec(vec![ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, ]) .unwrap(); let m2 = Matrix::square_from_vec(vec![ 20, 15, 10, 5, 0, 21, 16, 11, 6, 1, 22, 17, 12, 7, 2, 23, 18, 13, 8, 3, 24, 19, 14, 9, 4, ]) .unwrap(); assert_eq!(m1.rotated_cw(0), m1); assert_eq!(m1.rotated_cw(1), m2); assert_eq!(m2.rotated_cw(3), m1); } #[test] fn non_square_rotate() { let m0 = matrix![[10, 20, 30], [40, 50, 60]]; let m1 = matrix![[40, 10], [50, 20], [60, 30]]; let m2 = matrix![[60, 50, 40], [30, 20, 10]]; let m3 = matrix![[30, 60], [20, 50], [10, 40]]; assert_eq!(m0.rotated_cw(0), m0); assert_eq!(m0.rotated_cw(1), m1); assert_eq!(m0.rotated_cw(2), m2); assert_eq!(m0.rotated_cw(3), m3); assert_eq!(m0.rotated_cw(4), m0); assert_eq!(m0.rotated_ccw(0), m0); assert_eq!(m0.rotated_ccw(1), m3); assert_eq!(m0.rotated_ccw(2), m2); assert_eq!(m0.rotated_ccw(3), m1); assert_eq!(m0.rotated_ccw(4), m0); } #[test] #[should_panic(expected = "this operation would create a matrix with empty rows")] fn no_rows_rotated_cw_panic() { _ = Matrix::::new_empty(10).rotated_cw(1); } #[test] #[should_panic(expected = "this operation would create a matrix with empty rows")] fn no_rows_rotated_ccw_panic() { _ = Matrix::::new_empty(10).rotated_ccw(1); } #[test] fn no_rows_rotated_twice() { _ = Matrix::::new_empty(10).rotated_cw(2); _ = Matrix::::new_empty(10).rotated_ccw(2); } #[test] fn flip_square() { let m1 = Matrix::square_from_vec(vec![0, 1, 2, 3]).unwrap(); let m2 = Matrix::square_from_vec(vec![1, 0, 3, 2]).unwrap(); let m3 = Matrix::square_from_vec(vec![2, 3, 0, 1]).unwrap(); assert_eq!(m1.flipped_lr(), m2); assert_eq!(m1.flipped_ud(), m3); let m1 = Matrix::square_from_vec(vec![0, 1, 2, 3, 4, 5, 6, 7, 8]).unwrap(); let m2 = Matrix::square_from_vec(vec![2, 1, 0, 5, 4, 3, 8, 7, 6]).unwrap(); let m3 = Matrix::square_from_vec(vec![6, 7, 8, 3, 4, 5, 0, 1, 2]).unwrap(); assert_eq!(m1.flipped_lr(), m2); assert_eq!(m1.flipped_ud(), m3); } #[test] fn flip_non_square() { let m1 = Matrix::from_vec( 4, 5, vec![ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, ], ) .unwrap(); let m2 = Matrix::from_vec( 4, 5, vec![ 15, 16, 17, 18, 19, 10, 11, 12, 13, 14, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, ], ) .unwrap(); let m3 = Matrix::from_vec( 4, 5, vec![ 4, 3, 2, 1, 0, 9, 8, 7, 6, 5, 14, 13, 12, 11, 10, 19, 18, 17, 16, 15, ], ) .unwrap(); assert_eq!(m1.flipped_ud(), m2); assert_eq!(m1.flipped_lr(), m3); } #[test] fn transpose() { let m1 = Matrix::from_vec(2, 3, vec![0, 1, 2, 3, 4, 5]).unwrap(); let m2 = Matrix::from_vec(3, 2, vec![0, 3, 1, 4, 2, 5]).unwrap(); assert_eq!(m1.transposed(), m2); assert_eq!(m2.transposed(), m1); } #[test] #[should_panic(expected = "this operation would create a matrix with empty rows")] fn no_rows_transposed_panic() { _ = Matrix::::new_empty(10).transposed(); } #[test] fn transpose_in_place_square() { let mut m = matrix![[0, 1, 2], [3, 4, 5], [6, 7, 8]]; m.transpose(); assert_eq!(m, matrix![[0, 3, 6], [1, 4, 7], [2, 5, 8]]); } #[test] fn transpose_in_place_non_square() { let mut m = matrix![[0, 1, 2]]; m.transpose(); assert_eq!(m, matrix![[0], [1], [2]]); let mut m = matrix![[0, 1, 2], [3, 4, 5]]; m.transpose(); assert_eq!(m, matrix![[0, 3], [1, 4], [2, 5]]); let mut m = matrix![[0, 1], [2, 3], [4, 5], [6, 7], [8, 9]]; m.transpose(); assert_eq!(m, matrix![[0, 2, 4, 6, 8], [1, 3, 5, 7, 9]]); } #[test] fn transpose_in_place_empty() { let mut m: Matrix = matrix![]; m.transpose(); assert_eq!(m, matrix![]); } fn sum(slice: &[usize]) -> usize { slice.iter().sum::() } #[test] fn as_ref() { let m1 = Matrix::from_vec(2, 3, vec![0, 1, 2, 3, 4, 5]).unwrap(); assert_eq!(sum(m1.as_ref()), 15); } #[test] fn as_mut() { let mut m1 = Matrix::from_vec(2, 3, vec![0, 1, 2, 3, 4, 5]).unwrap(); assert_eq!(sum(m1.as_ref()), 15); m1.as_mut()[2] = 10; assert_eq!(sum(m1.as_ref()), 23); } #[test] fn slice() { let m1 = Matrix::square_from_vec(vec![ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, ]) .unwrap(); let m2 = m1.slice(1..3, 2..5).unwrap(); assert_eq!(m2.rows, 2); assert_eq!(m2.columns, 3); assert_eq!(m2.to_vec(), [7, 8, 9, 12, 13, 14]); } #[test] fn slice_err() { let m1 = Matrix::square_from_vec(vec![ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, ]) .unwrap(); assert!(matches!( m1.slice(1..3, 2..6), Err(MatrixFormatError::WrongIndex), )); assert!(matches!( m1.slice(2..6, 1..3), Err(MatrixFormatError::WrongIndex), )); } #[test] fn set_slice() { let mut m1 = Matrix::square_from_vec(vec![ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, ]) .unwrap(); let m2 = Matrix::from_vec(3, 2, vec![10, 20, 30, 40, 50, 60]).unwrap(); m1.set_slice((2, 3), &m2); assert_eq!( m1.to_vec(), [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 10, 20, 15, 16, 17, 30, 40, 20, 21, 22, 50, 60, ] ); let mut m1 = Matrix::square_from_vec(vec![ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, ]) .unwrap(); let m2 = Matrix::from_vec(4, 3, vec![10, 20, 22, 30, 40, 44, 50, 60, 66, 70, 80, 88]).unwrap(); m1.set_slice((2, 3), &m2); assert_eq!( m1.to_vec(), [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 10, 20, 15, 16, 17, 30, 40, 20, 21, 22, 50, 60, ] ); } #[test] fn empty_extend() { let mut m = Matrix::new_empty(3); m.extend(&[0, 1, 2]).unwrap(); m.extend(&[3, 4, 5]).unwrap(); assert_eq!(m.columns, 3); assert_eq!(m.rows, 2); let mut i = 0; for row in 0..m.rows { for column in 0..m.columns { assert_eq!(m[(row, column)], i); i += 1; } } } #[test] fn extend_bad_size_error() { let mut m = Matrix::new_empty(3); assert!(matches!( m.extend(&[0, 1]), Err(MatrixFormatError::WrongLength), )); } #[test] fn extend_empty_row_error() { let mut m: Matrix = matrix![]; assert!(matches!(m.extend(&[]), Err(MatrixFormatError::EmptyRow))); } #[test] fn matrix_macro() { let m = matrix![[0, 1, 2], [3, 4, 5]]; assert_eq!(m.columns, 3); assert_eq!(m.rows, 2); let mut i = 0; for row in 0..m.rows { for column in 0..m.columns { assert_eq!(m[(row, column)], i); i += 1; } } let other_m = matrix![0, 1, 2; 3, 4, 5]; assert_eq!(m, other_m); } #[test] #[should_panic(expected = "all rows must have the same width")] fn matrix_macro_inconsistent_panic() { matrix![[0, 1, 2], [3, 4]]; } #[test] #[should_panic(expected = "all rows must have the same width")] fn matrix_macro_inconsistent_panic_2() { matrix![0, 1, 2; 3, 4]; } #[test] fn macro_trailing_comma() { // A trailing comma must be accepted let m1 = matrix!([1, 2, 3], [4, 5, 6]); let m2 = matrix!([1, 2, 3], [4, 5, 6],); assert_eq!(m1, m2); let m3 = matrix!(1, 2, 3; 4, 5, 6,); assert_eq!(m1, m3); let m4 = matrix!(1, 2, 3; 4, 5, 6;); assert_eq!(m1, m4); let m5 = matrix!(1, 2, 3; 4, 5, 6,;); assert_eq!(m1, m5); } #[test] fn neighbours() { let m = matrix![[0, 1, 2], [3, 4, 5], [6, 7, 8]]; for r in 0..3 { for c in 0..3 { for &diagonal in &[false, true] { let mut neighbours = m.neighbours((r, c), diagonal).collect::>(); neighbours.sort_unstable(); let mut manual = Vec::new(); for rr in 0..3 { for cc in 0..3 { let dr = r.abs_diff(rr); let dc = c.abs_diff(cc); if dr + dc == 1 || (diagonal && dr == 1 && dc == 1) { manual.push((rr, cc)); } } } assert_eq!(neighbours, manual); } } } } #[test] fn empty_neighbours() { let m: Matrix = matrix![]; assert_eq!(m.neighbours((0, 0), false).collect::>(), vec![]); assert_eq!(m.neighbours((0, 0), true).collect::>(), vec![]); let m = Matrix::new(10, 10, 42); assert_eq!(m.neighbours((10, 10), false).collect::>(), vec![]); assert_eq!(m.neighbours((10, 10), true).collect::>(), vec![]); assert_eq!(m.neighbours((5, 10), false).collect::>(), vec![]); assert_eq!(m.neighbours((5, 10), true).collect::>(), vec![]); assert_eq!(m.neighbours((10, 5), false).collect::>(), vec![]); assert_eq!(m.neighbours((10, 5), true).collect::>(), vec![]); } #[test] fn bfs_reachable() { let m = matrix![[0, 1, 2], [3, 4, 5], [6, 7, 8]]; let indices = m.bfs_reachable((1, 0), false, |n| m[n] % 4 != 0); assert_eq!( indices.into_iter().collect::>(), vec![(1, 0), (2, 0), (2, 1)] ); let indices = m.bfs_reachable((1, 0), true, |n| m[n] % 4 != 0); assert_eq!( indices.into_iter().collect::>(), vec![(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)] ); } #[test] fn bfs_reachable_mut() { let m = matrix![[0, 1, 2], [3, 4, 5], [6, 7, 8]]; let mut counter = 0; let indices = m.bfs_reachable((1, 0), false, |n| { counter += 1; m[n] % 4 != 0 }); assert_eq!( indices.into_iter().collect::>(), vec![(1, 0), (2, 0), (2, 1)] ); assert_eq!(counter, 8); let mut counter = 0; let indices = m.bfs_reachable((1, 0), true, |n| { counter += 1; m[n] % 4 != 0 }); assert_eq!( indices.into_iter().collect::>(), vec![(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)] ); assert_eq!(counter, 26); } #[test] fn dfs_reachable() { let m = matrix![[0, 1, 2], [3, 4, 5], [6, 7, 8]]; let indices = m.dfs_reachable((1, 0), false, |n| m[n] % 4 != 0); assert_eq!( indices.into_iter().collect::>(), vec![(1, 0), (2, 0), (2, 1)] ); let indices = m.dfs_reachable((1, 0), true, |n| m[n] % 4 != 0); assert_eq!( indices.into_iter().collect::>(), vec![(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)] ); } #[test] fn dfs_reachable_mut() { let m = matrix![[0, 1, 2], [3, 4, 5], [6, 7, 8]]; let mut counter = 0; let indices = m.dfs_reachable((1, 0), false, |n| { counter += 1; m[n] % 4 != 0 }); assert_eq!( indices.into_iter().collect::>(), vec![(1, 0), (2, 0), (2, 1)] ); assert_eq!(counter, 8); let mut counter = 0; let indices = m.dfs_reachable((1, 0), true, |n| { counter += 1; m[n] % 4 != 0 }); assert_eq!( indices.into_iter().collect::>(), vec![(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)] ); assert_eq!(counter, 26); } #[test] fn bounds_test() { let mut m = matrix![[0, 1, 2], [3, 4, 5]]; assert!(m.within_bounds((1, 2))); assert!(!m.within_bounds((1, 3))); assert!(!m.within_bounds((2, 2))); assert_eq!(m.get((1, 0)), Some(&3)); assert_eq!(m.get((3, 0)), None); assert_eq!(m.get_mut((1, 0)), Some(&mut 3)); assert_eq!(m.get_mut((3, 0)), None); } #[test] fn from_rows() { let m = Matrix::from_rows((1..3).map(|n| (1..5).map(move |x| x * n))).unwrap(); assert_eq!(m.rows, 2); assert_eq!(m.columns, 4); assert_eq!(m.to_vec(), vec![1, 2, 3, 4, 2, 4, 6, 8]); let m = Matrix::from_rows((1..3).map(|n| (1..n).map(move |x| x * n))); assert!(matches!(m, Err(MatrixFormatError::WrongLength))); } #[test] fn from_iter() { let m = (1..3) .map(|n| (1..5).map(move |x| x * n)) .collect::>(); assert_eq!(m.rows, 2); assert_eq!(m.columns, 4); assert_eq!(m.to_vec(), vec![1, 2, 3, 4, 2, 4, 6, 8]); } #[test] #[should_panic(expected = "provided data does not correspond to the expected length")] fn from_iter_error() { _ = (1..3) .map(|n| (1..n).map(move |x| x * n)) .collect::>(); } #[test] fn iter() { let m = matrix![[0, 1, 2], [3, 4, 5], [6, 7, 8]]; let mut i = m.iter(); assert_eq!(i.next().unwrap(), &[0, 1, 2]); assert_eq!(i.next().unwrap(), &[3, 4, 5]); assert_eq!(i.next().unwrap(), &[6, 7, 8]); assert_eq!(i.next(), None); } #[test] fn iter_back() { let m = matrix![[0, 1, 2], [3, 4, 5], [6, 7, 8]]; let mut forward = m.iter().collect::>(); forward.reverse(); assert_eq!(forward, m.iter().rev().collect::>()); } #[test] fn into_iter() { let m = matrix![[0, 1, 2], [2, 1, 0], [1, 0, 2]]; for c in &m { assert_eq!(c.iter().sum::(), 3); } } #[test] fn column_iter() { let m = matrix![[0, 1, 2], [3, 4, 5], [6, 7, 8]]; let mut i = m.column_iter(); assert_eq!(i.next().unwrap(), vec![&0, &3, &6]); assert_eq!(i.next().unwrap(), vec![&1, &4, &7]); assert_eq!(i.next().unwrap(), vec![&2, &5, &8]); assert_eq!(i.next(), None); } #[test] fn column_iter_back() { let m = matrix![[0, 1, 2], [3, 4, 5], [6, 7, 8]]; let mut i = m.column_iter().rev(); assert_eq!(i.next().unwrap(), vec![&2, &5, &8]); assert_eq!(i.next().unwrap(), vec![&1, &4, &7]); assert_eq!(i.next().unwrap(), vec![&0, &3, &6]); assert_eq!(i.next(), None); } #[test] fn into_iter_is_fused() { let m = matrix![[0, 1, 2], [2, 1, 0], [1, 0, 2]]; let mut it = m.iter(); for _ in 0..3 { assert!(it.next().is_some()); } for _ in 0..3 { assert!(it.next().is_none()); } } #[test] #[allow(deprecated)] fn indices() { let m = matrix![[0, 1, 2], [2, 1, 0]]; assert_eq!( m.indices().collect::>(), vec![(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)] ); } #[test] fn keys() { let m = matrix![[0, 1, 2], [2, 1, 0]]; assert_eq!( m.keys().collect::>(), vec![(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)] ); } #[test] fn values() { let m = matrix![[0, 1, 2], [2, 1, 0]]; assert_eq!( m.values().copied().collect::>(), vec![0, 1, 2, 2, 1, 0] ); } #[test] fn values_mut() { let mut m = matrix![[0, 1, 2], [2, 1, 0]]; *m.values_mut().nth(3).unwrap() = 5; let mut iter = m.values_mut(); iter.next(); *iter.next().unwrap() = 4; assert_eq!(m, matrix![[0, 4, 2], [5, 1, 0]]); } #[test] fn in_direction() { let m = Matrix::new_square(8, 0); assert_eq!(m.in_direction((1, 1), (0, 0)).collect::>(), vec![]); assert_eq!(m.in_direction((10, 10), (0, 0)).collect::>(), vec![]); assert_eq!( m.in_direction((10, 10), (-1, -1)).collect::>(), vec![] ); assert_eq!( m.in_direction((4, 4), (-2, 0)).collect::>(), vec![(2, 4), (0, 4)] ); assert_eq!( m.in_direction((4, 4), (-3, 0)).collect::>(), vec![(1, 4)] ); assert_eq!( m.in_direction((4, 4), (2, 0)).collect::>(), vec![(6, 4)] ); assert_eq!( m.in_direction((4, 4), (3, 0)).collect::>(), vec![(7, 4)] ); assert_eq!( m.in_direction((4, 4), (0, -2)).collect::>(), vec![(4, 2), (4, 0)] ); assert_eq!( m.in_direction((4, 4), (0, -3)).collect::>(), vec![(4, 1)] ); assert_eq!( m.in_direction((4, 4), (0, 2)).collect::>(), vec![(4, 6)] ); assert_eq!( m.in_direction((4, 4), (0, 3)).collect::>(), vec![(4, 7)] ); } #[test] fn map() { let m = Matrix::new(3, 3, 10); let m = m.map({ let mut counter = 0; move |x| { counter += 1; x + counter } }); assert_eq!( m, Matrix::square_from_vec(vec![11, 12, 13, 14, 15, 16, 17, 18, 19]).unwrap() ); } #[test] fn items() { let m = matrix![[0, 1, 2], [3, 4, 5], [6, 7, 8]]; assert_eq!(m.items().find(|&(_, val)| val == &3), Some(((1, 0), &3))); } #[test] fn items_mut() { let mut m = matrix![[0, 1, 2], [3, 4, 5], [6, 7, 8]]; for ((r, c), v) in m.items_mut() { if r == 2 && c == 1 { *v *= 2; } } assert_eq!(&*m, &[0, 1, 2, 3, 4, 5, 6, 14, 8]); } #[test] fn is_empty() { let m = matrix![[0, 1, 2], [3, 4, 5], [6, 7, 8]]; assert!(!m.is_empty()); let m: Matrix = matrix![]; assert!(m.is_empty()); } pathfinding-4.14.0/tests/pathfinding.rs000064400000000000000000000315611046102023000162160ustar 00000000000000mod ex1 { use lazy_static::lazy_static; use pathfinding::prelude::*; #[allow(clippy::trivially_copy_pass_by_ref)] fn successors(node: &u8) -> impl Iterator { lazy_static! { static ref SUCCESSORS: Vec> = vec![ vec![(1, 7), (2, 7), (3, 6)], vec![(0, 8), (6, 7)], vec![(5, 7)], vec![(7, 7)], vec![(4, 2)], vec![(1, 1)], vec![(2, 5), (4, 5), (5, 2)], vec![(5, 8)], vec![], ]; } SUCCESSORS[*node as usize].iter().copied() } fn expected(target: u8) -> Option<(Vec, usize)> { match target { 0 => Some((vec![1, 0], 8)), 1 => Some((vec![1], 0)), 2 => Some((vec![1, 6, 2], 12)), 3 => Some((vec![1, 0, 3], 14)), 4 => Some((vec![1, 6, 4], 12)), 5 => Some((vec![1, 6, 5], 9)), 6 => Some((vec![1, 6], 7)), 7 => Some((vec![1, 0, 3, 7], 21)), 8 => None, _ => panic!("no such node"), } } #[test] fn dijkstra_ok() { for target in 0..9 { assert_eq!( dijkstra(&1, successors, |&node| node == target), expected(target) ); } } #[test] fn fringe_ok() { for target in 0..9 { assert_eq!( fringe(&1, successors, |_| 0, |&node| node == target), expected(target) ); } } #[test] fn dfs_ok() { for target in 0..9 { match dfs(1, |n| successors(n).map(|(v, _)| v), |&node| node == target) { None => assert_eq!(expected(target), None, "path not found"), Some(path) => assert!( expected(target).expect("non-existing path found").0.len() <= path.len() ), } } } #[test] fn djkstra_loop_ok() { assert_eq!(dijkstra(&1, |_| vec![(1, 1)], |&n| n == 2), None); } #[test] fn dfs_loop_ok() { assert_eq!(dfs(1, |_| vec![1], |&n| n == 2), None); } #[test] fn bfs_loops() { let successors = |n: &u8| successors(n).map(|(n, _)| n); assert_eq!(bfs_loop(&0, successors), Some(vec![0, 1, 0])); assert_eq!(bfs_loop(&1, successors), Some(vec![1, 0, 1])); assert_eq!(bfs_loop(&2, successors), Some(vec![2, 5, 1, 0, 2])); assert_eq!(bfs_loop(&8, successors), None); } #[test] fn bfs_reach_is_fused() { let mut it = bfs_reach(1, |&n| vec![n * 2, n * 3].into_iter().filter(|&x| x < 15)).skip(1); for _ in 0..7 { assert!(it.next().is_some()); } for _ in 0..3 { assert!(it.next().is_none()); } } #[test] fn bfs_remaining_nodes() { let mut it = bfs_reach(1, |&n| vec![n * 2, n * 3].into_iter().filter(|&x| x < 15)); assert_eq!(1, it.remaining_nodes_low_bound()); // [1] assert_eq!(Some(1), it.next()); assert_eq!(2, it.remaining_nodes_low_bound()); // [2, 3] assert_eq!(Some(2), it.next()); assert_eq!(3, it.remaining_nodes_low_bound()); // [3, 4, 6] assert_eq!(Some(3), it.next()); assert_eq!(3, it.remaining_nodes_low_bound()); // [4, 6, 9] assert_eq!(Some(4), it.next()); assert_eq!(4, it.remaining_nodes_low_bound()); // [6, 9, 8, 12] assert_eq!(Some(6), it.next()); assert_eq!(3, it.remaining_nodes_low_bound()); // [9, 8, 12] assert_eq!(Some(9), it.next()); assert_eq!(2, it.remaining_nodes_low_bound()); // [8, 12] assert_eq!(Some(8), it.next()); assert_eq!(1, it.remaining_nodes_low_bound()); // [12] assert_eq!(Some(12), it.next()); assert_eq!(0, it.remaining_nodes_low_bound()); // [] assert_eq!(None, it.next()); } #[test] fn dfs_reach_is_fused() { let mut it = dfs_reach(1, |&n| vec![n * 2, n * 3].into_iter().filter(|&x| x < 15)).skip(1); for _ in 0..7 { assert!(it.next().is_some()); } for _ in 0..3 { assert!(it.next().is_none()); } } #[test] fn dfs_remaining_nodes() { let mut it = dfs_reach(1, |&n| vec![n * 2, n * 3].into_iter().filter(|&x| x < 15)); assert_eq!(1, it.remaining_nodes_low_bound()); // [1] assert_eq!(Some(1), it.next()); assert_eq!(2, it.remaining_nodes_low_bound()); // [2, 3] assert_eq!(Some(2), it.next()); assert_eq!(3, it.remaining_nodes_low_bound()); // [4, 6, 3] assert_eq!(Some(4), it.next()); assert_eq!(4, it.remaining_nodes_low_bound()); // [8, 12, 6, 3] assert_eq!(Some(8), it.next()); assert_eq!(3, it.remaining_nodes_low_bound()); // [12, 6, 3] assert_eq!(Some(12), it.next()); assert_eq!(2, it.remaining_nodes_low_bound()); // [6, 3] assert_eq!(Some(6), it.next()); assert_eq!(1, it.remaining_nodes_low_bound()); // [3] assert_eq!(Some(3), it.next()); assert_eq!(1, it.remaining_nodes_low_bound()); // [9] assert_eq!(Some(9), it.next()); assert_eq!(0, it.remaining_nodes_low_bound()); // [] assert_eq!(None, it.next()); } } mod ex2 { use lazy_static::lazy_static; use pathfinding::prelude::*; const MAZE: &str = "\ ######### #.#.....# ###.##..# #...#...# #...#...# #...#...# #...#...# ######### "; lazy_static! { static ref OPEN: Vec> = MAZE .lines() .map(|l| l.chars().map(|c| c == '.').collect()) .collect(); } fn successors(&(x, y): &(usize, usize)) -> Vec<((usize, usize), usize)> { vec![(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)] .into_iter() .filter_map(|(nx, ny)| OPEN[ny][nx].then_some(((nx, ny), 1))) .collect() } const fn distance(&(x1, y1): &(usize, usize), &(x2, y2): &(usize, usize)) -> usize { x1.abs_diff(x2) + y1.abs_diff(y2) } #[test] fn astar_path_ok() { const GOAL: (usize, usize) = (6, 3); let mut counter = 0; let (path, cost) = astar( &(2, 3), |n| { counter += 1; successors(n) }, |n| distance(n, &GOAL), |n| n == &GOAL, ) .expect("path not found"); assert_eq!(cost, 8); assert!(path.iter().all(|&(nx, ny)| OPEN[ny][nx])); assert_eq!(counter, 11); } #[test] fn astar_bag_path_single_ok() { const GOAL: (usize, usize) = (6, 3); let mut counter = 0; let (paths, cost) = astar_bag_collect( &(2, 3), |n| { counter += 1; successors(n) }, |n| distance(n, &GOAL), |n| n == &GOAL, ) .unwrap(); assert_eq!(cost, 8); assert_eq!(paths.len(), 1); assert!(paths .iter() .all(|path| path.iter().all(|&(nx, ny)| OPEN[ny][nx]))); assert_eq!(counter, 15); } #[test] fn astar_bag_path_multiple_ok() { const GOAL: (usize, usize) = (7, 3); let mut counter = 0; let (paths, cost) = astar_bag_collect( &(2, 3), |n| { counter += 1; successors(n) }, |n| distance(n, &GOAL), |n| n == &GOAL, ) .unwrap(); assert_eq!(cost, 9); assert_eq!(paths.len(), 3); assert!(paths .iter() .all(|path| path.iter().all(|&(nx, ny)| OPEN[ny][nx]))); assert_eq!(counter, 18); } #[test] fn astar_bag_iter_is_fused() { const GOAL: (usize, usize) = (7, 3); let (mut it, _) = astar_bag(&(2, 3), successors, |n| distance(n, &GOAL), |n| n == &GOAL).unwrap(); for _ in 0..3 { assert!(it.next().is_some()); } for _ in 0..3 { assert!(it.next().is_none()); } } #[test] fn idastar_path_ok() { const GOAL: (usize, usize) = (6, 3); let mut counter = 0; let (path, cost) = idastar( &(2, 3), |n| { counter += 1; successors(n) }, |n| distance(n, &GOAL), |n| n == &GOAL, ) .expect("path not found"); assert_eq!(cost, 8); assert!(path.iter().all(|&(nx, ny)| OPEN[ny][nx])); assert_eq!(counter, 18); } #[test] fn fringe_path_ok() { const GOAL: (usize, usize) = (6, 3); let mut counter = 0; let (path, cost) = fringe( &(2, 3), |n| { counter += 1; successors(n) }, |n| distance(n, &GOAL), |n| n == &GOAL, ) .expect("path not found"); assert_eq!(cost, 8); assert!(path.iter().all(|&(nx, ny)| OPEN[ny][nx])); assert_eq!(counter, 14); } #[test] fn dijkstra_path_ok() { const GOAL: (usize, usize) = (6, 3); let mut counter = 0; let (path, cost) = dijkstra( &(2, 3), |n| { counter += 1; successors(n) }, |n| n == &GOAL, ) .expect("path not found"); assert_eq!(cost, 8); assert!(path.iter().all(|&(nx, ny)| OPEN[ny][nx])); assert_eq!(counter, 20); } #[test] fn bfs_path_ok() { const GOAL: (usize, usize) = (6, 3); let path = bfs( &(2, 3), |n| successors(n).into_iter().map(|(n, _)| n), |n| n == &GOAL, ) .expect("path not found"); assert_eq!(path.len(), 9); assert!(path.iter().all(|&(nx, ny)| OPEN[ny][nx])); } #[test] fn bfs_bidirectional_path_ok() { static SUCCESSORS: fn(&(usize, usize)) -> Vec<(usize, usize)> = |n| successors(n).into_iter().map(|(n, _)| n).collect(); let path = bfs_bidirectional(&(2, 3), &(6, 3), SUCCESSORS, SUCCESSORS).expect("path not found"); assert_eq!(path.len(), 9); assert!(path.iter().all(|&(nx, ny)| OPEN[ny][nx])); } #[test] fn dfs_path_ok() { const GOAL: (usize, usize) = (6, 3); let path = dfs( (2, 3), |n| successors(n).into_iter().map(|(n, _)| n), |n| n == &GOAL, ) .expect("path not found"); assert!(path.len() >= 9); assert!(path.iter().all(|&(nx, ny)| OPEN[ny][nx])); } #[test] fn iddfs_path_ok() { const GOAL: (usize, usize) = (6, 3); let path = iddfs( (2, 3), |n| successors(n).into_iter().map(|(n, _)| n), |n| n == &GOAL, ) .expect("path not found"); assert_eq!(path.len(), 9); assert!(path.iter().all(|&(nx, ny)| OPEN[ny][nx])); } #[test] fn astar_no_path() { const GOAL: (usize, usize) = (1, 1); assert_eq!( astar(&(2, 3), successors, |n| distance(n, &GOAL), |n| n == &GOAL), None ); } #[test] fn idastar_no_path() { const GOAL: (usize, usize) = (1, 1); assert_eq!( idastar(&(2, 3), successors, |n| distance(n, &GOAL), |n| n == &GOAL), None ); } #[test] fn fringe_no_path() { const GOAL: (usize, usize) = (1, 1); assert_eq!( fringe(&(2, 3), successors, |n| distance(n, &GOAL), |n| n == &GOAL), None ); } #[test] fn dijkstra_no_path() { const GOAL: (usize, usize) = (1, 1); assert_eq!(dijkstra(&(2, 3), successors, |n| n == &GOAL), None); } #[test] fn bfs_no_path() { const GOAL: (usize, usize) = (1, 1); assert_eq!( bfs( &(2, 3), |n| successors(n).into_iter().map(|(n, _)| n), |n| n == &GOAL, ), None ); } #[test] fn bfs_bidirectional_no_path() { static SUCCESSORS: fn(&(usize, usize)) -> Vec<(usize, usize)> = |n| successors(n).into_iter().map(|(n, _)| n).collect(); assert_eq!( bfs_bidirectional(&(2, 3), &(1, 1), SUCCESSORS, SUCCESSORS), None ); } #[test] fn dfs_no_path() { const GOAL: (usize, usize) = (1, 1); assert_eq!( dfs( (2, 3), |n| successors(n).into_iter().map(|(n, _)| n), |n| n == &GOAL ), None ); } #[test] fn iddfs_no_path() { const GOAL: (usize, usize) = (1, 1); assert_eq!( iddfs( (2, 3), |n| successors(n).into_iter().map(|(n, _)| n), |n| n == &GOAL, ), None ); } } pathfinding-4.14.0/tests/prim.rs000064400000000000000000000034141046102023000146660ustar 00000000000000use pathfinding::undirected::prim::prim; #[test] // Simple example taken from the test used in kruskal implementation fn base_test() { let edges = vec![ ('a', 'b', 3), ('a', 'e', 1), ('b', 'c', 5), ('b', 'e', 4), ('c', 'd', 2), ('c', 'e', 6), ('d', 'e', 7), ]; assert_eq!( prim(&edges), vec![ (&'a', &'e', 1), (&'a', &'b', 3), (&'b', &'c', 5), (&'c', &'d', 2), ] ); } #[test] // Taken from https://www.geeksforgeeks.org/prims-minimum-spanning-tree-mst-greedy-algo-5/ fn geeksforgeeks() { let edges = vec![ (0, 1, 4), (0, 7, 8), (1, 2, 8), (1, 7, 11), (2, 3, 7), (2, 5, 4), (2, 8, 2), (3, 4, 9), (3, 5, 14), (4, 5, 10), (5, 6, 2), (6, 7, 1), (6, 8, 6), (7, 8, 7), ]; assert_eq!( prim(&edges), vec![ (&0, &1, 4), (&0, &7, 8), (&7, &6, 1), (&6, &5, 2), (&5, &2, 4), (&2, &8, 2), (&2, &3, 7), (&3, &4, 9), ] ); } // Order of edges is not important in the result, except for starting edge, because always // starting vertex of the first edge will be selected as the start in algorithm #[test] fn another_test() { let edges = vec![ ('B', 'C', 10), ('B', 'D', 4), ('C', 'D', 2), ('A', 'C', 3), ('C', 'D', 2), ('D', 'E', 1), ('C', 'E', 6), ('D', 'E', 1), ]; assert_eq!( prim(&edges), vec![ (&'B', &'D', 4), (&'D', &'E', 1), (&'D', &'C', 2), (&'C', &'A', 3), ] ); } pathfinding-4.14.0/tests/r299.data000064400000000000000000000631751046102023000147230ustar 0000000000000023 141 - 25 139 4 35 133 - 33 131 4 17 155 - 17 157 2 7 1 - 11 5 8 1 23 - 3 23 2 1 21 2 27 37 - 27 39 2 17 3 - 17 1 2 1 171 - 3 171 2 3 173 4 1 3 - 3 3 2 3 5 4 1 11 - 3 13 4 5 11 4 1 21 - 1 23 2 3 21 2 3 19 4 1 27 - 3 29 4 3 25 4 1 39 - 1 41 2 3 39 2 3 35 6 1 41 - 1 43 2 3 41 2 1 39 2 1 43 - 3 43 2 1 41 2 3 45 4 1 53 - 1 55 2 3 53 2 1 55 - 3 55 2 1 53 2 1 59 4 1 59 - 1 61 2 3 59 2 1 55 4 1 61 - 3 61 2 1 59 2 5 67 10 1 69 - 1 71 2 5 69 4 5 67 6 1 71 - 3 71 2 1 69 2 1 75 4 1 75 - 1 79 4 3 73 4 1 71 4 1 79 - 1 81 2 3 79 2 1 75 4 1 81 - 3 81 2 1 79 2 1 95 - 3 95 2 1 99 4 3 93 4 1 99 - 1 101 2 3 99 2 1 95 4 1 101 - 1 99 2 3 99 4 1 109 - 1 111 2 3 109 2 3 107 4 1 111 - 1 113 2 3 111 2 1 109 2 1 113 - 1 115 2 1 111 2 3 111 4 1 115 - 1 113 2 3 117 4 1 127 - 3 127 2 3 133 8 1 139 - 1 141 2 3 139 2 3 135 6 1 141 - 3 141 2 1 139 2 1 151 - 1 153 2 5 151 4 3 149 4 1 153 - 3 153 2 1 151 2 1 157 4 1 157 - 1 153 4 5 159 6 3 153 6 1 163 - 3 163 2 3 165 4 3 161 4 3 3 - 1 3 2 3 5 2 5 3 2 3 5 - 3 7 2 5 5 2 3 3 2 1 3 4 3 7 - 5 7 2 3 5 2 3 13 - 3 15 2 5 13 2 1 11 4 3 15 - 5 15 2 3 13 2 3 19 - 3 21 2 5 19 2 1 21 4 5 17 4 3 21 - 1 21 2 3 23 2 3 19 2 3 23 - 1 23 2 3 25 2 3 21 2 3 25 - 5 25 2 3 23 2 1 27 4 3 29 - 3 31 2 1 27 4 3 31 - 3 29 2 5 29 4 3 35 - 5 35 2 1 39 6 3 39 - 1 39 2 3 41 2 5 39 2 3 41 - 1 41 2 3 43 2 5 41 2 3 39 2 3 43 - 1 43 2 3 45 2 3 41 2 3 45 - 5 45 2 3 43 2 1 43 4 3 53 - 1 53 2 3 55 2 5 53 6 3 55 - 1 55 2 3 57 2 5 55 2 3 53 2 3 57 - 3 59 2 5 57 2 3 55 2 3 59 - 1 59 2 3 61 2 3 57 2 3 61 - 1 61 2 3 59 2 5 63 4 3 71 - 1 71 2 3 73 2 5 71 2 3 73 - 5 73 2 3 71 2 1 75 4 3 79 - 1 79 2 3 81 2 5 79 2 3 81 - 1 81 2 3 79 2 5 85 6 7 79 6 3 87 - 3 89 2 5 85 4 3 89 - 3 91 2 5 89 2 3 87 2 3 91 - 3 89 2 5 89 4 3 93 - 3 95 2 1 95 4 7 95 6 3 95 - 1 95 2 3 97 2 3 93 2 3 97 - 3 99 2 3 95 2 3 99 - 1 99 2 3 97 2 1 101 4 3 107 - 3 109 2 5 107 2 1 109 4 3 109 - 1 109 2 3 111 2 3 107 2 3 111 - 1 111 2 3 109 2 1 113 4 3 117 - 3 119 2 1 115 4 3 119 - 5 119 2 3 117 2 3 127 - 1 127 2 3 129 2 5 127 2 3 129 - 3 131 2 5 129 2 3 127 2 3 131 - 3 133 2 5 131 2 3 129 2 3 133 - 3 135 2 3 131 2 1 127 8 3 135 - 5 135 2 3 133 2 1 139 6 3 139 - 1 139 2 3 141 2 5 139 2 3 141 - 1 141 2 5 141 2 3 139 2 3 145 4 3 145 - 3 147 2 5 145 2 3 141 4 3 147 - 3 149 2 3 145 2 3 149 - 5 149 2 3 147 2 1 151 4 3 153 - 1 153 2 5 153 2 1 157 6 3 161 - 3 163 2 1 163 4 5 165 6 3 163 - 1 163 2 3 165 2 3 161 2 3 165 - 5 165 2 3 163 2 1 163 4 3 171 - 1 171 2 3 173 2 3 173 - 5 173 2 3 171 2 1 171 4 5 3 - 3 3 2 5 5 2 7 5 4 5 5 - 3 5 2 5 7 2 7 5 2 5 3 2 5 7 - 3 7 2 5 9 2 5 5 2 5 9 - 5 11 2 5 7 2 5 11 - 5 9 2 1 11 4 5 13 - 3 13 2 5 15 2 7 15 4 5 15 - 3 15 2 7 15 2 5 13 2 5 17 - 5 19 2 7 17 2 3 19 4 5 19 - 3 19 2 7 19 2 5 17 2 5 23 - 5 25 2 7 23 2 5 25 - 3 25 2 7 25 2 5 23 2 5 29 - 7 29 2 3 31 4 5 35 - 3 35 2 7 35 2 5 39 - 3 39 2 5 41 2 7 41 4 5 41 - 3 41 2 7 41 2 5 39 2 5 45 - 3 45 2 5 47 2 7 49 6 5 47 - 5 45 2 7 49 4 5 53 - 5 55 2 7 53 2 3 53 6 5 55 - 3 55 2 5 57 2 5 53 2 5 57 - 3 57 2 7 57 2 5 55 2 5 63 - 3 61 4 7 61 4 5 67 - 7 67 2 1 69 6 1 61 10 5 69 - 5 71 2 7 69 2 1 69 4 5 71 - 3 71 2 5 73 2 7 71 2 5 69 2 5 73 - 3 73 2 7 73 2 5 71 2 5 77 - 5 79 2 7 75 4 5 79 - 3 79 2 7 79 2 5 77 2 5 85 - 3 87 4 3 81 6 5 89 - 3 89 2 3 91 4 9 87 6 5 107 - 3 107 2 5 109 2 5 109 - 5 111 2 5 107 2 5 111 - 5 109 2 7 113 4 5 119 - 3 119 2 5 121 2 7 119 2 5 121 - 7 121 2 5 119 2 5 123 - 5 125 2 7 123 2 5 125 - 5 127 2 7 125 2 5 123 2 5 127 - 3 127 2 5 129 2 7 127 2 5 125 2 5 129 - 3 129 2 5 131 2 5 127 2 5 131 - 3 131 2 5 133 2 5 129 2 5 133 - 5 135 2 5 131 2 7 131 4 5 135 - 3 135 2 5 133 2 9 139 8 11 131 10 5 139 - 3 139 2 5 141 2 5 141 - 3 141 2 7 141 2 5 139 2 5 145 - 3 145 2 7 143 4 5 149 - 3 149 2 5 151 2 7 149 2 9 147 6 5 151 - 5 153 2 7 151 2 5 149 2 1 151 4 5 153 - 3 153 2 5 155 2 7 153 2 5 151 2 5 155 - 5 157 2 7 155 2 5 153 2 5 157 - 5 159 2 5 155 2 7 155 4 5 159 - 5 157 2 9 159 4 1 157 6 5 165 - 3 165 2 3 161 6 5 171 - 5 173 2 7 171 2 5 173 - 3 173 2 7 173 2 5 171 2 5 175 - 7 177 4 7 5 - 5 5 2 9 5 2 5 3 4 7 15 - 5 15 2 7 17 2 5 13 4 7 17 - 5 17 2 7 19 2 9 17 2 7 15 2 7 19 - 5 19 2 7 17 2 9 21 4 7 23 - 5 23 2 7 25 2 9 23 2 7 25 - 5 25 2 7 27 2 7 23 2 7 27 - 7 29 2 9 27 2 7 25 2 7 29 - 5 29 2 7 31 2 7 27 2 9 31 4 7 31 - 7 33 2 9 31 2 7 29 2 7 33 - 7 35 2 9 33 2 7 31 2 7 35 - 5 35 2 7 37 2 7 33 2 7 37 - 7 35 2 9 39 4 7 41 - 5 41 2 9 41 2 5 39 4 7 49 - 9 49 2 5 47 4 5 45 6 7 53 - 5 53 2 11 53 4 7 57 - 5 57 2 9 55 4 7 61 - 5 63 4 9 63 4 7 67 - 5 67 2 7 69 2 9 69 4 7 69 - 5 69 2 7 71 2 9 69 2 7 67 2 7 71 - 5 71 2 9 71 2 7 69 2 7 73 - 5 73 2 7 75 2 9 73 2 7 75 - 9 75 2 7 73 2 5 77 4 7 79 - 5 79 2 3 81 6 7 95 - 9 95 2 3 93 6 9 91 6 7 103 - 7 105 2 9 103 2 7 105 - 9 105 2 7 103 2 7 113 - 7 115 2 5 111 4 7 115 - 7 113 2 11 115 4 7 119 - 5 119 2 7 121 2 9 119 2 9 117 4 7 121 - 5 121 2 9 121 2 7 119 2 7 123 - 5 123 2 7 125 2 9 123 2 7 125 - 5 125 2 7 127 2 9 125 2 7 123 2 7 127 - 5 127 2 7 125 2 7 131 4 7 131 - 9 131 2 5 133 4 7 127 4 7 141 - 5 141 2 7 143 2 9 141 2 7 143 - 7 141 2 5 145 4 9 141 4 7 149 - 5 149 2 7 151 2 9 149 2 7 151 - 5 151 2 7 153 2 7 149 2 7 153 - 5 153 2 7 155 2 7 151 2 7 155 - 5 155 2 9 155 2 7 153 2 5 157 4 7 171 - 5 171 2 7 173 2 9 171 2 7 173 - 5 173 2 7 171 2 11 175 6 7 177 - 5 175 4 9 5 - 7 5 2 11 5 2 9 9 - 11 9 2 9 17 - 7 17 2 9 19 2 13 17 4 13 15 6 9 19 - 9 21 2 9 17 2 9 21 - 9 23 2 9 19 2 7 19 4 9 23 - 7 23 2 9 25 2 9 21 2 9 25 - 9 27 2 11 25 2 9 23 2 9 27 - 7 27 2 11 27 2 9 25 2 9 31 - 7 31 2 9 33 2 11 31 2 7 29 4 9 33 - 7 33 2 11 33 2 9 31 2 9 39 - 9 41 2 11 39 2 7 37 4 9 41 - 7 41 2 9 39 2 11 39 4 9 47 - 9 49 2 13 47 4 9 49 - 7 49 2 9 47 2 11 51 4 9 55 - 9 57 2 11 55 2 7 57 4 9 57 - 11 57 2 9 55 2 9 63 - 11 63 2 7 61 4 9 69 - 7 69 2 9 71 2 11 69 2 7 67 4 9 71 - 7 71 2 9 73 2 9 69 2 11 69 8 9 73 - 7 73 2 11 73 2 9 71 2 9 75 - 7 75 2 9 77 2 11 75 2 9 77 - 9 75 2 11 79 4 9 83 - 9 87 4 11 81 4 9 87 - 9 91 4 9 83 4 5 89 6 9 91 - 9 93 2 9 87 4 7 95 6 9 93 - 9 95 2 11 93 2 9 91 2 9 95 - 7 95 2 11 95 2 9 93 2 11 97 4 9 99 - 9 101 2 13 97 6 9 101 - 9 103 2 9 99 2 9 103 - 7 103 2 9 105 2 11 103 2 9 101 2 9 105 - 7 105 2 9 107 2 9 103 2 9 107 - 11 107 2 9 105 2 11 109 4 9 117 - 9 119 2 11 117 2 7 119 4 9 119 - 7 119 2 9 121 2 11 119 2 9 117 2 9 121 - 7 121 2 11 121 2 9 119 2 9 123 - 7 123 2 9 125 2 11 123 2 9 125 - 7 125 2 9 123 2 11 129 6 9 129 - 9 131 2 11 129 2 9 131 - 7 131 2 11 131 2 9 129 2 9 139 - 9 141 2 11 139 2 5 135 8 9 141 - 7 141 2 9 139 2 7 143 4 9 147 - 9 149 2 11 147 2 5 149 6 9 149 - 7 149 2 9 147 2 11 151 4 9 155 - 7 155 2 13 155 4 11 153 4 9 159 - 5 159 4 11 161 4 9 169 - 9 171 2 13 165 8 9 171 - 7 171 2 11 171 2 9 169 2 11 5 - 9 5 2 7 1 8 11 9 - 9 9 2 13 7 4 11 25 - 9 25 2 11 27 2 13 25 2 11 27 - 9 27 2 11 29 2 13 27 2 11 25 2 11 29 - 11 31 2 13 29 2 11 27 2 11 31 - 9 31 2 11 33 2 11 29 2 11 33 - 9 33 2 11 35 2 13 33 2 11 31 2 11 35 - 13 35 2 11 33 2 13 37 4 11 39 - 9 39 2 9 41 4 11 51 - 13 51 2 9 49 4 11 53 - 11 55 2 7 53 4 11 55 - 9 55 2 11 57 2 13 55 2 11 53 2 11 57 - 9 57 2 11 59 2 13 57 2 11 55 2 11 59 - 11 61 2 13 59 2 11 57 2 11 61 - 11 63 2 13 61 2 11 59 2 11 63 - 9 63 2 13 63 2 11 61 2 11 67 - 11 69 2 11 69 - 9 69 2 11 67 2 9 71 8 11 73 - 9 73 2 11 75 2 15 73 4 11 75 - 9 75 2 11 73 2 15 75 4 11 79 - 11 81 2 9 77 4 11 81 - 11 83 2 11 79 2 9 83 4 11 83 - 13 83 2 11 81 2 11 87 4 11 87 - 11 89 2 11 83 4 13 83 6 11 89 - 11 87 2 11 93 4 15 89 4 11 93 - 9 93 2 13 95 4 11 89 4 11 95 - 9 95 2 11 97 2 13 95 2 11 97 - 13 97 2 11 95 2 9 95 4 11 103 - 9 103 2 13 105 4 15 101 6 11 107 - 9 107 2 11 109 2 13 107 2 11 109 - 11 111 2 11 107 2 9 107 4 11 111 - 11 113 2 13 111 2 11 109 2 11 113 - 11 115 2 11 111 2 11 115 - 11 117 2 11 113 2 7 115 4 13 117 4 11 117 - 9 117 2 11 119 2 13 117 2 11 115 2 11 119 - 9 119 2 13 119 2 11 117 2 11 121 - 9 121 2 11 123 2 13 121 2 11 123 - 9 123 2 13 123 2 11 121 2 11 129 - 9 129 2 11 131 2 9 125 6 11 131 - 9 131 2 11 129 2 5 135 10 11 137 - 11 139 2 13 137 2 13 135 4 11 139 - 9 139 2 11 141 2 11 137 2 11 141 - 13 141 2 11 139 2 11 145 4 11 145 - 11 147 2 11 141 4 11 147 - 9 147 2 13 147 2 11 145 2 11 151 - 11 153 2 9 149 4 13 153 4 11 153 - 13 153 2 11 151 2 9 155 4 11 161 - 11 163 2 13 161 2 9 159 4 11 163 - 13 163 2 11 161 2 11 171 - 9 171 2 11 173 2 13 173 4 11 173 - 11 175 2 13 173 2 11 171 2 11 175 - 11 173 2 7 173 6 13 7 - 13 9 2 15 7 2 11 9 4 13 9 - 13 7 2 13 13 4 15 11 4 13 13 - 13 15 2 15 13 2 13 9 4 13 15 - 13 13 2 15 13 4 9 17 6 13 17 - 15 17 2 9 17 4 13 25 - 11 25 2 15 25 2 13 27 - 11 27 2 13 29 2 15 27 2 13 29 - 11 29 2 13 31 2 13 27 2 13 31 - 13 33 2 15 31 2 13 29 2 13 33 - 11 33 2 15 33 2 13 31 2 13 35 - 11 35 2 13 37 2 15 35 2 13 37 - 15 37 2 13 35 2 11 35 4 13 43 - 13 47 4 13 47 - 9 47 4 13 43 4 17 45 6 13 51 - 11 51 2 17 51 4 17 49 6 13 55 - 11 55 2 13 57 2 19 55 6 13 57 - 11 57 2 13 59 2 13 55 2 13 59 - 11 59 2 13 61 2 13 57 2 13 61 - 11 61 2 13 63 2 15 61 2 13 59 2 13 63 - 11 63 2 15 63 2 13 61 2 13 83 - 11 83 2 11 87 6 13 95 - 11 95 2 13 97 2 11 93 4 13 97 - 11 97 2 13 95 2 9 99 6 13 105 - 13 107 2 11 103 4 15 101 6 13 107 - 11 107 2 15 107 2 13 105 2 13 111 - 11 111 2 15 109 4 17 109 6 13 117 - 11 117 2 15 117 2 11 115 4 13 119 - 11 119 2 13 121 2 15 119 2 13 121 - 11 121 2 13 123 2 15 121 2 13 119 2 13 123 - 11 123 2 13 121 2 15 123 6 13 135 - 11 137 4 15 137 4 13 137 - 11 137 2 15 137 2 13 141 - 11 141 2 17 143 6 13 147 - 11 147 2 15 147 2 17 149 6 13 153 - 11 153 2 15 153 2 11 151 4 13 155 - 9 155 4 15 157 4 15 153 4 13 161 - 11 161 2 13 163 2 15 161 2 13 163 - 11 163 2 13 165 2 13 161 2 13 165 - 13 167 2 13 163 2 9 169 8 13 167 - 15 167 2 13 165 2 13 173 - 11 173 2 15 173 2 11 171 4 15 1 - 17 1 2 15 7 6 15 7 - 13 7 2 19 5 6 15 1 6 15 11 - 15 13 2 17 11 2 13 9 4 15 13 - 13 13 2 15 11 2 13 15 4 15 17 - 13 17 2 15 25 - 13 25 2 15 27 2 17 25 2 15 27 - 13 27 2 17 27 2 15 25 2 15 31 - 13 31 2 17 29 4 15 33 - 13 33 2 15 35 2 19 33 4 15 35 - 13 35 2 15 37 2 15 33 2 15 37 - 13 37 2 17 37 2 15 35 2 15 61 - 13 61 2 15 63 2 19 63 6 15 63 - 13 63 2 15 61 2 19 63 4 15 73 - 15 75 2 17 73 2 11 73 4 15 75 - 17 75 2 15 73 2 11 75 4 15 79 - 15 81 2 19 81 6 15 81 - 17 81 2 15 79 2 15 85 4 15 85 - 15 87 2 17 85 2 15 81 4 15 87 - 15 89 2 17 87 2 15 85 2 15 89 - 17 89 2 15 87 2 11 89 4 15 91 - 15 93 2 17 91 2 15 93 - 15 95 2 15 91 2 17 91 4 15 95 - 15 93 2 17 97 4 15 101 - 17 99 4 11 103 6 13 105 6 15 107 - 13 107 2 15 109 2 17 107 2 15 109 - 17 109 2 15 107 2 13 111 4 15 115 - 15 117 2 17 115 2 15 117 - 13 117 2 15 119 2 17 117 2 15 115 2 15 119 - 13 119 2 15 121 2 15 117 2 17 117 4 15 121 - 13 121 2 15 123 2 15 119 2 15 123 - 15 121 2 17 125 4 13 123 6 15 129 - 17 129 2 17 127 4 15 137 - 13 137 2 13 135 4 21 139 12 15 145 - 15 147 2 17 145 2 15 147 - 13 147 2 17 147 2 15 145 2 15 153 - 13 153 2 13 155 4 17 151 4 15 157 - 17 157 2 13 155 4 15 161 4 15 161 - 13 161 2 15 163 2 15 157 4 15 163 - 17 163 2 15 161 2 15 167 4 15 167 - 13 167 2 17 167 2 15 163 4 15 173 - 13 173 2 17 1 - 15 1 2 17 3 2 21 1 4 17 11 - 15 11 2 19 11 2 19 9 4 17 25 - 15 25 2 17 27 2 17 27 - 15 27 2 19 27 2 17 25 2 17 29 - 15 31 4 21 27 6 17 37 - 15 37 2 17 39 2 19 35 4 17 39 - 17 37 2 23 37 8 17 43 - 17 45 2 17 45 - 17 43 2 17 49 4 13 47 6 21 47 6 17 49 - 17 51 2 17 45 4 13 51 6 17 51 - 19 51 2 17 49 2 13 51 4 17 59 - 19 57 4 17 67 - 17 69 2 17 69 - 19 69 2 17 67 2 17 71 6 17 71 - 17 73 2 19 71 2 17 69 6 17 73 - 15 73 2 17 75 2 17 71 2 19 71 4 17 75 - 15 75 2 19 75 2 17 73 2 17 81 - 15 81 2 17 83 2 19 81 2 17 83 - 17 85 2 19 83 2 17 81 2 17 85 - 15 85 2 19 85 2 17 83 2 17 87 - 15 87 2 17 89 2 19 87 2 17 89 - 15 89 2 17 91 2 17 87 2 17 91 - 15 91 2 19 91 2 17 89 2 15 93 4 17 97 - 17 99 2 15 95 4 17 99 - 17 101 2 17 97 2 15 101 4 19 97 4 17 101 - 17 103 2 17 99 2 19 103 4 17 103 - 17 105 2 19 103 2 17 101 2 17 105 - 17 107 2 19 105 2 17 103 2 17 107 - 15 107 2 17 109 2 19 107 2 17 105 2 17 109 - 15 109 2 17 107 2 13 111 6 17 115 - 15 115 2 17 117 2 19 115 2 17 117 - 15 117 2 19 117 2 17 115 2 15 119 4 17 125 - 17 127 2 15 123 4 17 127 - 17 129 2 17 125 2 15 129 4 17 129 - 15 129 2 17 127 2 17 143 - 17 145 2 13 141 6 17 145 - 15 145 2 17 147 2 19 145 2 17 143 2 17 147 - 15 147 2 17 149 2 17 145 2 17 149 - 17 151 2 17 147 2 13 147 6 17 151 - 19 151 2 17 149 2 15 153 4 17 157 - 15 157 2 17 155 2 19 159 4 17 163 - 15 163 2 19 163 2 17 167 4 17 167 - 15 167 2 17 163 4 19 5 - 21 7 4 15 7 6 21 1 6 19 9 - 19 11 2 21 9 2 17 11 4 19 11 - 17 11 2 21 11 2 19 9 2 19 15 - 21 17 4 21 13 4 19 19 - 19 21 2 21 19 2 19 21 - 19 19 2 19 27 6 19 27 - 17 27 2 21 27 2 19 21 6 19 33 - 19 35 2 15 33 4 21 31 4 19 35 - 21 35 2 19 33 2 17 37 4 19 49 - 19 51 2 21 49 2 19 51 - 17 51 2 19 53 2 21 51 2 19 49 2 19 53 - 19 55 2 19 51 2 19 55 - 19 57 2 21 55 2 19 53 2 13 55 6 19 57 - 19 55 2 17 59 4 19 63 - 21 63 2 15 63 4 15 61 6 19 69 - 17 69 2 19 71 2 21 69 2 19 71 - 17 71 2 19 69 2 17 73 4 19 75 - 17 75 2 19 77 2 21 75 2 19 77 - 21 77 2 19 75 2 19 81 - 17 81 2 19 83 2 15 79 6 19 83 - 17 83 2 21 83 2 19 81 2 19 85 - 17 85 2 19 87 2 21 85 2 19 87 - 17 87 2 19 89 2 19 85 2 19 89 - 19 91 2 19 87 2 19 91 - 17 91 2 19 89 2 21 93 4 19 95 - 19 97 2 21 95 2 21 93 4 19 97 - 21 97 2 19 95 2 17 99 4 19 103 - 17 103 2 19 105 2 21 103 2 17 101 4 19 105 - 17 105 2 19 107 2 19 103 2 19 107 - 17 107 2 21 107 2 19 105 2 19 113 - 19 115 2 21 111 4 19 115 - 17 115 2 21 115 2 19 113 2 19 117 - 17 117 2 19 119 2 21 117 2 19 119 - 19 121 2 19 117 2 19 121 - 19 119 2 21 123 4 23 121 4 19 145 - 17 145 2 21 145 2 21 143 4 19 151 - 17 151 2 19 153 2 21 151 2 21 147 6 19 153 - 21 153 2 19 151 2 21 155 4 19 159 - 21 159 2 17 157 4 19 163 - 17 163 2 21 161 4 19 171 - 19 173 2 19 173 - 19 175 2 21 173 2 19 171 2 19 175 - 19 173 2 21 177 4 21 1 - 23 1 2 17 1 4 19 5 6 21 7 - 21 9 2 19 5 4 21 9 - 19 9 2 21 11 2 23 9 2 21 7 2 21 11 - 19 11 2 21 13 2 23 11 2 21 9 2 21 13 - 23 13 2 21 11 2 19 15 4 21 17 - 21 19 2 23 17 2 19 15 4 21 19 - 19 19 2 21 17 2 25 19 4 21 27 - 19 27 2 23 27 2 17 29 6 21 31 - 21 33 2 23 31 2 19 33 4 21 33 - 21 35 2 21 31 2 23 31 4 21 35 - 19 35 2 21 33 2 25 35 4 21 47 - 21 49 2 23 45 4 17 45 6 21 49 - 19 49 2 21 51 2 21 47 2 23 51 4 21 51 - 19 51 2 23 51 2 21 49 2 21 55 - 19 55 2 23 53 4 21 63 - 19 63 2 25 63 4 23 67 6 21 69 - 19 69 2 23 71 4 23 67 4 21 75 - 19 75 2 21 77 2 23 75 2 21 77 - 19 77 2 21 75 2 21 81 4 21 81 - 21 83 2 23 81 2 21 77 4 21 83 - 19 83 2 21 85 2 21 81 2 21 85 - 19 85 2 21 83 2 23 87 4 21 93 - 23 93 2 19 95 4 19 91 4 21 95 - 19 95 2 21 97 2 23 95 2 21 97 - 19 97 2 21 95 2 21 103 6 21 103 - 19 103 2 21 107 4 21 97 6 21 107 - 19 107 2 23 107 2 21 103 4 21 109 - 21 111 2 23 109 2 21 111 - 21 109 2 19 113 4 23 109 4 21 115 - 19 115 2 21 117 2 23 115 2 21 117 - 19 117 2 23 117 2 21 115 2 21 123 - 21 125 2 23 123 2 19 121 4 21 125 - 21 127 2 23 125 2 21 123 2 21 127 - 23 127 2 21 125 2 23 129 4 21 137 - 21 139 2 23 137 2 21 139 - 23 139 2 21 137 2 15 137 12 21 143 - 21 145 2 23 143 2 19 145 4 21 145 - 19 145 2 21 147 2 23 145 2 21 143 2 21 147 - 23 147 2 21 145 2 19 151 6 21 151 - 19 151 2 21 153 2 21 153 - 19 153 2 21 155 2 21 151 2 21 155 - 23 155 2 21 153 2 19 153 4 21 159 4 21 159 - 19 159 2 23 159 2 21 155 4 21 161 - 19 163 4 25 161 4 21 165 - 21 167 2 23 165 2 21 167 - 23 167 2 21 165 2 21 171 - 21 173 2 23 171 2 23 169 4 21 173 - 19 173 2 21 171 2 23 171 4 21 177 - 19 175 4 25 175 6 23 1 - 21 1 2 23 3 2 23 3 - 23 1 2 25 7 6 23 9 - 21 9 2 23 11 2 25 9 2 25 7 4 23 11 - 21 11 2 23 13 2 23 9 2 23 13 - 21 13 2 23 11 2 27 15 6 23 17 - 21 17 2 25 17 2 25 15 4 23 23 - 25 23 2 23 27 - 21 27 2 25 27 2 25 29 4 23 31 - 21 31 2 25 31 2 21 33 4 23 37 - 23 39 2 25 39 4 17 39 8 23 39 - 23 41 2 25 39 2 23 37 2 23 41 - 23 43 2 23 39 2 23 43 - 23 45 2 23 41 2 23 45 - 25 45 2 23 43 2 21 47 4 23 51 - 21 51 2 23 53 2 21 49 4 23 53 - 25 53 2 23 51 2 21 55 4 23 57 - 23 59 2 25 57 2 25 55 4 23 59 - 25 59 2 23 57 2 25 61 8 23 67 - 25 67 2 21 69 4 21 63 6 23 71 - 25 71 2 21 69 4 23 75 - 21 75 2 23 77 2 25 75 2 23 77 - 25 77 2 23 75 2 23 81 4 23 81 - 21 81 2 23 83 2 23 77 4 23 83 - 25 83 2 23 81 2 23 87 4 23 87 - 21 85 4 23 83 4 27 89 6 23 93 - 21 93 2 23 95 2 23 95 - 21 95 2 23 97 2 23 93 2 27 95 4 23 97 - 25 97 2 23 95 2 23 107 14 23 107 - 21 107 2 23 109 2 23 97 14 23 109 - 21 109 2 23 107 2 21 111 4 27 107 6 23 115 - 21 115 2 23 117 2 27 113 6 23 117 - 21 117 2 23 119 2 23 115 2 23 119 - 23 121 2 23 117 2 27 119 4 23 121 - 23 123 2 23 119 2 19 121 4 23 123 - 21 123 2 25 123 2 23 121 2 23 125 - 21 125 2 23 127 2 25 125 2 23 127 - 21 127 2 25 127 2 23 125 2 23 129 - 23 131 2 21 127 4 23 131 - 23 129 2 25 133 4 23 135 8 23 135 - 23 137 2 25 133 4 23 131 8 23 137 - 21 137 2 23 139 2 23 135 2 27 135 6 23 139 - 21 139 2 25 139 2 23 137 2 23 143 - 21 143 2 23 145 2 25 143 2 23 145 - 21 145 2 25 145 2 23 143 2 23 147 - 21 147 2 25 147 2 25 151 6 23 155 - 21 155 2 23 157 2 25 153 4 23 157 - 23 159 2 25 157 2 23 155 2 23 159 - 21 159 2 23 157 2 25 161 4 23 165 - 21 165 2 23 167 2 25 165 2 25 163 4 23 167 - 21 167 2 23 169 2 25 167 2 23 165 2 23 169 - 23 171 2 25 169 2 23 167 2 21 171 4 23 171 - 21 171 2 23 169 2 21 173 4 25 7 - 27 7 2 23 9 4 23 3 6 25 9 - 23 9 2 27 9 2 27 11 4 25 15 - 25 17 2 27 15 2 23 17 4 25 17 - 23 17 2 25 19 2 25 15 2 27 15 4 25 19 - 25 17 2 21 19 4 25 23 - 23 23 2 25 25 2 27 25 4 25 25 - 25 27 2 27 25 2 25 23 2 25 27 - 23 27 2 25 29 2 25 25 2 25 29 - 25 31 2 25 27 2 23 27 4 25 31 - 23 31 2 25 33 2 27 31 2 25 29 2 25 33 - 25 35 2 27 33 2 25 31 2 25 35 - 25 33 2 21 35 4 27 33 4 25 39 - 23 39 2 25 41 2 27 39 2 23 37 4 25 41 - 25 43 2 27 41 2 25 39 2 25 43 - 25 45 2 27 43 2 25 41 2 25 45 - 23 45 2 25 47 2 27 45 2 25 43 2 25 47 - 27 47 2 25 45 2 25 53 6 25 53 - 23 53 2 25 55 2 25 47 6 25 55 - 25 57 2 25 53 2 23 57 4 25 57 - 23 57 2 25 59 2 25 55 2 25 59 - 23 59 2 25 61 2 25 57 2 25 61 - 25 63 2 25 59 2 29 59 6 23 59 8 25 63 - 27 63 2 25 61 2 21 63 4 25 67 - 23 67 2 25 69 2 27 67 2 25 69 - 25 71 2 27 69 2 25 67 2 25 71 - 23 71 2 27 71 2 25 69 2 25 75 - 23 75 2 25 77 2 29 75 4 27 73 4 25 77 - 23 77 2 25 75 2 25 81 4 25 81 - 25 83 2 27 81 2 25 77 4 25 83 - 23 83 2 27 83 2 25 81 2 25 97 - 23 97 2 27 97 2 27 99 4 25 123 - 23 123 2 25 125 2 27 121 4 25 125 - 23 125 2 25 127 2 27 125 2 25 123 2 25 127 - 23 127 2 27 127 2 25 125 2 25 133 - 27 133 2 23 135 4 23 131 4 25 139 - 23 139 2 27 139 2 23 141 4 25 143 - 23 143 2 25 145 2 27 143 2 25 145 - 23 145 2 25 147 2 25 143 2 25 147 - 23 147 2 25 145 2 25 151 4 25 151 - 25 153 2 27 151 2 25 147 4 23 147 6 25 153 - 27 153 2 25 151 2 23 155 4 25 157 4 25 157 - 23 157 2 27 157 2 25 153 4 25 161 - 25 163 2 21 161 4 23 159 4 25 163 - 25 165 2 27 163 2 25 161 2 23 165 4 25 165 - 23 165 2 27 165 2 25 163 2 25 167 - 23 167 2 25 169 2 27 167 2 25 169 - 23 169 2 27 169 2 25 167 2 25 175 - 21 177 6 27 7 - 25 7 2 27 9 2 29 7 2 27 9 - 25 9 2 27 11 2 29 9 2 27 7 2 27 11 - 29 11 2 27 9 2 25 9 4 27 15 - 25 15 2 25 17 4 23 13 6 27 25 - 25 25 2 29 27 4 25 23 4 27 31 - 25 31 2 27 33 2 29 31 2 27 33 - 25 33 2 27 31 2 25 35 4 29 31 4 27 39 - 25 39 2 27 41 2 27 37 2 27 41 - 25 41 2 29 41 2 27 39 2 27 43 - 25 43 2 27 45 2 29 43 2 27 45 - 25 45 2 27 43 2 31 45 4 27 47 - 25 47 2 27 49 2 31 49 6 27 49 - 27 51 2 29 49 2 27 47 2 27 51 - 29 51 2 27 49 2 29 53 4 27 63 - 25 63 2 27 65 2 31 61 6 27 65 - 27 67 2 29 65 2 27 63 2 27 67 - 25 67 2 27 69 2 27 65 2 27 69 - 25 69 2 27 71 2 27 67 2 29 67 4 27 71 - 25 71 2 27 73 2 27 69 2 29 73 4 27 73 - 29 73 2 27 71 2 25 75 4 27 79 - 27 81 2 29 79 2 27 81 - 25 81 2 27 83 2 27 79 2 27 83 - 25 83 2 29 83 2 27 81 2 27 89 - 29 89 2 29 87 4 23 87 6 27 95 - 27 97 2 29 95 2 23 95 4 29 93 4 27 97 - 25 97 2 27 99 2 27 95 2 27 99 - 29 99 2 27 97 2 25 97 4 27 107 - 29 107 2 23 109 6 27 113 - 27 115 2 29 113 2 23 115 6 27 115 - 27 113 2 27 119 - 27 121 2 29 119 2 23 119 4 27 121 - 27 123 2 27 119 2 25 123 4 27 123 - 27 125 2 29 123 2 27 121 2 27 125 - 25 125 2 27 127 2 27 123 2 27 127 - 25 127 2 27 125 2 29 131 6 27 133 - 25 133 2 27 135 2 29 133 2 27 135 - 27 133 2 31 135 4 23 137 6 27 139 - 25 139 2 29 141 4 31 137 6 27 143 - 25 143 2 29 143 2 29 141 4 31 145 6 27 151 - 25 151 2 27 153 2 27 153 - 25 153 2 27 155 2 27 151 2 27 155 - 27 157 2 29 155 2 27 153 2 27 157 - 25 157 2 27 159 2 27 155 2 27 159 - 27 161 2 29 159 2 27 157 2 27 161 - 27 163 2 29 161 2 27 159 2 27 163 - 25 163 2 29 163 2 27 161 2 27 165 - 25 165 2 27 167 2 29 165 2 27 167 - 25 167 2 27 169 2 29 167 2 27 165 2 27 169 - 25 169 2 29 169 2 27 167 2 29 5 - 29 7 2 31 5 2 31 3 4 29 7 - 27 7 2 29 9 2 29 5 2 29 9 - 27 9 2 29 11 2 31 9 2 29 7 2 29 11 - 27 11 2 29 9 2 33 9 6 29 15 - 29 17 2 31 15 2 29 17 - 29 19 2 31 17 2 29 15 2 29 19 - 29 21 2 29 17 2 29 21 - 31 21 2 29 19 2 29 27 - 29 29 2 27 25 4 33 25 6 29 29 - 29 31 2 31 29 2 29 27 2 29 31 - 27 31 2 29 29 2 27 33 4 29 37 - 29 39 2 31 37 2 29 39 - 29 41 2 29 37 2 31 37 4 29 41 - 27 41 2 29 43 2 29 39 2 29 43 - 27 43 2 31 43 2 29 41 2 29 49 - 27 49 2 29 51 2 31 49 2 29 51 - 27 51 2 29 53 2 29 49 2 29 53 - 29 55 2 29 51 2 27 51 4 29 55 - 29 57 2 29 53 2 29 57 - 29 59 2 29 55 2 29 59 - 31 59 2 29 57 2 25 61 6 29 65 - 27 65 2 29 67 2 31 65 2 29 67 - 29 65 2 27 69 4 31 65 4 29 73 - 27 73 2 29 75 2 31 73 2 27 71 4 29 75 - 29 77 2 29 73 2 25 75 4 29 77 - 29 79 2 31 77 2 29 75 2 29 79 - 27 79 2 29 81 2 31 79 2 29 77 2 29 81 - 29 83 2 29 79 2 31 79 4 29 83 - 27 83 2 29 85 2 29 81 2 29 85 - 29 87 2 31 85 2 29 83 2 29 87 - 29 89 2 29 85 2 27 89 4 29 89 - 27 89 2 29 87 2 33 89 4 29 93 - 29 95 2 27 95 4 29 95 - 27 95 2 29 97 2 31 95 2 29 93 2 29 97 - 29 99 2 31 97 2 29 95 2 29 99 - 27 99 2 29 97 2 29 103 - 31 103 2 29 107 - 27 107 2 29 109 2 31 107 2 29 109 - 29 107 2 33 111 6 29 113 - 27 113 2 31 113 2 29 119 - 27 119 2 29 121 2 33 117 6 29 121 - 29 123 2 31 121 2 29 119 2 29 123 - 27 123 2 29 121 2 31 121 4 29 131 - 29 133 2 31 131 2 27 127 6 33 129 6 29 133 - 27 133 2 31 133 2 29 131 2 29 141 - 29 143 2 27 143 4 27 139 4 31 137 6 29 143 - 27 143 2 29 141 2 31 145 4 29 149 - 29 151 2 31 149 2 29 151 - 31 151 2 29 149 2 29 155 4 29 155 - 27 155 2 29 157 2 29 151 4 29 157 - 29 159 2 31 157 2 29 155 2 29 159 - 27 159 2 31 159 2 29 157 2 29 161 - 27 161 2 29 163 2 31 161 2 29 163 - 27 163 2 29 165 2 29 161 2 29 165 - 27 165 2 29 167 2 29 163 2 29 167 - 27 167 2 29 169 2 29 165 2 29 169 - 27 169 2 31 169 2 29 167 2 31 1 - 31 3 2 33 1 2 31 3 - 31 5 2 31 1 2 29 5 4 31 5 - 29 5 2 31 7 2 31 3 2 31 7 - 31 9 2 33 7 2 31 5 2 31 9 - 29 9 2 33 9 2 31 7 2 31 15 - 29 15 2 31 17 2 33 15 2 33 13 4 31 17 - 29 17 2 33 17 2 31 15 2 31 21 - 29 21 2 33 19 4 31 29 - 29 29 2 33 29 2 31 35 - 31 37 2 33 35 2 33 33 4 31 37 - 29 37 2 31 35 2 29 39 4 31 43 - 29 43 2 31 45 2 33 41 4 31 45 - 33 45 2 31 43 2 27 45 4 31 49 - 29 49 2 31 51 2 27 47 6 31 51 - 31 49 2 31 55 4 33 47 6 31 55 - 31 57 2 33 55 2 31 51 4 31 57 - 31 59 2 31 55 2 33 55 4 31 59 - 29 59 2 31 61 2 33 59 2 31 57 2 31 61 - 33 61 2 31 59 2 33 63 4 27 63 6 31 65 - 29 65 2 33 65 2 29 67 4 31 73 - 29 73 2 31 75 2 35 75 6 31 75 - 31 77 2 33 75 2 31 73 2 31 77 - 29 77 2 33 77 2 31 75 2 31 79 - 29 79 2 33 79 2 29 81 4 31 85 - 29 85 2 33 85 2 31 95 - 29 95 2 33 95 2 33 93 4 31 97 - 29 97 2 31 99 2 33 97 2 31 99 - 31 101 2 33 99 2 31 97 2 31 101 - 31 103 2 33 101 2 31 99 2 31 103 - 29 103 2 33 103 2 31 101 2 31 107 4 31 107 - 29 107 2 33 107 2 31 103 4 31 113 - 29 113 2 31 115 2 33 113 2 33 111 4 31 115 - 33 115 2 31 113 2 31 121 - 29 121 2 29 123 4 33 123 4 33 117 6 31 127 - 33 127 2 31 131 - 29 131 2 31 133 2 33 131 2 31 133 - 29 133 2 31 131 2 31 135 - 31 137 2 33 135 2 27 135 4 31 137 - 31 135 2 33 135 4 27 139 6 29 141 6 31 145 - 31 147 2 29 143 4 27 143 6 31 147 - 31 149 2 33 147 2 31 145 2 31 149 - 29 149 2 31 151 2 33 149 2 31 147 2 31 151 - 29 151 2 33 151 2 31 149 2 31 157 - 29 157 2 33 157 2 33 153 6 31 159 - 29 159 2 31 161 2 33 157 4 31 161 - 29 161 2 31 159 2 33 165 6 31 167 - 31 169 2 33 167 2 33 165 4 31 169 - 29 169 2 31 171 2 33 169 2 31 167 2 31 171 - 33 171 2 31 169 2 33 1 - 31 1 2 33 3 2 33 3 - 33 5 2 33 1 2 33 5 - 33 7 2 33 3 2 33 7 - 31 7 2 33 5 2 35 9 4 33 9 - 31 9 2 35 9 2 29 11 6 33 13 - 33 15 2 35 13 2 31 15 4 33 15 - 31 15 2 35 15 2 33 13 2 33 17 - 31 17 2 33 19 2 35 17 2 33 19 - 33 17 2 31 21 4 35 17 4 33 25 - 29 27 6 33 29 - 31 29 2 35 33 6 33 33 - 33 35 2 35 33 2 31 35 4 33 35 - 31 35 2 33 33 2 35 33 4 33 41 - 33 43 2 31 43 4 35 39 4 33 43 - 33 45 2 35 43 2 33 41 2 33 45 - 31 45 2 33 47 2 35 45 2 33 43 2 33 47 - 33 45 2 35 45 4 31 51 6 33 55 - 31 55 2 35 55 2 31 57 4 35 53 4 33 59 - 31 59 2 33 61 2 33 61 - 31 61 2 33 63 2 33 59 2 33 63 - 33 65 2 33 61 2 31 61 4 33 65 - 31 65 2 33 63 2 33 69 4 33 69 - 33 71 2 33 65 4 33 71 - 33 69 2 33 75 - 31 75 2 33 77 2 35 75 2 33 77 - 31 77 2 33 79 2 33 75 2 33 79 - 31 79 2 33 77 2 35 75 10 33 85 - 31 85 2 35 85 2 33 89 4 33 89 - 35 89 2 29 89 4 33 85 4 33 93 - 31 95 4 35 95 4 33 95 - 31 95 2 33 97 2 35 95 2 33 97 - 31 97 2 35 97 2 33 95 2 33 99 - 31 99 2 33 101 2 35 99 2 33 101 - 31 101 2 33 99 2 35 99 4 33 103 - 31 103 2 33 105 2 35 105 4 33 105 - 33 107 2 35 105 2 33 103 2 33 107 - 31 107 2 33 105 2 35 105 4 33 111 - 33 113 2 31 113 4 29 109 6 33 113 - 31 113 2 33 115 2 35 113 2 33 111 2 33 115 - 31 115 2 35 115 2 33 113 2 33 117 - 35 115 4 29 119 6 31 121 6 33 123 - 33 127 4 31 121 4 33 127 - 31 127 2 33 129 2 33 123 4 33 129 - 33 131 2 33 127 2 29 131 6 33 131 - 31 131 2 33 129 2 35 133 4 33 135 - 31 135 2 31 137 4 33 143 - 33 145 2 33 145 - 33 147 2 33 143 2 33 147 - 31 147 2 33 145 2 33 149 - 31 149 2 33 151 2 33 151 - 31 151 2 33 153 2 33 149 2 33 153 - 33 151 2 33 157 4 31 157 6 33 157 - 31 157 2 31 159 4 33 153 4 33 165 - 33 167 2 31 167 4 31 161 6 33 167 - 31 167 2 35 167 2 33 165 2 33 169 - 31 169 2 33 171 2 35 169 2 33 171 - 31 171 2 33 173 2 33 169 2 35 169 4 33 173 - 33 171 2 35 175 4 33 175 6 33 175 - 35 175 2 33 173 6 35 9 - 33 9 2 35 13 4 33 7 4 35 13 - 33 13 2 35 15 2 35 9 4 35 15 - 33 15 2 35 17 2 35 13 2 35 17 - 33 17 2 35 15 2 33 19 4 35 33 - 33 33 2 33 35 4 33 29 6 35 39 - 33 41 4 35 43 4 35 43 - 33 43 2 35 45 2 35 39 4 35 45 - 33 45 2 35 43 2 33 47 4 35 53 - 35 55 2 33 55 4 35 55 - 33 55 2 35 53 2 35 75 - 33 75 2 31 73 6 33 79 10 35 85 - 33 85 2 35 89 4 35 89 - 33 89 2 35 85 4 35 95 - 33 95 2 35 97 2 33 93 4 35 97 - 33 97 2 35 99 2 35 95 2 35 99 - 33 99 2 35 97 2 33 101 4 35 105 - 33 105 2 33 107 4 33 103 4 35 113 - 33 113 2 35 115 2 35 115 - 33 115 2 35 113 2 33 117 4 35 167 - 33 167 2 35 169 2 35 169 - 33 169 2 35 167 2 33 171 4 35 175 - 33 175 2 33 173 4 pathfinding-4.14.0/tests/r299.rs000064400000000000000000000062311046102023000144240ustar 00000000000000#![cfg(test)] // http://bit.ly/2jwqlY6 use pathfinding::prelude::*; use std::collections::HashMap; #[derive(Clone, Debug, Eq, PartialEq, Hash)] struct Point { row: usize, col: usize, } fn add_successor( n: &mut HashMap>, from: &Point, to: &Point, cost: usize, ) { let entry = n.entry(from.clone()).or_default(); entry.push((to.clone(), cost)); } type SuccessorInfo = Vec<(Point, usize)>; fn parse(input: &str) -> (Vec, HashMap) { let mut nodes = Vec::new(); let mut successors = HashMap::new(); input .lines() .map(|l| { l.split(' ') .map(|s| s.parse::().unwrap_or(0)) .collect::>() }) .for_each(|words| { let src = Point { row: words[0], col: words[1], }; nodes.push(src.clone()); for n in words[3..].chunks(3) { let dst = Point { row: n[0], col: n[1], }; let cost = n[2]; assert!(cost >= distance(&src, &dst)); add_successor(&mut successors, &src, &dst, cost); } }); (nodes, successors) } const fn distance(a: &Point, b: &Point) -> usize { a.row.abs_diff(b.row) + a.col.abs_diff(b.col) } #[test] fn main() { let expectations = [ vec![28, 44, 220, 184, 144, 208, 76], vec![60, 212, 176, 136, 200, 92], vec![252, 216, 176, 240, 36], vec![48, 84, 64, 276], vec![48, 40, 240], vec![72, 200], vec![264], ]; let (nodes, graph) = parse(include_str!("r299.data")); for (i, start) in nodes[..7].iter().enumerate() { for (j, target) in nodes[i + 1..8].iter().enumerate() { let expected = expectations[i][j]; assert_eq!( astar( start, |n| graph[n].iter().cloned(), |n| distance(n, target), |n| n == target, ) .unwrap() .1, expected ); assert_eq!( dijkstra(start, |n| graph[n].iter().cloned(), |n| n == target) .unwrap() .1, expected ); assert_eq!( fringe( start, |n| graph[n].iter().cloned(), |n| distance(n, target), |n| n == target, ) .unwrap() .1, expected ); if expected < 150 { // Longer paths will take too long to run with IDA*. assert_eq!( idastar( start, |n| graph[n].iter().cloned(), |n| distance(n, target), |n| n == target, ) .unwrap() .1, expected ); } } } } pathfinding-4.14.0/tests/strongly_connected_components.rs000064400000000000000000000061701046102023000220710ustar 00000000000000use lazy_static::lazy_static; use pathfinding::directed::strongly_connected_components::*; use std::collections::hash_map::HashMap; // Tests in this file use the example at // https://en.wikipedia.org/wiki/Strongly_connected_component#/media/File:Graph_Condensation.svg #[allow(clippy::trivially_copy_pass_by_ref)] fn successors(n: &usize) -> Vec { match *n { 0 => vec![2], 1 => vec![0, 5], 2 => vec![1, 4], 3 => vec![2, 9], 4 => vec![3, 5, 10], 5 => vec![6, 8, 13], 6 => vec![7], 7 => vec![8, 15], 8 => vec![6, 15], 9 => vec![10], 10 => vec![11, 12], 11 => vec![9], 12 => vec![11, 13], 13 => vec![14, 15], 14 => vec![13], 15 => vec![], _ => panic!("error"), } } lazy_static! { static ref EXPECTED: Vec> = vec![ vec![0, 1, 2, 3, 4], vec![5], vec![6, 7, 8], vec![9, 10, 11, 12], vec![13, 14], vec![15], ]; static ref SCC: HashMap> = EXPECTED .clone() .into_iter() .flat_map(|v| v.clone().into_iter().map(move |n| (n, v.clone()))) .collect(); } #[test] fn empty_scc() { let c = strongly_connected_components(&[], successors); assert_eq!(c.len(), 0); } #[test] fn single_scc() { let c = strongly_connected_components(&[42], |_| vec![]); assert_eq!(c, vec![vec![42]]); let s = strongly_connected_component(&42, |_| vec![]); assert_eq!(s, vec![42]); } #[test] fn all_scc() { let mut c = strongly_connected_components(&(0..15).collect::>(), successors) .into_iter() .map(|mut v| { v.sort_unstable(); v }) .collect::>(); c.sort(); assert_eq!(c, *EXPECTED); } #[test] fn some_scc() { fn starting_from(start: usize) -> Vec { let mut c = strongly_connected_components_from(&start, successors) .into_iter() .map(|mut v| { v.sort_unstable(); v }) .collect::>(); c.sort(); // Check that clusters are indeed valid ones for v in &c { assert!(EXPECTED.contains(v)); } // Return the first element of each cluster c.into_iter().map(|v| v[0]).collect() } for &i in &[0, 1, 2, 3, 4] { assert_eq!(starting_from(i), vec![0, 5, 6, 9, 13, 15]); } assert_eq!(starting_from(5), vec![5, 6, 13, 15]); for &i in &[6, 7, 8] { assert_eq!(starting_from(i), vec![6, 15]); } for &i in &[9, 10, 11, 12] { assert_eq!(starting_from(i), vec![9, 13, 15]); } for &i in &[13, 14] { assert_eq!(starting_from(i), vec![13, 15]); } assert_eq!(starting_from(15), vec![15]); } #[test] fn individual_scc() { for n in 0..=15 { let mut c = strongly_connected_component(&n, successors); c.sort_unstable(); assert_eq!(c, SCC[&n]); } } #[test] fn loops() { let mut c = strongly_connected_components(&[0], |_| vec![42]); c.sort(); assert_eq!(c, vec![vec![0], vec![42]]); } pathfinding-4.14.0/tests/topological_sort.rs000064400000000000000000000062321046102023000173030ustar 00000000000000use itertools::Itertools; use pathfinding::directed::topological_sort::topological_sort as tsort; use pathfinding::directed::topological_sort::topological_sort_into_groups; use rand::rngs; use rand::seq::SliceRandom; #[test] fn empty() { let empty: Vec = vec![]; assert_eq!(tsort(&empty, |&n| vec![n]), Ok(empty)); } #[test] fn order() { // Shuffle integers from 1 to 1000, and order them so that divisors // are located before the numbers they divide. let mut rng = rngs::OsRng; let mut ints = (1..1000).collect_vec(); ints.shuffle(&mut rng); let sorted = tsort(&ints, |&n| { (2..).map(|m| m * n).take_while(|&p| p < 1000).collect_vec() }) .unwrap(); for (i, &vi) in sorted.iter().enumerate() { for &vj in sorted.iter().skip(i + 1) { assert!(vi % vj != 0, "{vj} is located after {vi} and divides it"); } } } #[test] fn complexity() { // To ensure that the sort is O(|E| + |V|), we ensure that the // successors for a particular node are requested exactly one time. let mut rng = rngs::OsRng; let mut ints = (1..1000).collect_vec(); ints.shuffle(&mut rng); let mut requested = 0; let result = tsort(&ints, |&n| { requested += 1; if n < 999 { vec![n + 1] } else { vec![] } }); assert_eq!(result, Ok((1..1000).collect_vec())); assert_eq!(requested, 999); } // Wrapper around topological_sort_into_groups that sorts each group (since // topological_sort_into_groups makes no guarantees about node order within // each group). #[allow(clippy::type_complexity)] fn tsig(succs: &[&[usize]]) -> Result>, (Vec>, Vec)> { let nodes: Vec = (0..succs.len()).collect(); match topological_sort_into_groups(&nodes, |&n| succs[n].iter().copied()) { Ok(mut groups) => { for group in &mut groups { group.sort_unstable(); } Ok(groups) } Err((mut groups, mut remaining)) => { for group in &mut groups { group.sort_unstable(); } remaining.sort_unstable(); Err((groups, remaining)) } } } #[test] fn tsig_empty_graph() { assert_eq!(tsig(&[]), Ok(vec![])); } #[test] fn tsig_graph_with_no_edges() { assert_eq!(tsig(&[&[], &[], &[]]), Ok(vec![vec![0, 1, 2]])); } #[test] fn tsig_diamond() { assert_eq!( tsig(&[&[1, 2], &[3], &[3], &[]]), Ok(vec![vec![0], vec![1, 2], vec![3]]) ); } #[test] fn tsig_multiple_layers() { let succs: &[&[usize]] = &[&[1, 5], &[2], &[3], &[], &[5], &[3]]; assert_eq!( tsig(succs), Ok(vec![vec![0, 4], vec![1, 5], vec![2], vec![3]]) ); } #[test] fn tsig_nothing_but_a_cycle() { assert_eq!(tsig(&[&[1], &[2], &[0]]), Err((vec![], vec![0, 1, 2]))); } #[test] fn tsig_chain_then_cycle() { assert_eq!( tsig(&[&[1], &[2], &[3], &[2, 4], &[]]), Err((vec![vec![0], vec![1]], vec![2, 3, 4])) ); } #[test] fn tsig_self_edge() { assert_eq!( tsig(&[&[1, 2], &[3], &[3], &[3]]), Err((vec![vec![0], vec![1, 2]], vec![3])) ); } pathfinding-4.14.0/tests/ui.rs000064400000000000000000000002511046102023000143300ustar 00000000000000#[test] fn ui() { if version_check::is_min_version("1.84.0").unwrap() { let t = trybuild::TestCases::new(); t.compile_fail("tests/ui/*.rs"); } } pathfinding-4.14.0/tests/utils.rs000064400000000000000000000017171046102023000150630ustar 00000000000000use pathfinding::utils::*; #[test] fn in_direction_start_oob() { assert_eq!(move_in_direction((8, 8), (-1, -1), (8, 8)), None); assert_eq!(in_direction((8, 8), (-1, -1), (8, 8)).next(), None); } #[test] fn in_direction_end_oob() { assert_eq!(move_in_direction((0, 0), (-1, -1), (8, 8)), None); assert_eq!(in_direction((0, 0), (-1, -1), (8, 8)).next(), None); assert_eq!(move_in_direction((7, 0), (1, -1), (8, 8)), None); assert_eq!(in_direction((0, 7), (-1, 1), (8, 8)).next(), None); } #[test] fn in_direction_invalid() { assert_eq!(in_direction((0, 8), (-1, 1), (8, 8)).next(), None); assert_eq!(in_direction((8, 0), (-1, 1), (8, 8)).next(), None); assert_eq!(in_direction((0, 7), (0, 0), (8, 8)).next(), None); } #[test] fn in_direction_valid() { assert_eq!(move_in_direction((1, 1), (1, 3), (2, 4)), None); assert_eq!( in_direction((1, 1), (1, 3), (8, 8)).collect::>(), vec![(2, 4), (3, 7)] ); } pathfinding-4.14.0/tests/version.rs000064400000000000000000000013051046102023000154010ustar 00000000000000const VERSION: &str = env!("CARGO_PKG_VERSION"); const README: &str = include_str!("../README.md"); #[test] fn check_version() { let line = README .lines() .find(|l| l.starts_with("pathfinding = ")) .expect("no version line found in README.md"); let version = line.split('"').collect::>()[1]; assert!( trim(VERSION).starts_with(&trim(version)), "Version in README.md ({} - seen as {}) is not compatible with Cargo.toml ({} - seen as {})", version, trim(version), VERSION, trim(VERSION), ); } // Keep at most two components (major/minor). fn trim(version: &str) -> String { version.split('.').take(2).collect::>().join(".") } pathfinding-4.14.0/tests/yen-issue-507.rs000064400000000000000000000361201046102023000161510ustar 00000000000000use pathfinding::directed::yen::yen; #[test] fn issue507() { let grid: &Vec> = &INPUT.lines().map(|l| l.chars().collect()).collect(); let start = (1_usize, 0_usize); let end = (grid[0].len() - 2, grid.len() - 1); let k = 10; let k_shortest_paths = yen( &start, |&(x, y)| { let dirs = [(1, 0), (-1, 0), (0, 1), (0, -1)]; dirs.into_iter().filter_map(move |(dx, dy)| { let (nx, ny) = (x.wrapping_add_signed(dx), y.wrapping_add_signed(dy)); let tile = *grid.get(ny)?.get(nx)?; match tile { 'v' if dy == -1 => None, '>' if dx == -1 => None, '#' => None, _ => Some(((nx, ny), 1)), } }) }, |&pos| pos == end, k, ); let path_lengths: Vec<_> = k_shortest_paths.iter().map(|(_, l)| l).collect(); for (a, b) in path_lengths.iter().zip(path_lengths.iter().skip(1)) { assert!(a <= b); } } const INPUT: &str = "#.########################################################################################################################### #.#.....#...###.......#.....#.......#.......###...#...#.......###...###...#####...#...###...###...#.....#.....#...#...###...# #.#.###.#.#.###.#####.#.###.#.#####.#.#####.###.#.#.#.#.###.#.###.#.###.#.#####.#.#.#.###.#.###.#.#.###.#.###.#.#.#.#.###.#.# #.#...#...#...#.....#.#...#.#.#.....#.#.....#...#.#.#.#.#...#...#.#...#.#.....#.#.#.#.#...#...#.#.#...#.#...#...#...#.#...#.# #.#.#.....#.#...###.#...#.#.#.#...>.>.#...#.#...#.....#.#...#...#...#.#.#...#.....#.....#.#...#...#...#.#.#.#.....#.#.#...#.# #.#.#.#####.###.###.###.#.#.#.#####v#######.#.#.#.#####.#.#.#.#.###.#.#.#####.#####.#####.#.###.###.#.#.#.#.#.###.#.#.#####.# #.#.#.#.#.###.#v#.#####.#.#.#.#.#####.#######.#.#####.#.#.#####.#.#######.#####.#.#####.#.###.#.###.#.#.#.#.###.#####.#.##### #.#####.###.#################.#########.#######.#######.#.#.#.###########.#.#.#############.#.#.###.#.#####.#.#.###########.# #.....#.....#...###.........#.......#...#.......#####...#.....#####.....#...#...#.....#.....#...#...#.....#.#...#.........#.# #####.#######.#.###.#######.#######.#.###.###########.#############.###.#######.#.###.#.#########.#######.#.#####.#######.#.# #.....#.......#.....#.......#.......#.###.........#...#...#.........#...#.......#...#.#...###.....#...###...#...#.......#.#.# #.#####.#############.#######.#######.###########.#.###.#.###########.###.#########.#.###.###.#####.#.#######.#.#######.#.#.# #.......#.......#.....###...#.........#...........#...#.#...........#...#...........#...#.#...#...#.#.###...#.#.#...#...#.#.# #########.#####.#.#######.#.###########.#############.#.###.#######.###.###############.#.#.###.#.#.#.###.#.#.#.#.#.#v###.#.# #...#...#.....#...#...###.#.###...###...#...........#...#.........#.....###...#...#...#...#...#.#.#.#.#...#...#...#.>.###.#.# #.#.#.#.#####.#####.#.###.#.###.#.###.###.#########.#####v#######.#########.#.#.#.#.#.#######.#.#.#.#.#.#############v###.#.# #.#...#.......#...#.#.#...#.#...#...#.....#.........#...>.>.......#...###...#.#.#...#...#...#.#.#.#.#.#.#...#.....#...###.#.# #.#############.#.#.#.#.###.#.#####.#######.#########.###v#########.#.###.###.#.#######.#.#.#.#.#.#.#.#.#.#.#.###.#.#####.#.# #.#.............#...#.#...#.#...#...###.....###...#...#...#.......#.#...#...#.#.....#...#.#.#.#.#.#.#...#.#...###...#...#...# #.#.#################.###.#.###.#.#####.#######.#.#.###.#########.#.###.###.#.#####.#.###.#.#v#.#.#.#####.###########.#.##### #...#...###...........#...#...#.#.....#.....###.#.#.#...#.........#...#...#.#.#...#.#.#...#.>.>.#.#.....#.............#.....# #####.#.###v###########.#####.#.#####.#####.###.#.#.#.###.###########.###.#.#.#.#.#.#.#.#####v###.#####.###################.# #.....#...#.>...###...#.....#.#.#.....#...#.#...#...#...#.#...###...#...#.#.#.#.#.#.#...#...#.###...#...#...........#.......# #.#######.#v###.###.#.#####.#.#.#.#####.#.#v#.#########.#.###.###.#.###.#.#.#.#.#.#.#####.#.#.#####.#.###.#########.#.####### #.#.....#.#...#.#...#.#...#.#.#.#.#...#.#.>.>.#.....#...#.#.#.#...#.....#.#.#.#.#.#.#.....#...#...#...#...#.......#...#...### #.#.###.#.###.#.#.###.#.#.#.#.#.#.#.#.#.###v###.###.#.###.#.#.#.#########.#.#.#.#.#.#.#########.#.#####.###.#####.#####.#.### #...###.#.....#...#...#.#.#.#.#.#.#.#...###.###.#...#...#.#.#.#...###...#...#...#...#...........#...###.....#.....#...#.#...# #.#...#...#.#.#...#.#.#.#...#.#.#.#.#.....#...#...#.....#.#...###...#.....#...#.###...###...#.....#.#.#.#.#...........#.....# #.#.#.#####.#.#.#.#.#.#.###.#.#.#.#.#.#####.#.#########.#.#.#.#################.#############.#####.#.#.#.#################.# #...#.....#...#.#.#.#.#.#...#.#.#.#.#...#...#.......###...#.#.#.........#...#...#.....#.....#...#...#.#.#.###...#...#.......# #########.#####.#.#.#.#.#.###.#.#.#.###.#.#########.#######.#.#.#######.#.#.#.###.###.#.###.###.#.###.#.#.###v#.#.#.#.####### #.........#...#.#.#.#.#.#.###.#.#.#.###.#...#.......#...#...#.#.......#...#.#.###...#.#...#.#...#...#.#.#.#.>.#...#...#...### #.#########.#.#.#.#.#.#.#.###.#.#.#.###v###.#.#######.#.#.###.#######.#####.#.#####.#.###.#.#.#####.#.#.#.#.#v#########.#.### #.#.....#...#...#...#.#.#.#...#.#.#...>.>...#.......#.#.#.....#...#...#...#...#...#.#.....#...#...#.#.#.#...#...........#...# #.#.###v#.###########.#.#.#.###.#.#####v###########.#.#.#######.#.#.###.#.#####.#.#.###########.#.#.#.#.###################.# #.#.###.>.#...#...###...#.#.#...#.#.....###.....#...#.#.#.....#.#.#.....#.......#.#.........#...#...#.#.#...........#.......# #.#.###v###.#.#.#.#######.#.#.###.#.#######.###.#.###.#.#.###.#.#.###############.#########.#.#######.#.#.#########.#.####### #...#...#...#.#.#.......#...#.....#.#.....#...#...###.#.#.....#.#.###.............#...#.....#.......#.#.#.........#.#.....### #####.###.###.#.#######.###########.#.###.###.#######.#.###.###.#.###v#############.#.#.###########.#.#.#########.#.#####.### #...#.....###.#.#.......#.........#...#...###...#...#.#.#.....#.#...>.>.###...#...#.#.#...#...#...#.#...###.......#.....#...# #.#.#########.#.#.#######.#######.#####.#######.#.#.#.#.#.###.#.#####v#.###.#.#.#.#.#.###v#.#.#.#.#.#######.###########.###.# #.#...........#.#...###...#...#...#.....#...###.#.#.#.#.#.###.#.#.....#.....#.#.#...#.#.>.>.#...#.#...#.....#...#...###...#.# #.#############.###.###.###.#.#.###.#####.#.###.#.#.#.#.#.###.#.#.###########.#.#####.#.#v#######.###.#.#####.#.#.#.#####.#.# #.#...#.....#...###.....#...#...###.......#...#.#.#.#.#...#...#.#.........#...#...#...#.#.#...###.....#.......#...#.....#.#.# #.#.#.#.###.#.###########.###################.#.#.#.#.#####.###.#########.#.#####.#.###.#.#.#.#########################.#.#.# #...#.#.#...#.#.........#.###...#.............#.#.#.#...#.......#.......#.#...#...#...#.#.#.#...###.....#...............#.#.# #####.#.#.###.#.#######.#.###.#.#.#############.#.#.###.#.#######.#####.#.###.#.#####.#.#.#.###.###.###.#.###############.#.# #.....#.#.....#.......#.#...#.#.#.............#...#.....#..####...#...#...###.#.#...#...#...###.....#...#...............#...# #.#####.#############.#.###.#.#.#############.#################.###.#.#######.#.#.#.#################.#################.##### #.......###...#...#...#.....#.#.....#.........#...###......##...#...#...#...#...#.#...#.....#.......#.#...#.......#...#.....# ###########.#.#.#.#.#########.#####.#.#########.#.###.#######.###.#####.#.#.#####.###.#.###.#.#####.#.#.#.#.#####.#.#.#####.# #...........#.#.#...#.....#...#.....#...........#...#.......#...#.....#.#.#.#...#.#...#...#.#.....#...#.#.#.....#.#.#...#...# #.###########.#.#####.###.#.###.###################.#######.###.#####.#.#.#.#.#.#.#.#####.#.#####v#####.#.#####v#.#.###.#.### #...........#.#.......#...#...#.###...#.......#.....#.......#...#.....#...#.#.#...#.#.....#.....>.>.#...#.#...>.#.#...#...### ###########.#.#########.#####.#.###.#.#v#####.#.#####.#######v###.#########.#.#####.#.###########v#.#.###.#.###v#.###.####### #...........#...........#.....#...#.#.>.>.###.#.#...#.......>.>.#.....#.....#.....#...#...###...#.#.#...#...#...#...#.......# #.#######################.#######.#.###v#.###.#.#.#.#########v#.#####.#.#########.#####.#.###.#.#.#.###.#####.#####.#######.# #...........#.......#...#.......#.#.#...#...#...#.#.#...###...#.#...#.#.#...#...#.#.....#.....#...#...#.#.....#####.#.......# ###########.#.#####.#.#.#######.#.#.#.#####.#####.#.#.#.#######.#.#.#.#.#.#.#.#.#.#.#################.#.#.#########.#.####### #...###...#.#.#.....#.#.#.....#.#.#.#.#...#...#...#.#.#.#.>...#...#...#...#.#.#...#.................#...#.......###...#...### #.#.###.#.#.#.#.#####.#.#.###.#.#.#.#.#.#.###.#.###.#.#.#.###.#############.#.#####################.###########.#######.#.### #.#.....#.#...#.#...#.#...###.#.#.#.#.#.#...#...#...#.#.#.#...#...###...###...###...#...............#.....#...#.....#...#...# #.#######.#####.#.#.#.#######.#.#.#.#.#.###.#####.###.#.#.#####.#.###.#.#########.#.#.###############.###.#.#.#####.#.#####.# #.......#.....#.#.#.#.......#...#.#.#.#.###.....#...#.#.#.#.###.#.#...#...###.....#.#...............#...#...#.......#.#.....# #######.#####.#.#.#v#######.#####.#.#.#.#######.###.#.#.#.#.###.#.#.#####.###.#####.###############.###.#############.#.##### #.......#.....#.#.#.>.....#.....#...#...###.....###.#.#...#.#...#...#...#...#.....#.............#...###...............#.....# #.#######.#####.#.#v#####.#####.###########.#######.#.#######.#######.#.###.#####.#############.#.#########################.# #.......#.#...#...#.....#.#...#...#.........###.....#.....#...#...#...#.....#.....#...#.....###...#.........................# #######.#.#.#.#########.#.#.#.###.#.###########.#########.#####.#.#.#########.#####.#.#.###.#######.######################### #.......#...#.###...#...#.#.#.#...#...........#.#...#...#.#...#.#.#.........#.#.....#...###.....###...............#.........# #.###########.###.#.#.###.#.#.#.#############.#.#.#.#.#.#.###.#.#.#########.#.#.###############.#################.#.#######.# #.#.........#...#.#...###...#...#...#.........#...#.#.#...#.#...#...........#...#.............#.....#.............#.#.......# #.#.#######.###.#.###############.#.#.#############.#.#####.#####################.###########.#####.#.#############.#.####### #.#.#.......###.#.#.....#...#...#.#.#...#.....#...#.#.#...#.................#...#...........#.#.....#.#.....#...#...#.......# #.#.#.#########.#.#.###.#.#.#.#.#.#.###.#.###.#.#.#.#.#.#.#################.#.#.###########.#.#.#####.#.###.#.#.#.#########.# #.#.#.......###.#.#.#...#.#.#.#.#.#.###...#...#.#.#...#.#.#.......#.........#.#.....#.......#...#...#...###...#...#.....#...# #.#.#######.###.#.#.#.###.#.#.#.#.#.#######.###.#.#####.#.#######.#.#########.#####.#.###########.#.###############.###.#.### #.#.#.......#...#.#.#.#...#.#.#.#.#.#.....#.....#...###.#.#.#...#...#...#...#.#.....#.......#...#.#.###.......#...#...#.#...# #.#.#.#######.###.#.#.#.###.#.#.#.#.#.###.#########.###.#.#.#.#.#####.#.#.#.#.#.###########.#.#.#.#.###.#####.#.#.###.#.###.# #.#.#.....###.....#.#.#...#.#.#.#.#.#.#...#.........#...#.#...#.....#.#.#.#.#.#.#...###...#.#.#.#.#.#...#...#...#.#...#.....# #.#.#####.#########.#.###.#.#.#.#.#.#.#.###v#########.###.#########.#.#.#.#.#.#.#.#.###.#.#v#.#.#.#.#.###.#.#####.#.######### #...#####...#...###.#.#...#.#.#.#.#.#.#...>.>...#...#.#...#.........#.#.#.#.#.#...#...#.#.>.>.#...#.#.....#.....#...###...### ###########.#.#.###.#.#.###.#.#.#.#.#.#####v###.#.#.#.#.###.#########.#.#.#.#.#######.#.###v#######.###########.#######.#.### #...###.....#.#.#...#.#.###.#.#...#...###...#...#.#.#.#...#...#.....#.#.#.#...###...#...#...#.......#...........###...#.#.### #.#.###v#####.#.#.###.#.###.#.###########.###.###.#.#.###.###.#.###.#.#.#.#######.#.#####.###.#######.#############.#.#.#.### #.#.###.>.....#.#...#.#.#...#...#.........###...#.#.#...#.....#...#.#.#.#.....#...#...#...#...###...#.......#.....#.#.#.#.### #.#.###v#######.###.#.#.#.#####.#.#############.#.#.###.###v#####.#.#.#.#####.#.#####.#.###.#####.#.#######v#.###.#.#.#.#.### #.#.###.......#.....#.#.#.#.....#...........#...#.#.....###.>.#...#...#.....#.#.....#.#...#.#...#.#...#...>.#.#...#.#...#...# #.#.#########.#######.#.#.#.###############.#.###.#########v#.#.###########.#.#####.#.###.#.#.#.#.###.#.###v#.#.###.#######.# #.#...........###...#.#.#...#...###...#.....#...#.#.........#.#.#.........#.#...#...#...#.#...#.#...#.#.#...#.#.....#.....#.# #.###############.#.#.#.#####.#.###.#.#.#######.#.#.#######.#.#.#.#######.#.###.#.#####.#.#####.###.#.#.#.###.#######.###.#.# #.................#.#.#...#...#.#...#...#.....#...#.........#...#.......#.#.....#.....#.#.#...#.#...#.#.#...#.###...#...#.#.# ###################.#.###.#.###.#.#######.###.#############.###########.#.###########.#.#.#.#.#.#.###.#.###.#.###.#.###.#.#.# #...................#.....#...#.#.........#...###...#.......#...###.....#...###...#...#...#.#.#.#.#...#.#...#.#...#.....#.#.# #.###########################.#.###########.#####.#.#.#######.#.###.#######.###.#.#.#######.#.#.#.#.###.#.###.#.#########.#.# #...#.......###.........#.....#...........#.#...#.#.#.....#.#.#...#.....#...#...#...#...#...#.#.#.#.....#...#.#...#...###...# ###.#.#####.###.#######.#.###############.#.#.#.#.#.#####.#.#.###.#####.#.###.#######.#.#.###.#.#.#########.#.###.#.#.####### #...#.#.....#...#.......#...............#...#.#.#.#.#####.#.#.#...#.....#...#.......#.#.#...#.#...#...#...#.#.###...#.......# #.###.#.#####.###.#####################.#####.#.#.#.#####.#.#.#.###.#######.#######.#.#.###.#.#####.#.#.#.#.#.#############.# #.....#.....#...#.#.....#.......#.....#.#...#.#.#.#.......#...#...#.#.......#...###.#.#.###.#.###...#...#.#...#.............# ###########.###.#.#.###.#.#####.#.###.#.#.#.#.#.#.###############.#.#.#######.#.###v#.#.###.#.###.#######.#####.############# #.....#.....###.#.#.#...#.....#.#...#...#.#.#.#.#..........##...#.#.#.#...#...#.#.>.>.#.....#.....#.......#.....#...#...#...# #.###.#.#######.#.#.#.#######.#.###v#####.#.#.#.#############.#.#.#.#.#.#.#.###.#.#################.#######.#####.#.#.#.#.#.# #...#.#...#...#.#.#.#.#.....#.#.#.>.>.#...#.#.#...#...#.......#.#...#...#.#.###.#.#.............#...#.....#.......#...#...#.# ###.#.###.#.#.#.#.#.#.#.###.#.#.#.###.#.###.#.###.#.#.#.###.###.#########.#.###.#.#.###########.#.###.###.#################.# #...#.....#.#...#...#.#...#.#.#.#...#.#.###.#.#...#.#.#...#...#.#...#...#.#...#.#.#...........#...###.#...#...###...........# #.#########.#########.###.#.#.#.###.#.#.###.#.#.###.#.###v###.#.#.#.#.#.#v###.#.#.###########.#######.#.###.#.###.########### #...#.....#.###...#...#...#...#...#.#.#.#...#.#...#.#.#.>.>.#.#.#.#.#.#.>.>.#.#...#...........###.....#.#...#...#...........# ###.#.###.#.###.#.#.###.#########.#.#.#.#.###.###.#.#.#.###.#.#.#.#.#.#####.#.#####.#############.#####.#.#####.###########.# #...#.#...#.....#.#...#.......#...#.#.#.#...#...#...#.#...#.#.#.#.#.#.###...#.....#...............#.....#.....#.###...#.....# #.###.#.#########.###.#######.#.###.#.#.###.###.#####.###.#.#.#.#.#.#.###.#######.#################.#########.#.###.#.#.##### #.#...#.#...#...#.###.....#...#...#.#.#.###...#.#.....#...#.#.#...#.#...#...#...#.###...#...........#...#####.#.###.#.#.#...# ###...#...#...#...###...#...#####...#...#...#...#.........#...#...#.....#...###...###...#...#.....#...#.........#...###...#.# ###########################################################################################################################.# "; pathfinding-4.14.0/tests/yen.rs000064400000000000000000000112041046102023000145060ustar 00000000000000use pathfinding::prelude::yen; // A simple tests of Yen's algorithm based on the example and visualization // from https://en.wikipedia.org/wiki/Yen's_algorithm#Example. #[test] fn simple() { let result = yen( &'c', |c| match c { 'c' => vec![('d', 3), ('e', 2)], 'd' => vec![('f', 4)], 'e' => vec![('d', 1), ('f', 2), ('g', 3)], 'f' => vec![('g', 2), ('h', 1)], 'g' => vec![('h', 2)], 'h' => vec![], _ => panic!(""), }, |c| *c == 'h', 3, ); assert_eq!(result.len(), 3); assert_eq!(result[0], (vec!['c', 'e', 'f', 'h'], 5)); assert_eq!(result[1], (vec!['c', 'e', 'g', 'h'], 7)); assert_eq!(result[2], (vec!['c', 'd', 'f', 'h'], 8)); } /// Tests that we correctly return fewer routes when /// we exhaust all possible paths. #[test] fn ask_more_than_exist() { let result = yen( &'c', |c| match c { 'c' => vec![('d', 3), ('e', 2)], 'd' => vec![('f', 4)], 'e' => vec![('d', 1), ('f', 2), ('g', 3)], 'f' => vec![('g', 2), ('h', 1)], 'g' => vec![('h', 2)], 'h' => vec![], _ => panic!(""), }, |c| *c == 'h', 10, ); // we asked for 10 but the graph can only produce 7 assert_eq!( result.iter().map(|&(_, c)| c).collect::>(), vec![5, 7, 8, 8, 8, 11, 11] ); } /// Test that we return None in case there is no solution #[test] fn no_path() { let result = yen( &'c', |c| match c { 'c' => vec![('d', 3), ('e', 2)], 'd' => vec![('f', 4)], 'e' => vec![('d', 1), ('f', 2), ('g', 3)], 'f' => vec![('g', 2), ('d', 1)], 'g' => vec![('e', 2)], 'h' => vec![], _ => panic!(""), }, |c| *c == 'h', 2, ); assert!(result.is_empty()); } /// Test that we support loops #[test] fn single_node() { let result = yen( &'c', |c| match c { 'c' => vec![('c', 1)], _ => panic!(""), }, |c| *c == 'c', 2, ); assert_eq!(result, vec![(vec!['c'], 0)]); } /// Test that we don't panic if an alternative path is more than two nodes longer than a previous one. #[test] fn longer_alternative_path() { let result = yen( &'c', |c| match c { 'c' => vec![('d', 1), ('h', 1)], 'd' => vec![('e', 1)], 'e' => vec![('f', 1)], 'f' => vec![('g', 1), ('h', 1)], 'g' => vec![('h', 1)], 'h' => vec![], _ => panic!(""), }, |c| *c == 'h', 3, ); assert_eq!(result.len(), 3); assert_eq!(result[0], (vec!['c', 'h'], 1)); assert_eq!(result[1], (vec!['c', 'd', 'e', 'f', 'h'], 4)); assert_eq!(result[2], (vec!['c', 'd', 'e', 'f', 'g', 'h'], 5)); } /// Check that we return all loopless paths /// (issue #467) #[test] fn all_paths() { let mut result = yen( &'a', |c| match c { 'a' => vec![('b', 1), ('c', 1), ('d', 1)], 'b' => vec![('c', 1), ('d', 1)], 'c' => vec![('b', 1), ('d', 1)], 'd' => vec![], _ => unreachable!(), }, |c| *c == 'd', usize::MAX, ); result.sort_unstable(); assert_eq!( result, vec![ (vec!['a', 'b', 'c', 'd'], 3), (vec!['a', 'b', 'd'], 2), (vec!['a', 'c', 'b', 'd'], 3), (vec!['a', 'c', 'd'], 2), (vec!['a', 'd'], 1), ] ); } #[test] fn multiple_equal_cost_paths() { use std::collections::HashMap; // Graph example: // A --> B --> D // A --> C --> D // Both paths (A -> B -> D) and (A -> C -> D) have the same cost of 2. let mut graph = HashMap::new(); graph.insert('A', vec![('B', 1), ('C', 1)]); graph.insert('B', vec![('D', 1)]); graph.insert('C', vec![('D', 1)]); graph.insert('D', vec![]); // Goal node let successors = |n: &char| { let neighbors = match n { 'A' => "BC", 'B' | 'C' => "D", _ => "", }; neighbors.chars().map(|n| (n, 1)) }; // Start is 'A', goal is 'D', and we want 2 shortest paths. let paths = yen(&'A', successors, |n| *n == 'D', 2); // We expect two distinct paths both with cost 2: // Path 1: A -> B -> D // Path 2: A -> C -> D assert_eq!(paths.len(), 2); // Check both paths have total cost of 2 and are distinct assert_eq!(paths[0], (vec!['A', 'B', 'D'], 2)); assert_eq!(paths[1], (vec!['A', 'C', 'D'], 2)); }